ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
ilSCORM13Package.php
Go to the documentation of this file.
1 <?php
2 
3 /* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4 
11 require_once "./Modules/Scorm2004/classes/ilSCORM13Package.php";
12 require_once "./Modules/Scorm2004/classes/class.ilSCORM2004Chapter.php";
13 require_once "./Modules/Scorm2004/classes/class.ilSCORM2004Sco.php";
14 require_once "./Modules/Scorm2004/classes/class.ilSCORM2004PageNode.php";
15 require_once "./Modules/Scorm2004/classes/adlparser/SeqTreeBuilder.php";
16 require_once("./Modules/ScormAicc/classes/SCORM/class.ilSCORMTree.php");
17 
19 {
20 
21  const DB_ENCODE_XSL = './Modules/Scorm2004/templates/xsl/op/op-scorm13.xsl';
22  const CONVERT_XSL = './Modules/Scorm2004/templates/xsl/op/scorm12To2004.xsl';
23  const DB_DECODE_XSL = './Modules/Scorm2004/templates/xsl/op/op-scorm13-revert.xsl';
24  const VALIDATE_XSD = './Modules/Scorm2004/templates/xsd/op/op-scorm13.xsd';
25 
26  const WRAPPER_HTML = './Modules/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/GenericRunTimeWrapper.htm';
27  const WRAPPER_JS = './Modules/Scorm2004/scripts/converter/GenericRunTimeWrapper1.0_aadlc/SCOPlayerWrapper.js';
28 
29 
30  private $packageFile;
31  private $packageFolder;
32  private $packagesFolder;
33  private $packageData;
34  private $slm;
35  private $slm_tree;
36 
37  public $imsmanifest;
38  public $manifest;
39  public $diagnostic;
40  public $status;
41  public $packageId;
42  public $packageName;
43  public $packageHash;
44  public $userId;
45 
46  private $idmap = array();
47  private $progress = 0.0;
48 
49  static private $elements = array(
50  'cp' => array(
51  'manifest',
52  'organization',
53  'item',
54  'hideLMSUI',
55  'resource',
56  'file',
57  'dependency',
58  'sequencing',
59  'rule',
60  'auxilaryResource',
61  'condition',
62  'mapinfo',
63  'objective',
64  ),
65  'cmi' => array(
66  'comment',
67  'correct_response',
68  'interaction',
69  'node',
70  'objective',
71  ),
72  );
73 
74  public function __construct($packageId = null)
75  {
76  $this->packagesFolder = IL_OP_PACKAGES_FOLDER;
77  $this->load($packageId);
78  $this->userId = $GLOBALS['USER']['usr_id'];
79  }
80 
81  public function load($packageId)
82  {
83  global $ilDB;
84 
85  if (!is_numeric($packageId))
86  {
87  return false;
88  }
89 
90  $lm_set = $ilDB->queryF('SELECT * FROM sahs_lm WHERE id = %s', array('integer'), array($packageId));
91  $lm_data = $ilDB->fetchAssoc($lm_set);
92  $pg_set = $ilDB->queryF('SELECT * FROM cp_package WHERE obj_id = %s', array('integer'), array($packageId));
93  $pg_data = $ilDB->fetchAssoc($lm_set);
94 
95  $this->packageData = array_merge($lm_data, $pg_data);
96  $this->packageId = $packageId;
97  $this->packageFolder = $this->packagesFolder . '/' . $packageId;
98  $this->packageFile = $this->packageFolder . '.zip';
99  $this->imsmanifestFile = $this->packageFolder . '/' . 'imsmanifest.xml';
100  return true;
101  }
102 
103  public function rollback()
104  {
105  $this->setProgress(0, 'Rolling back...');
106  $this->dbRemoveAll();
107  if (is_dir($this->packageFolder))
108  dir_delete($this->packageFolder);
109  if (is_file($this->packageFile))
110  @unlink($this->packageFile);
111  $this->setProgress(0, 'Roll back finished: Ok. ');
112  }
113 
114  public function exportZIP()
115  {
116  header('content-type: application/zip');
117  header('content-disposition: attachment; filename="' . basename($this->packageFile) . '"');
118  readfile($this->packageFile);
119  }
120 
124  public function exportXML()
125  {
126  global $ilDB;
127 
128  header('content-type: text/xml');
129  header('content-disposition: attachment; filename="manifest.xml"');
130 
131  //$row = ilSCORM13DB::getRecord("cp_package", "obj_id",$this->packageId);
132  $res = $ilDB->queryF(
133  'SELECT xmldata FROM cp_package WHERE obj_id = %s',
134  array('integer'),
135  array($this->packageId)
136  );
137  $row = $ilDB->fetchAssoc($res);
138 
139  print($row['xmldata']);
140  }
141 
142 
149  public function il_import($packageFolder,$packageId,$ilias,$validate,$reimport=false){
150  global $ilDB, $ilLog, $ilErr;
151 
152 
153  if ($reimport === true) {
154  $this->packageId = $packageId;
155  $this->dbRemoveAll();
156  }
157 
158  $this->packageFolder=$packageFolder;
159  $this->packageId=$packageId;
160  $this->imsmanifestFile = $this->packageFolder . '/' . 'imsmanifest.xml';
161  //step 1 - parse Manifest-File and validate
162  $this->imsmanifest = new DOMDocument;
163  $this->imsmanifest->async = false;
164  if (!@$this->imsmanifest->load($this->imsmanifestFile))
165  {
166  $this->diagnostic[] = 'XML not wellformed';
167  return false;
168  }
169 
170  //step 2 tranform
171  $this->manifest = $this->transform($this->imsmanifest, self::DB_ENCODE_XSL);
172 
173  if (!$this->manifest)
174  {
175  $this->diagnostic[] = 'Cannot transform into normalized manifest';
176  return false;
177  }
178  //setp 2.5 if only a single item, make sure the scormType of it's linked resource is SCO
179  $path = new DOMXpath($this->manifest);
180  $path->registerNamespace("scorm","http://www.openpalms.net/scorm/scorm13");
181  $items = $path->query("//scorm:item");
182  if($items->length == 1){
183  $n = $items->item(0);
184  $resource = $path->query("//scorm:resource");//[&id='"+$n->getAttribute("resourceId")+"']");
185  foreach($resource as $res){
186  if($res->getAttribute('id') == $n->getAttribute("resourceId")){
187  $res->setAttribute('scormType','sco');
188  }
189  }
190  }
191  //$this->manifest->save("C:\Users\gratat\after.xml");
192  //step 3 validation -just for normalized XML
193  if ($validate=="y") {
194  if (!$this->validate($this->manifest, self::VALIDATE_XSD))
195  {
196 
197  $ilErr->raiseError("<b>The uploaded SCORM 1.2 / SCORM 2004 is not valid. You can try to import the package without the validation option checked on your own risk. </b><br><br>Validation Error(s):</b><br> Normalized XML is not conform to ". self::VALIDATE_XSD,
198  $ilErr->MESSAGE);
199  }
200  }
201  $this->dbImport($this->manifest);
202 
203  if(file_exists($this->packageFolder . '/' . 'index.xml'))
204  {
205  $doc = simplexml_load_file($this->packageFolder . '/' . 'index.xml');
206  $l = $doc->xpath ("/ContentObject/MetaData" );
207  if($l[0])
208  {
209  include_once 'Services/MetaData/classes/class.ilMDXMLCopier.php';
210  $mdxml =& new ilMDXMLCopier($l[0]->asXML(),$packageId,$packageId,ilObject::_lookupType($packageId));
211  $mdxml->startParsing();
212  $mdxml->getMDObject()->update();
213  }
214  }
215 
216  //step 5
217  $x = simplexml_load_string($this->manifest->saveXML());
218  $x['persistPreviousAttempts'] = $this->packageData['persistprevattempts'];
219  $x['online'] = $this->packageData['c_online'];
220 
221  $x['defaultLessonMode'] = $this->packageData['default_lesson_mode'];
222  $x['credit'] = $this->packageData['credit'];
223  $x['autoReview'] = $this->packageData['auto_review'];
224  $j = array();
225  // first read resources into flat array to resolve item/identifierref later
226  $r = array();
227  foreach ($x->resource as $xe)
228  {
229  $r[strval($xe['id'])] = $xe;
230  unset($xe);
231  }
232  // iterate through items and set href and scoType as activity attributes
233  foreach ($x->xpath('//*[local-name()="item"]') as $xe)
234  {
235  // get reference to resource and set href accordingly
236  if ($b = $r[strval($xe['resourceId'])])
237  {
238  $xe['href'] = strval($b['base']) . strval($b['href']);
239  unset($xe['resourceId']);
240  if (strval($b['scormType'])=='sco') $xe['sco'] = true;
241  }
242  }
243  // iterate recursivly through activities and build up simple php object
244  // with items and associated sequencings
245  // top node is the default organization which is handled as an item
246  self::jsonNode($x->organization, $j['item']);
247  foreach($x->sequencing as $s)
248  {
249  self::jsonNode($s, $j['sequencing'][]);
250  }
251  // combined manifest+resources xml:base is set as organization base
252  $j['item']['base'] = strval($x['base']);
253  // package folder is base to whole playing process
254  $j['base'] = $packageFolder . '/';
255  $j['foreignId'] = floatval($x['foreignId']); // manifest cp_node_id for associating global (package wide) objectives
256  $j['id'] = strval($x['id']); // manifest id for associating global (package wide) objectives
257 
258 
259  //last step - build ADL Activity tree
260  $act = new SeqTreeBuilder();
261  $adl_tree = $act->buildNodeSeqTree($this->imsmanifestFile);
262  $ilDB->update('cp_package',
263  array(
264  'xmldata' => array('clob', $x->asXML()),
265  'jsdata' => array('clob', json_encode($j)),
266  'activitytree' => array('clob', json_encode($adl_tree['tree'])),
267  'global_to_system' => array('integer', (int)$adl_tree['global']),
268  'shared_data_global_to_system' => array('integer', (int)$adl_tree['dataglobal'])
269  ),
270  array(
271  'obj_id' => array('integer', (int)$this->packageId)
272  )
273  );
274 
275  return $j['item']['title'];
276  }
277 
278 
285  public function il_importSco($packageId, $sco_id, $packageFolder)
286  {
287  global $ilDB, $ilLog;
288 
289  $this->packageFolder=$packageFolder;
290  $this->packageId=$packageId;
291  $this->imsmanifestFile = $this->packageFolder . '/' . 'index.xml';
292  $this->imsmanifest = new DOMDocument;
293  $this->imsmanifest->async = false;
294 
295  if (!@$this->imsmanifest->load($this->imsmanifestFile))
296  {
297  $this->diagnostic[] = 'XML not wellformed';
298  return false;
299  }
300 
302  $sco = new ilSCORM2004Sco($slm,$sco_id);
303  $this->dbImportSco($slm,$sco);
304 
305  // import sco.xml
306  $sco_xml_file = $this->packageFolder . '/sco.xml';
307  if (is_file($sco_xml_file))
308  {
309  $scodoc = new DOMDocument;
310  $scodoc->async = false;
311  if (!@$scodoc->load($sco_xml_file))
312  {
313  $this->diagnostic[] = 'XML of sco.xml not wellformed';
314  return false;
315  }
316  //$doc = new SimpleXMLElement($scodoc->saveXml());
317  //$l = $doc->xpath("/sco/objective");
318  $xpath = new DOMXPath($scodoc);
319  $nodes = $xpath->query("/sco/objective");
320  foreach($nodes as $node)
321  {
322  $t_node = $node->firstChild;
323  if (is_object($t_node))
324  {
325  $objective_text = $t_node->textContent;
326  if (trim($objective_text) != "")
327  {
328  $objs = $sco->getObjectives();
329  foreach ($objs as $o)
330  {
331  $mappings = $o->getMappings();
332  if ($mappings == null)
333  {
334  $ob = new ilScorm2004Objective($sco->getId(), $o->getId());
335  $ob->setObjectiveID($objective_text);
336  $ob->updateObjective();
337  }
338  }
339  }
340  }
341  }
342  }
343  return "";
344  }
345 
352  public function il_importAss($packageId, $sco_id, $packageFolder)
353  {
354  global $ilDB, $ilLog;
355 
356  $this->packageFolder=$packageFolder;
357  $this->packageId=$packageId;
358  $this->imsmanifestFile = $this->packageFolder . '/' . 'index.xml';
359  $this->imsmanifest = new DOMDocument;
360  $this->imsmanifest->async = false;
361 
362  if (!@$this->imsmanifest->load($this->imsmanifestFile))
363  {
364  $this->diagnostic[] = 'XML not wellformed';
365  return false;
366  }
367 
369  $sco = new ilSCORM2004Asset($slm,$sco_id);
370  $this->dbImportSco($slm,$sco, true);
371 
372  // import sco.xml
373 /*
374  $sco_xml_file = $this->packageFolder . '/sco.xml';
375  if (is_file($sco_xml_file))
376  {
377  $scodoc = new DOMDocument;
378  $scodoc->async = false;
379  if (!@$scodoc->load($sco_xml_file))
380  {
381  $this->diagnostic[] = 'XML of sco.xml not wellformed';
382  return false;
383  }
384  //$doc = new SimpleXMLElement($scodoc->saveXml());
385  //$l = $doc->xpath("/sco/objective");
386  $xpath = new DOMXPath($scodoc);
387  $nodes = $xpath->query("/sco/objective");
388  foreach($nodes as $node)
389  {
390  $t_node = $node->firstChild;
391  if (is_object($t_node))
392  {
393  $objective_text = $t_node->textContent;
394  if (trim($objective_text) != "")
395  {
396  $objs = $sco->getObjectives();
397  foreach ($objs as $o)
398  {
399  $mappings = $o->getMappings();
400  if ($mappings == null)
401  {
402  $ob = new ilScorm2004Objective($sco->getId(), $o->getId());
403  $ob->setObjectiveID($objective_text);
404  $ob->updateObjective();
405  }
406  }
407  }
408  }
409  }
410  }
411 */
412  return "";
413  }
414 
415  public function il_importLM($slm, $packageFolder, $a_import_sequencing = false)
416  {
417  global $ilDB, $ilLog;
418 
419  $this->packageFolder=$packageFolder;
420  $this->packageId=$slm->getId();
421  $this->imsmanifestFile = $this->packageFolder . '/' . 'imsmanifest.xml';
422  $this->imsmanifest = new DOMDocument;
423  $this->imsmanifest->async = false;
424  $this->imsmanifest->formatOutput = false;
425  $this->imsmanifest->preserveWhiteSpace = false;
426  $this->slm = $slm;
427  if (!@$this->imsmanifest->load($this->imsmanifestFile))
428  {
429  $this->diagnostic[] = 'XML not wellformed';
430  return false;
431  }
432 
433  $this->mani_xpath = new DOMXPath($this->imsmanifest);
434  $this->mani_xpath->registerNamespace("d", "http://www.imsproject.org/xsd/imscp_rootv1p1p2");
435  $this->mani_xpath->registerNamespace("imscp", "http://www.imsglobal.org/xsd/imscp_v1p1");
436  $this->mani_xpath->registerNamespace("imsss", "http://www.imsglobal.org/xsd/imsss");
437 
438 
439  $this->dbImportLM(simplexml_import_dom($this->imsmanifest->documentElement), "",
440  $a_import_sequencing);
441 
442  if(is_dir($packageFolder."/glossary"))
443  {
444  $this->importGlossary($slm,$packageFolder."/glossary");
445  }
446  //die($slm->title);
447 
448  return $slm->title;
449  }
450 
452  {
453  global $ilias;
454  // create and insert object in objecttree
455  include_once("./Modules/Glossary/classes/class.ilObjGlossary.php");
456  $newObj = new ilObjGlossary();
457  $newObj->setType('glo');
458  $newObj->setTitle('');
459  $newObj->create(true);
460  $newObj->createReference();
461  $newObj->putInTree($_GET["ref_id"]);
462  $newObj->setPermissions($_GET["ref_id"]);
463  $newObj->notify("new",$_GET["ref_id"],$_GET["parent_non_rbac_id"],$_GET["ref_id"],$newObj->getRefId());
464 
465  $xml_file = $packageFolder."/glossary.xml";
466 
467  // check whether xml file exists within zip file
468  if (!is_file($xml_file))
469  {
470  return;
471  }
472 
473  include_once ("./Modules/LearningModule/classes/class.ilContObjParser.php");
474  $contParser = new ilContObjParser($newObj, $xml_file, $packageFolder);
475  $contParser->startParsing();
476  $newObj->update();
477  //ilObject::_writeImportId($newObj->getId(), $newObj->getImportId());
478  $slm->setAssignedGlossary($newObj->getId());
479  $slm->update();
480  }
481 
482  function dbImportLM($node, $parent_id = "", $a_import_sequencing = false)
483  {
484 
485  switch($node->getName())
486  {
487  case "manifest":
488  $this->slm_tree =& new ilTree($this->slm->getId());
489  $this->slm_tree->setTreeTablePK("slm_id");
490  $this->slm_tree->setTableNames('sahs_sc13_tree', 'sahs_sc13_tree_node');
491  $this->slm_tree->addTree($this->slm->getId(), 1);
492 
493  //add seqinfo for rootNode
494  include_once ("./Modules/Scorm2004/classes/seq_editor/class.ilSCORM2004Sequencing.php");
495  $seq_info = new ilSCORM2004Sequencing($this->slm->getId(),true);
496 
497  // get original sequencing information
498  $r = $this->mani_xpath->query("/d:manifest/d:organizations/d:organization/imsss:sequencing");
499  $this->imsmanifest->formatOutput = false;
500  if ($r)
501  {
502  $this->setSequencingInfo($r->item(0), $seq_info, $a_import_sequencing);
503  if ($a_import_sequencing)
504  {
505  $seq_info->initDom();
506  }
507  }
508  $seq_info->insert();
509 
510  if(file_exists($this->packageFolder . '/' . 'index.xml'))
511  {
512  $doc = simplexml_load_file($this->packageFolder . '/' . 'index.xml');
513  $l = $doc->xpath ( "/ContentObject/MetaData" );
514  if($l[0])
515  {
516  include_once 'Services/MetaData/classes/class.ilMDXMLCopier.php';
517  $mdxml =& new ilMDXMLCopier($l[0]->asXML(),$this->slm->getId(),$this->slm->getId(),$this->slm->getType());
518  $mdxml->startParsing();
519  $mdxml->getMDObject()->update();
520  }
521  }
522  break;
523  case "organization":
524  $this->slm->title=$node->title;
525  break;
526  case "item":
527  $a = $node->attributes();
528  if(preg_match("/il_\d+_chap_\d+/",$a['identifier']))
529  {
530  $chap=& new ilSCORM2004Chapter($this->slm);
531  $chap->setTitle($node->title);
532  $chap->setSLMId($this->slm->getId());
533  $chap->create(true);
534 
535  // save sequencing information
536  $r = $this->mani_xpath->query("//d:item[@identifier='".$a['identifier']."']/imsss:sequencing");
537  if ($r)
538  {
539  $seq_info = new ilSCORM2004Sequencing($chap->getId());
540  $this->setSequencingInfo($r->item(0), $seq_info, $a_import_sequencing);
541  $seq_info->initDom();
542  $seq_info->insert();
543  }
544 
545  ilSCORM2004Node::putInTree($chap, $parent_id, "");
546  $parent_id = $chap->getId();
547  $doc = simplexml_load_file($this->packageFolder . '/' . 'index.xml');
548  $l = $doc->xpath ( "/ContentObject/StructureObject/MetaData[General/Identifier/@Entry='".$a['identifier']."']" );
549  if($l[0])
550  {
551  include_once 'Services/MetaData/classes/class.ilMDXMLCopier.php';
552  $mdxml =& new ilMDXMLCopier($l[0]->asXML(),$this->slm->getId(),$chap->getId(),$chap->getType());
553  $mdxml->startParsing();
554  $mdxml->getMDObject()->update();
555  }
556  }
557  if(preg_match("/il_\d+_sco_(\d+)/",$a['identifier'], $match))
558  {
559  $sco = new ilSCORM2004Sco($this->slm);
560  $sco->setTitle($node->title);
561  $sco->setSLMId($this->slm->getId());
562  $sco->create(true);
563 
564  // save sequencing information
565  $r = $this->mani_xpath->query("//d:item[@identifier='".$a['identifier']."']/imsss:sequencing");
566  if ($r)
567  {
568  $seq_info = new ilSCORM2004Sequencing($sco->getId());
569  $this->setSequencingInfo($r->item(0), $seq_info, $a_import_sequencing,
570  "local_obj_".$sco->getID()."_0");
571  $seq_info->initDom();
572  $seq_info->insert();
573  }
574 
575  ilSCORM2004Node::putInTree($sco, $parent_id, "");
576  $newPack = new ilSCORM13Package();
577  $newPack->il_importSco($this->slm->getId(),$sco->getId(),$this->packageFolder."/".$match[1]);
578  $parent_id = $sco->getId();
579  }
580  if(preg_match("/il_\d+_ass_(\d+)/",$a['identifier'], $match))
581  {
582  $ass = new ilSCORM2004Asset($this->slm);
583  $ass->setTitle($node->title);
584  $ass->setSLMId($this->slm->getId());
585  $ass->create(true);
586 
587  // save sequencing information
588  $r = $this->mani_xpath->query("//d:item[@identifier='".$a['identifier']."']/imsss:sequencing");
589  if ($r)
590  {
591  $seq_info = new ilSCORM2004Sequencing($ass->getId());
592  $this->setSequencingInfo($r->item(0), $seq_info, $a_import_sequencing,
593  "local_obj_".$ass->getID()."_0");
594  $seq_info->initDom();
595  $seq_info->insert();
596  }
597 
598  ilSCORM2004Node::putInTree($ass, $parent_id, "");
599  $newPack = new ilSCORM13Package();
600  $newPack->il_importAss($this->slm->getId(),$ass->getId(),$this->packageFolder."/".$match[1]);
601  $parent_id = $ass->getId();
602  }
603 
604  break;
605  }
606  //if($node->nodeType==XML_ELEMENT_NODE)
607  {
608  foreach($node->children() as $child)
609  {
610  $this->dbImportLM($child, $parent_id, $a_import_sequencing);
611  }
612  }
613  }
614 
621  function setSequencingInfo($a_node, $a_seq_info, $a_import_sequencing, $a_fix_obj_id = "")
622  {
623  $seq_xml = trim(str_replace("imsss:", "", $this->imsmanifest->saveXML($a_node)));
624  if ($seq_xml != "")
625  {
626  $a_seq_info->setImportSeqXml('<?xml version="1.0"?>'.$seq_xml);
627  }
628  if ($a_import_sequencing)
629  {
630  if ($a_fix_obj_id != "")
631  {
632  $seq_xml = preg_replace("/local_obj_[0-9]*_0/", $a_fix_obj_id, $seq_xml);
633  }
634  $a_seq_info->setSeqXml('<?xml version="1.0"?>'.$seq_xml);
635  }
636  }
637 
638 
639  private function setProgress($progress, $msg = '')
640  {
641  $this->progress = $progress;
642  $this->diagnostic[] = $msg;
643  }
644 
653  public function jsonNode($node, &$sink)
654  {
655  foreach ($node->attributes() as $k => $v)
656  {
657  // cast to boolean and number if possible
658  $v = strval($v);
659  if ($v==="true") $v = true;
660  else if ($v==="false") $v = false;
661  else if (is_numeric($v)) $v = (float) $v;
662  $sink[$k] = $v;
663  }
664  foreach ($node->children() as $name => $child)
665  {
666  self::jsonNode($child, $sink[$name][]); // RECURSION
667  }
668  }
669 
670  public function dbImportSco($slm,$sco, $asset = false)
671  {
672  $qtis = array();
673  $d = ilUtil::getDir ( $this->packageFolder );
674  foreach ( $d as $f ) {
675  //continue;
676  if ($f [type] == 'file' && substr ( $f [entry], 0, 4 ) == 'qti_') {
677  include_once "./Services/QTI/classes/class.ilQTIParser.php";
678  include_once "./Modules/Test/classes/class.ilObjTest.php";
679 
680 
681  $qtiParser = new ilQTIParser ( $this->packageFolder . "/" . $f [entry], IL_MO_VERIFY_QTI, 0, "" );
682  $result = $qtiParser->startParsing ();
683  $founditems = & $qtiParser->getFoundItems ();
684  // die(print_r($founditems));
685  foreach ( $founditems as $qp ) {
686  $newObj = new ilObjTest ( 0, true );
687 
688  // This creates a lot of invalid repository objects for each question
689  // question are not repository objects (see e.g. table object_data), alex 29 Sep 2009
690 
691 // $newObj->setType ( $qp ['type'] );
692 // $newObj->setTitle ( $qp ['title'] );
693 // $newObj->create ( true );
694 // $newObj->createReference ();
695 // $newObj->putInTree ($_GET ["ref_id"]);
696 // $newObj->setPermissions ( $sco->getId ());
697 // $newObj->notify ("new", $_GET["ref_id"], $sco->getId (), $_GET["ref_id"], $newObj->getRefId () );
698 // $newObj->mark_schema->flush ();
699  $qtiParser = new ilQTIParser ( $this->packageFolder . "/" . $f [entry], IL_MO_PARSE_QTI, 0, "" );
700  $qtiParser->setTestObject ( $newObj );
701  $result = $qtiParser->startParsing ();
702 // $newObj->saveToDb ();
703  $qtis = array_merge($qtis, $qtiParser->getImportMapping());
704 
705  }
706  }
707  }
708 //exit;
709  include_once 'Modules/Scorm2004/classes/class.ilSCORM2004Page.php';
710  $doc = new SimpleXMLElement($this->imsmanifest->saveXml());
711  $l = $doc->xpath ( "/ContentObject/MetaData" );
712  if($l[0])
713  {
714  include_once 'Services/MetaData/classes/class.ilMDXMLCopier.php';
715  $mdxml =& new ilMDXMLCopier($l[0]->asXML(),$slm->getId(),$sco->getId(),$sco->getType());
716  $mdxml->startParsing();
717  $mdxml->getMDObject()->update();
718  }
719  $l = $doc->xpath("/ContentObject/PageObject");
720  foreach ( $l as $page_xml )
721  {
722  $tnode = $page_xml->xpath ( 'MetaData/General/Title' );
723  $page = new ilSCORM2004PageNode ( $slm );
724  $page->setTitle ( $tnode [0] );
725  $page->setSLMId ( $slm->getId () );
726  $page->create (true);
727  ilSCORM2004Node::putInTree ( $page, $sco->getId (), $target );
728  $pmd = $page_xml->xpath ("MetaData");
729  if($pmd[0])
730  {
731  include_once 'Services/MetaData/classes/class.ilMDXMLCopier.php';
732  $mdxml =& new ilMDXMLCopier($pmd[0]->asXML(),$slm->getId(),$page->getId(),$page->getType());
733  $mdxml->startParsing();
734  $mdxml->getMDObject()->update();
735  }
736  $tnode = $page_xml->xpath("//MediaObject/MediaAlias | //InteractiveImage/MediaAlias");
737  foreach($tnode as $ttnode)
738  {
739  include_once './Services/MediaObjects/classes/class.ilObjMediaObject.php';
740  $OriginId = $ttnode[OriginId];
741  $medianodes = $doc->xpath("//MediaObject[MetaData/General/Identifier/@Entry='".$OriginId ."']");
742  $medianode = $medianodes[0];
743  if($medianode)
744  {
745  $media_object = new ilObjMediaObject ( );
746  $media_object->setTitle ($medianode->MetaData->General->Title);
747  $media_object->setDescription ($medianode->MetaData->General->Description);
748  $media_object->create (false);
749  $mmd = $medianode->xpath ("MetaData");
750  if($mmd[0])
751  {
752  include_once 'Services/MetaData/classes/class.ilMDXMLCopier.php';
753  $mdxml =& new ilMDXMLCopier($mmd[0]->asXML(),0,$media_object->getId(),$media_object->getType());
754  $mdxml->startParsing();
755  $mdxml->getMDObject()->update();
756  }
757  // determine and create mob directory, move uploaded file to directory
758  $media_object->createDirectory ();
759  $mob_dir = ilObjMediaObject::_getDirectory ( $media_object->getId () );
760  foreach ( $medianode->MediaItem as $xMediaItem )
761  {
762  $media_item = & new ilMediaItem ( );
763  $media_object->addMediaItem ( $media_item );
764  $media_item->setPurpose($xMediaItem[Purpose]);
765  $media_item->setFormat($xMediaItem->Format );
766  $media_item->setLocation($xMediaItem->Location);
767  $media_item->setLocationType($xMediaItem->Location[Type]);
768  $media_item->setWidth ( $xMediaItem->Layout[Width]);
769  $media_item->setHeight ( $xMediaItem->Layout[Height]);
770  $media_item->setHAlign($xMediaItem->Layout[HorizontalAlign]);
771  $media_item->setCaption($xMediaItem->Caption);
772  $media_item->setTextRepresentation($xMediaItem->TextRepresentation);
773  $nr = 0;
774 
775  // add map areas (external links only)
776  foreach ($xMediaItem->MapArea as $n => $v)
777  {
778 
779  if ($v->ExtLink[Href] != "")
780  {
781  include_once("./Services/MediaObjects/classes/class.ilMapArea.php");
782  $ma = new ilMapArea();
783 
784  $map_area = new ilMapArea();
785  $map_area->setShape($v[Shape]);
786  $map_area->setCoords($v[Coords]);
787  $map_area->setLinkType(IL_EXT_LINK);
788  $map_area->setTitle($v->ExtLink);
789  $map_area->setHref($v->ExtLink[Href]);
790 
791  $media_item->addMapArea($map_area);
792  }
793  }
794 
795  if($media_item->getLocationType()=="LocalFile")
796  {
797 // $tmp_name = $this->packageFolder."/objects/".$OriginId."/".$xMediaItem->Location;
798 // copy($tmp_name, $mob_dir."/".$xMediaItem->Location);
799  }
800  }
801 
802  // copy whole directory
803  ilUtil::rCopy($this->packageFolder."/objects/".$OriginId, $mob_dir);
804 
805 
806  // alex: fixed media import: these lines have been
807  // behind the next curly bracket which makes it fail
808  // when no medianode is given. (id=0 -> fatal error)
809  ilUtil::renameExecutables ( $mob_dir );
810  $media_object->update(true);
811  $ttnode [OriginId] = "il__mob_" . $media_object->getId ();
812  }
813  }
814  include_once("./Modules/File/classes/class.ilObjFile.php");
815  include_once("./Services/Utilities/classes/class.ilFileUtils.php");
816  include_once("./Services/MediaObjects/classes/class.ilObjMediaObject.php");
817 
818  $intlinks = $page_xml->xpath("//IntLink");
819  //die($intlinks);
820  //if($intlinks )
821  {
822  foreach ( $intlinks as $intlink )
823  {
824  if($intlink[Type]!="File") continue;
825  $path = $this->packageFolder."/objects/".str_replace('dfile','file',$intlink[Target]);
826  if(!is_dir($path )) continue;
827  $ffiles = array();
829  $filename = $ffiles[file][0];
830  $fileObj = new ilObjFile();
831  $fileObj->setType("file");
834 
835  // better use this, mime_content_type is deprecated
836  $fileObj->setFileType(ilObjMediaObject::getMimeType($path. "/" . $filename));
837 
838  $fileObj->setFileSize(filesize($path. "/" . $filename));
839  $fileObj->create();
840  $fileObj->createReference();
841  //$fileObj->putInTree($_GET["ref_id"]);
842  //$fileObj->setPermissions($slm->getId ());
843  $fileObj->createDirectory();
844  $fileObj->storeUnzipedFile($path."/" .$filename,ilFileUtils::utf8_encode(ilUtil::stripSlashes($filename)));
845  $intlink[Target]="il__dfile_".$fileObj->getId();
846 
847  }
848  }
849  $fileitems = $page_xml->xpath("//FileItem/Identifier");
850  //if($intlinks )
851  {
852  foreach ( $fileitems as $fileitem )
853  {
854  $path = $this->packageFolder."/objects/".$fileitem[Entry];
855  if(!is_dir($path )) continue;
856  $ffiles = array();
858  $filename = $ffiles[file][0];
859  $fileObj = new ilObjFile();
860  $fileObj->setType("file");
863 
864  // better use this, mime_content_type is deprecated
865  $fileObj->setFileType(ilObjMediaObject::getMimeType($path. "/" . $filename));
866 
867  $fileObj->setFileSize(filesize($path. "/" . $filename));
868  $fileObj->create();
869  $fileObj->createReference();
870  //$fileObj->putInTree($_GET["ref_id"]);
871  //$fileObj->setPermissions($slm->getId ());
872  $fileObj->createDirectory();
873  $fileObj->storeUnzipedFile($path."/" .$filename,ilFileUtils::utf8_encode(ilUtil::stripSlashes($filename)));
874  $fileitem[Entry]="il__file_".$fileObj->getId();
875 
876  }
877  }
878  $pagex = new ilSCORM2004Page($page->getId());
879 
880  $ddoc = new DOMDocument();
881  $ddoc->async = false;
882  $ddoc->preserveWhiteSpace = false;
883  $ddoc->formatOutput = false;
884  $ddoc->loadXML($page_xml->asXML());
885  $xpath = new DOMXPath($ddoc);
886  $tnode = $xpath->query('PageContent');
887  $t = "<PageObject>";
888  foreach($tnode as $ttnode)
889  $t .= $ddoc->saveXML($ttnode);
890  $t .="</PageObject>";
891  foreach ($qtis as $old=>$q)
892  $t = str_replace($old,'il__qst_'.$q['pool'], $t);
893  $pagex->setXMLContent($t);
894  $pagex->updateFromXML();
895  }
896  }
897 
898  public function dbImport($node, &$lft=1, $depth=1, $parent=0)
899  {
900  global $ilDB;
901 
902  switch ($node->nodeType)
903  {
904  case XML_DOCUMENT_NODE:
905 
906  // insert into cp_package
907  /*ilSCORM13DB::setRecord('cp_package', array(
908  'obj_id' => $this->packageId,
909  'identifier' => $this->packageName,
910  'persistPreviousAttempts' => 0,
911  'settings' => '',
912  ));*/
913 
914  $res = $ilDB->queryF(
915  'SELECT * FROM cp_package WHERE obj_id = %s AND c_identifier = %s',
916  array('integer', 'text'),
917  array($this->packageId, $this->packageName)
918  );
919  if($num_rows = $ilDB->numRows($res))
920  {
921  $query = 'UPDATE cp_package '
922  . 'SET persistprevattempts = %s, c_settings = %s '
923  . 'WHERE obj_id = %s AND c_identifier= %s';
924  $ilDB->manipulateF(
925  $query,
926  array('integer', 'text', 'integer', 'text'),
927  array(0, NULL, $this->packageId, $this->packageName)
928  );
929  }
930  else
931  {
932  $query = 'INSERT INTO cp_package (obj_id, c_identifier, persistprevattempts, c_settings) '
933  . 'VALUES (%s, %s, %s, %s)';
934  $ilDB->manipulateF(
935  $query,
936  array('integer','text','integer', 'text'),
937  array($this->packageId, $this->packageName, 0, NULL)
938  );
939  }
940 
941  // run sub nodes
942  $this->dbImport($node->documentElement); // RECURSION
943  break;
944 
945  case XML_ELEMENT_NODE:
946  if ($node->nodeName==='manifest')
947  {
948  if ($node->getAttribute('uri')=="")
949  {
950  // default URI is md5 hash of zip file, i.e. packageHash
951  $node->setAttribute('uri', 'md5:' . $this->packageHash);
952  }
953  }
954 
955  $cp_node_id = $ilDB->nextId('cp_node');
956 
957  $query = 'INSERT INTO cp_node (cp_node_id, slm_id, nodename) '
958  . 'VALUES (%s, %s, %s)';
959  $ilDB->manipulateF(
960  $query,
961  array('integer', 'integer', 'text'),
962  array($cp_node_id, $this->packageId, $node->nodeName)
963  );
964 
965  $query = 'INSERT INTO cp_tree (child, depth, lft, obj_id, parent, rgt) '
966  . 'VALUES (%s, %s, %s, %s, %s, %s)';
967  $ilDB->manipulateF(
968  $query,
969  array('integer', 'integer', 'integer', 'integer', 'integer', 'integer'),
970  array($cp_node_id, $depth, $lft++, $this->packageId, $parent, 0)
971  );
972 
973  // insert into cp_*
974  //$a = array('cp_node_id' => $cp_node_id);
975  $names = array('cp_node_id');
976  $values = array($cp_node_id);
977  $types = array('integer');
978 
979  foreach ($node->attributes as $attr)
980  {
981  switch(strtolower($attr->name))
982  {
983  case 'completionsetbycontent': $names[] = 'completionbycontent';break;
984  case 'objectivesetbycontent': $names[] = 'objectivebycontent';break;
985  case 'type': $names[] = 'c_type';break;
986  case 'mode': $names[] = 'c_mode';break;
987  case 'language': $names[] = 'c_language';break;
988  case 'condition': $names[] = 'c_condition';break;
989  case 'operator': $names[] = 'c_operator';break;
990  case 'condition': $names[] = 'c_condition';break;
991  case 'readnormalizedmeasure': $names[] = 'readnormalmeasure';break;
992  case 'writenormalizedmeasure': $names[] = 'writenormalmeasure';break;
993  case 'minnormalizedmeasure': $names[] = 'minnormalmeasure';break;
994  case 'primary': $names[] = 'c_primary';break;
995  case 'minnormalizedmeasure': $names[] = 'minnormalmeasure';break;
996  case 'persistpreviousattempts': $names[] = 'persistprevattempts';break;
997  case 'identifier': $names[] = 'c_identifier';break;
998  case 'settings': $names[] = 'c_settings';break;
999  case 'activityabsolutedurationlimit': $names[] = 'activityabsdurlimit';break;
1000  case 'activityexperienceddurationlimit': $names[] = 'activityexpdurlimit';break;
1001  case 'attemptabsolutedurationlimit': $names[] = 'attemptabsdurlimit';break;
1002  case 'measuresatisfactionifactive': $names[] = 'measuresatisfactive';break;
1003  case 'objectivemeasureweight': $names[] = 'objectivemeasweight';break;
1004  case 'requiredforcompleted': $names[] = 'requiredcompleted';break;
1005  case 'requiredforincomplete': $names[] = 'requiredincomplete';break;
1006  case 'requiredfornotsatisfied': $names[] = 'requirednotsatisfied';break;
1007  case 'rollupobjectivesatisfied': $names[] = 'rollupobjectivesatis';break;
1008  case 'rollupprogresscompletion': $names[] = 'rollupprogcompletion';break;
1009  case 'usecurrentattemptobjectiveinfo': $names[] = 'usecurattemptobjinfo';break;
1010  case 'usecurrentattemptprogressinfo': $names[] = 'usecurattemptproginfo';break;
1011  default: $names[] = strtolower($attr->name);break;
1012  }
1013 
1014  if(in_array($names[count($names) - 1],
1015  array('flow', 'completionbycontent',
1016  'objectivebycontent', 'rollupobjectivesatis',
1017  'tracked', 'choice',
1018  'choiceexit', 'satisfiedbymeasure',
1019  'c_primary', 'constrainchoice',
1020  'forwardonly', 'global_to_system',
1021  'writenormalmeasure', 'writesatisfiedstatus',
1022  'readnormalmeasure', 'readsatisfiedstatus',
1023  'preventactivation', 'measuresatisfactive',
1024  'reorderchildren', 'usecurattemptproginfo',
1025  'usecurattemptobjinfo', 'rollupprogcompletion',
1026  'read_shared_data', 'write_shared_data',
1027  'shared_data_global_to_system', 'completedbymeasure')))
1028  {
1029  if($attr->value == 'true')
1030  $values[] = 1;
1031  else if ($attr->value == 'false')
1032  $values[] = 0;
1033  else
1034  $values[] = (int)$attr->value;
1035  }
1036  else
1037  {
1038  $values[] = $attr->value;
1039  }
1040 
1041  if( in_array($names[count($names) - 1],
1042  array('objectivesglobtosys', 'attemptlimit',
1043  'flow', 'completionbycontent',
1044  'objectivebycontent', 'rollupobjectivesatis',
1045  'tracked', 'choice',
1046  'choiceexit', 'satisfiedbymeasure',
1047  'c_primary', 'constrainchoice',
1048  'forwardonly', 'global_to_system',
1049  'writenormalmeasure', 'writesatisfiedstatus',
1050  'readnormalmeasure', 'readsatisfiedstatus',
1051  'preventactivation', 'measuresatisfactive',
1052  'reorderchildren', 'usecurattemptproginfo',
1053  'usecurattemptobjinfo', 'rollupprogcompletion',
1054  'read_shared_data', 'write_shared_data',
1055  'shared_data_global_to_system')))
1056  $types[] = 'integer';
1057  else if ( in_array($names[count($names) - 1],
1058  array('jsdata', 'xmldata', 'activitytree', 'data')))
1059  $types[] = 'clob';
1060  else if ( in_array($names[count($names) - 1],
1061  array('objectivemeasweight')))
1062  $types[] = 'float';
1063  else
1064  $types[] = 'text';
1065  }
1066 
1067  if($node->nodeName==='datamap')
1068  {
1069  $names[] = 'slm_id';
1070  $values[] = $this->packageId;
1071  $types[] = 'integer';
1072 
1073  $names[] = 'sco_node_id';
1074  $values[] = $parent;
1075  $types[] = 'integer';
1076  }
1077 
1078  // we have to change the insert method because of clob fields ($ilDB->manipulate does not work here)
1079  $insert_data = array();
1080  foreach($names as $key => $db_field)
1081  {
1082  $insert_data[$db_field] = array($types[$key], trim($values[$key]));
1083  }
1084  $ilDB->insert('cp_'.strtolower($node->nodeName), $insert_data);
1085 
1086  $node->setAttribute('foreignId', $cp_node_id);
1087  $this->idmap[$node->getAttribute('id')] = $cp_node_id;
1088 
1089  // run sub nodes
1090  foreach($node->childNodes as $child)
1091  {
1092  $this->dbImport($child, $lft, $depth + 1, $cp_node_id); // RECURSION
1093  }
1094 
1095  // update cp_tree (rgt value for pre order walk in sql tree)
1096  $query = 'UPDATE cp_tree SET rgt = %s WHERE child = %s';
1097  $ilDB->manipulateF(
1098  $query,
1099  array('integer', 'integer'),
1100  array($lft++, $cp_node_id)
1101  );
1102 
1103  break;
1104  }
1105  }
1106 
1110  public function dbAddNew()
1111  {
1112  global $ilDB;
1113 
1114  //$this->packageId = 100;
1115  //return true;
1116  //ilSCORM13DB::getRecord('sahs_lm', array());
1117  // $this->packageId = ilSCORM13DB::getRecord('sahs_lm', array());
1118 /* ilSCORM13DB::setRecord('cp_package', array(
1119  'obj_id' => $this->packageId,
1120  'xmldata' => $x->asXML(),
1121  'jsdata' => json_encode($j),
1122  ), 'obj_id');
1123 */
1124 
1125  $ilDB->insert('cp_package', array(
1126  'obj_id' => array('integer', $this->packageId),
1127  'xmldata' => array('clob', $x->asXML()),
1128  'jsdata' => array('clob', json_encode($j))
1129  ));
1130 
1131  return true;
1132  }
1133 
1134 
1135  public function removeCMIData()
1136  {
1137  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004DeleteData.php");
1139 
1140  include_once("./Services/Tracking/classes/class.ilLPStatusWrapper.php");
1141  ilLPStatusWrapper::_refreshStatus($this->packageId);
1142 
1143  }
1144 
1145  public function removeCPData()
1146  {
1147  global $ilDB, $ilLog;
1148 
1149  //get relevant nodes
1150  $cp_nodes = array();
1151 
1152  $res = $ilDB->queryF(
1153  'SELECT cp_node.cp_node_id FROM cp_node WHERE cp_node.slm_id = %s',
1154  array('integer'),
1155  array($this->packageId)
1156  );
1157  while($data = $ilDB->fetchAssoc($res))
1158  {
1159  $cp_nodes[] = $data['cp_node_id'];
1160  }
1161 
1162  //remove package data
1163  foreach(self::$elements['cp'] as $t)
1164  {
1165  $t = 'cp_' . $t;
1166 
1167  $in = $ilDB->in(strtolower($t).'.cp_node_id', $cp_nodes, false, 'integer');
1168  $ilDB->manipulate('DELETE FROM '.strtolower($t).' WHERE '.$in);
1169  }
1170 
1171  // remove CP structure entries in tree and node
1172  $ilDB->manipulateF(
1173  'DELETE FROM cp_tree WHERE cp_tree.obj_id = %s',
1174  array('integer'),
1175  array($this->packageId)
1176  );
1177 
1178  $ilDB->manipulateF(
1179  'DELETE FROM cp_node WHERE cp_node.slm_id = %s',
1180  array('integer'),
1181  array($this->packageId)
1182  );
1183 
1184  // remove general package entry
1185  $ilDB->manipulateF(
1186  'DELETE FROM cp_package WHERE cp_package.obj_id = %s',
1187  array('integer'),
1188  array($this->packageId)
1189  );
1190  }
1191 
1192  public function dbRemoveAll()
1193  {
1194  //dont change order of calls
1195  $this->removeCMIData();
1196  $this->removeCPData();
1197  }
1198 
1199  public function transform($inputdoc, $xslfile, $outputpath = null)
1200  {
1201  $xsl = new DOMDocument;
1202  $xsl->async = false;
1203  if (!@$xsl->load($xslfile))
1204  {
1205  die('ERROR: load StyleSheet ' . $xslfile);
1206  }
1207  $prc = new XSLTProcessor;
1208  $prc->registerPHPFunctions();
1209  $r = @$prc->importStyleSheet($xsl);
1210  if (false===@$prc->importStyleSheet($xsl))
1211  {
1212  die('ERROR: importStyleSheet ' . $xslfile);
1213  }
1214  if ($outputpath)
1215  {
1216  file_put_contents($outputpath, $prc->transformToXML($inputdoc));
1217  }
1218  else
1219  {
1220  return $prc->transformToDoc($inputdoc);
1221  }
1222  }
1223 
1224  public function validate($doc, $schema)
1225  {
1226  libxml_use_internal_errors(true);
1227  $return = @$doc->schemaValidate($schema);
1228  if (!$return)
1229  {
1230  $levels = array(
1231  LIBXML_ERR_ERROR => 'Error',
1232  LIBXML_ERR_FATAL => 'Fatal Error'
1233  );
1234  foreach (libxml_get_errors() as $error)
1235  {
1236  $level = $levels[$error->level];
1237  if (isset($level))
1238  {
1239  $message = trim($error->message);
1240  $this->diagnostic[] = "XSLT $level (Line $error->line) $message";
1241  }
1242  }
1243  libxml_clear_errors();
1244  }
1245  libxml_use_internal_errors(false);
1246  return $return;
1247  }
1248 
1249  //to be called from IlObjUser
1250  public static function _removeTrackingDataForUser($user_id) {
1251 
1252  include_once("./Modules/Scorm2004/classes/class.ilSCORM2004DeleteData.php");
1254  //missing updatestatus
1255  }
1256 }
1257 ?>