'http://www.imsglobal.org/xsd/imsdt_v1p0']; public static $quizns = ['xmlns' => 'http://www.imsglobal.org/xsd/ims_qtiasiv1p2']; public static $resourcens = ['wl' => 'http://www.imsglobal.org/xsd/imswl_v1p0']; public static $instances = []; public static $manifest; public static $pathToManifestFolder; public static $namespaces = ['imscc' => 'http://www.imsglobal.org/xsd/imscc/imscp_v1p1', 'lomimscc' => 'http://ltsc.ieee.org/xsd/imscc/LOM', 'lom' => 'http://ltsc.ieee.org/xsd/LOM', 'voc' => 'http://ltsc.ieee.org/xsd/LOM/vocab', 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'cc' => 'http://www.imsglobal.org/xsd/imsccauth_v1p0', ]; public function __construct($path_to_manifest) { static::$manifest = new DOMDocument(); static::$manifest->validateOnParse = false; static::$pathToManifestFolder = dirname($path_to_manifest); static::logAction('Proccess start'); static::logAction('Load the manifest file: '.$path_to_manifest); if (!static::$manifest->load($path_to_manifest, LIBXML_NONET)) { static::logAction('Cannot load the manifest file: '.$path_to_manifest, true); } } /** * @return array */ public static function getquizns() { return static::$quizns; } /** * @return array */ public static function getforumns() { return static::$forumns; } /** * @return array */ public static function getresourcens() { return static::$resourcens; } /** * Find the imsmanifest.xml file inside the given folder and return its path. * * @param string $folder Full path name of the folder in which we expect to find imsmanifest.xml * * @return false|string */ public static function getManifest(string $folder) { if (!is_dir($folder)) { return false; } // Before iterate over directories, try to find one manifest at top level if (file_exists($folder.'/imsmanifest.xml')) { return $folder.'/imsmanifest.xml'; } $result = false; try { $dirIter = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::KEY_AS_PATHNAME); $recIter = new RecursiveIteratorIterator($dirIter, RecursiveIteratorIterator::CHILD_FIRST); foreach ($recIter as $info) { if ($info->isFile() && ($info->getFilename() == 'imsmanifest.xml')) { $result = $info->getPathname(); break; } } } catch (Exception $e) { } return $result; } public function isAuth() { $xpath = static::newxPath(static::$manifest, static::$namespaces); $count_auth = $xpath->evaluate('count(/imscc:manifest/cc:authorizations)'); if ($count_auth > 0) { $response = true; } else { $response = false; } return $response; } public function getNodesByCriteria($key, $value) { $response = []; if (array_key_exists('index', static::$instances)) { foreach (static::$instances['index'] as $item) { if ($item[$key] == $value) { $response[] = $item; } } } return $response; } public function countInstances($type) { $quantity = 0; if (array_key_exists('index', static::$instances)) { if (static::$instances['index'] && $type) { foreach (static::$instances['index'] as $instance) { if (!empty($instance['tool_type'])) { $types[] = $instance['tool_type']; } } $quantityInstances = array_count_values($types); $quantity = array_key_exists($type, $quantityInstances) ? $quantityInstances[$type] : 0; } } return $quantity; } public function getItemCcType($identifier) { $xpath = static::newxPath(static::$manifest, static::$namespaces); $nodes = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]/@type'); if ($nodes && !empty($nodes->item(0)->nodeValue)) { return $nodes->item(0)->nodeValue; } else { return ''; } } public function getItemHref($identifier) { $xpath = static::newxPath(static::$manifest, static::$namespaces); $nodes = $xpath->query('/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]/imscc:file/@href'); if ($nodes && !empty($nodes->item(0)->nodeValue)) { return $nodes->item(0)->nodeValue; } else { return ''; } } public static function newxPath(DOMDocument $manifest, $namespaces = '') { $xpath = new DOMXPath($manifest); if (!empty($namespaces)) { foreach ($namespaces as $prefix => $ns) { if (!$xpath->registerNamespace($prefix, $ns)) { static::logAction('Cannot register the namespace: '.$prefix.':'.$ns, true); } } } return $xpath; } public static function logFile() { return static::$pathToManifestFolder.DIRECTORY_SEPARATOR.'cc_import.log'; } public static function logAction($text, $criticalError = false) { $full_message = strtoupper(date("j/n/Y g:i:s a"))." - ".$text."\r"; file_put_contents(static::logFile(), $full_message, FILE_APPEND); if ($criticalError) { static::criticalError($text); } } public function convertToToolType($ccType) { $type = TYPE_UNKNOWN; if ($ccType == static::CC_TYPE_FORUM) { $type = TOOL_TYPE_FORUM; } if ($ccType == static::CC_TYPE_QUIZ) { $type = TOOL_TYPE_QUIZ; } if ($ccType == static::CC_TYPE_WEBLINK) { $type = TOOL_TYPE_WEBLINK; } if ($ccType == static::CC_TYPE_WEBCONTENT) { $type = TOOL_TYPE_DOCUMENT; } return $type; } protected function getMetadata($section, $key) { $xpath = static::newxPath(static::$manifest, static::$namespaces); $metadata = $xpath->query('/imscc:manifest/imscc:metadata/lomimscc:lom/lomimscc:'.$section.'/lomimscc:'.$key.'/lomimscc:string'); $value = !empty($metadata->item(0)->nodeValue) ? $metadata->item(0)->nodeValue : ''; return $value; } /** * Is activity visible or not. * * @param string $identifier * * @return number */ protected function getModuleVisible($identifier) { //Should item be hidden or not $mod_visible = 1; if (!empty($identifier)) { $xpath = static::newxPath(static::$manifest, static::$namespaces); $query = '/imscc:manifest/imscc:resources/imscc:resource[@identifier="'.$identifier.'"]'; $query .= '//lom:intendedEndUserRole/voc:vocabulary/lom:value'; $intendeduserrole = $xpath->query($query); if (!empty($intendeduserrole) && ($intendeduserrole->length > 0)) { $role = trim($intendeduserrole->item(0)->nodeValue); if (strcasecmp('Instructor', $role) == 0) { $mod_visible = 0; } } } return $mod_visible; } protected function createInstances($items, $level = 0, &$array_index = 0, $index_root = 0) { $level++; $i = 1; if ($items) { $xpath = self::newxPath(static::$manifest, static::$namespaces); foreach ($items as $item) { $array_index++; $title = $path = $tool_type = $identifierref = ''; if ($item->nodeName == 'item') { if ($item->hasAttribute('identifierref')) { $identifierref = $item->getAttribute('identifierref'); } $titles = $xpath->query('imscc:title', $item); if ($titles->length > 0) { $title = $titles->item(0)->nodeValue; } $ccType = $this->getItemCcType($identifierref); $tool_type = $this->convertToToolType($ccType); //Fix the label issue - MDL-33523 if (empty($identifierref) && empty($title)) { $tool_type = TYPE_UNKNOWN; } } elseif ($item->nodeName == 'resource') { $identifierref = $xpath->query('@identifier', $item); $identifierref = !empty($identifierref->item(0)->nodeValue) ? $identifierref->item(0)->nodeValue : ''; $ccType = $this->getItemCcType($identifierref); $tool_type = $this->convertToToolType($ccType); if (self::CC_TYPE_WEBCONTENT == $ccType) { $path = $this->getItemHref($identifierref); $title = basename($path); } else { // A resource but not a file... we assume it's a quiz bank and its assigned identifier is irrelevant to its name $title = 'Quiz Bank '.($this->countInstances($tool_type) + 1); } } if ($level == ROOT_DEEP) { $index_root = $array_index; } static::$instances['index'][$array_index] = [ 'common_cartridge_type' => $ccType, 'tool_type' => $tool_type, 'title' => $title ? $title : '', 'root_parent' => $index_root, 'index' => $array_index, 'deep' => $level, 'instance' => $this->countInstances($tool_type), 'resource_identifier' => $identifierref, ]; static::$instances['instances'][$tool_type][] = [ 'title' => $title, 'instance' => static::$instances['index'][$array_index]['instance'], 'common_cartridge_type' => $ccType, 'resource_identifier' => $identifierref, 'deep' => $level, 'src' => $path, ]; $more_items = $xpath->query('imscc:item', $item); if ($more_items->length > 0) { $this->createInstances($more_items, $level, $array_index, $index_root); } $i++; } } } protected static function criticalError($text) { $path_to_log = static::logFile(); echo '


A critical error has been found!

'.$text.'

The process has been stopped. Please see the log file for more information.

Log: '.$path_to_log.'


'; exit(); } protected function createCourseCode($title) { //Making sure that text of the short name does not go over the DB limit. //and leaving the space to add additional characters by the platform $code = substr(strtoupper(str_replace(' ', '', trim($title))), 0, 94); return $code; } }