1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
|
<?php // $Id: deploy.php,v 1.11.2.1 2006/08/10 15:34:32 skodak Exp $
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.com //
// //
// Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
// (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
/***
* This page will deploy an IMS Content Package zip file,
* building all the structures and auxiliary files to
* work inside a Moodle resource.
*/
/// Required stuff
require_once('../../../../config.php');
require_once('../../lib.php');
require_once('resource.class.php');
require_once('../../../../backup/lib.php');
require_once('../../../../lib/filelib.php');
require_once('../../../../lib/xmlize.php');
/// Load request parameters
$courseid = required_param ('courseid', PARAM_INT);
$cmid = required_param ('cmid', PARAM_INT);
$file = required_param ('file', PARAM_PATH);
$inpopup = optional_param ('inpopup', 0, PARAM_BOOL);
/// Fetch some records from DB
$course = get_record ('course', 'id', $courseid);
$cm = get_coursemodule_from_id('resource', $cmid);
$resource = get_record ('resource', 'id', $cm->instance);
/// Get some needed strings
$strdeploy = get_string('deploy','resource');
/// Instantiate a resource_ims object and modify its navigation
$resource_obj = new resource_ims ($cmid);
if ($resource_obj->course->category) {
$resource_obj->navigation = "<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/course/view.php?id={$course->id}\">{$course->shortname}</a> -> ".
"<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/mod/resource/index.php?id={$course->id}\">$resource_obj->strresources</a> -> ";
} else {
$resource_obj->navigation = "<a target=\"{$CFG->framename}\" href=\"$CFG->wwwroot/mod/resource/index.php?id={$course->id}\">$resource_obj->strresources</a> -> ";
}
/// Print the header of the page
$pagetitle = strip_tags($course->shortname.': '.
format_string($resource->name)).': '.
$strdeploy;
if ($inpopup) {
print_header($pagetitle, $course->fullname);
} else {
print_header($pagetitle, $course->fullname,
$resource_obj->navigation.format_string($resource->name).' -> '.$strdeploy,
'', '', true,
update_module_button($cm->id, $course->id, $resource_obj->strresource));
}
/// Security Constraints (sesskey and isteacheredit)
if (!confirm_sesskey()) {
error(get_string('confirmsesskeybad', 'error'));
} else if (!isteacheredit($courseid)) {
error(get_string('onlyeditingteachers', 'error'));
}
///
/// Main process, where everything is deployed
///
/// Set some variables
/// Create directories
if (!$resourcedir = make_upload_directory($courseid.'/'.$CFG->moddata.'/resource/'.$resource->id)) {
error (get_string('errorcreatingdirectory', 'error', $CFG->moddata.'/resource/'.$resource->id));
}
/// Ensure it's empty
if (!delete_dir_contents($resourcedir)) {
error (get_string('errorcleaningdirectory', 'error', $resourcedir));
}
/// Copy files
$origin = $CFG->dataroot.'/'.$courseid.'/'.$file;
if (!is_file($origin)) {
error (get_string('filenotfound' , 'error', $file));
}
$mimetype = mimeinfo("type", $file);
if ($mimetype != "application/zip") {
error (get_string('invalidfiletype', 'error', $file));
}
$resourcefile = $resourcedir.'/'.basename($origin);
if (!backup_copy_file($origin, $resourcefile)) {
error (get_string('errorcopyingfiles', 'error'));
}
/// Unzip files
if (!unzip_file($resourcefile, '', false)) {
error (get_string('errorunzippingfiles', 'error'));
}
/// Check for imsmanifest
if (!file_exists($resourcedir.'/imsmanifest.xml')) {
error (get_string('filenotfound', 'error', 'imsmanifest.xml'));
}
/// Load imsmanifest to memory (instead of using a full parser,
/// we are going to use xmlize intensively (because files aren't too big)
if (!$imsmanifest = ims_file2var ($resourcedir.'/imsmanifest.xml')) {
error (get_string ('errorreadingfile', 'error', 'imsmanifest.xml'));
}
/// Check if the first line is a proper one, because I've seen some
/// packages with some control characters at the beginning.
$inixml = strpos($imsmanifest, '<?xml ');
if ($inixml !== false) {
if ($inixml !== 0) {
//Strip strange chars before "<?xml "
$imsmanifest = substr($imsmanifest, $inixml);
}
} else {
error (get_string ('invalidxmlfile', 'error', 'imsmanifest.xml'));
}
/// xmlize the variable
$data = xmlize($imsmanifest, 0);
/// Extract every manifest present in the imsmanifest file.
/// Returns a tree structure.
if (!$manifests = ims_extract_manifests($data)) {
error (get_string('nonmeaningfulcontent', 'error'));
}
/// Process every manifest found in inverse order so every one
/// will be able to use its own submanifests. Not perfect because
/// teorically this will allow some manifests to use other non-childs
/// but this is supposed to be
/// Detect if all the manifest share a common xml:base tag
$manifest_base = $data['manifest']['@']['xml:base'];
/// Parse XML-metadata
/// Skip this for now (until a proper METADATA container was created in Moodle).
/// Parse XML-content package data
/// First we select an organization an load all the items
if (!$items = ims_process_organizations($data['manifest']['#']['organizations']['0'])) {
error (get_string('nonmeaningfulcontent', 'error'));
}
/// Detect if all the resources share a common xml:base tag
$resources_base = $data['manifest']['#']['resources']['0']['@']['xml:base'];
/// Now, we load all the resources available (keys are identifiers)
if (!$resources = ims_load_resources($data['manifest']['#']['resources']['0']['#']['resource'], $manifest_base, $resources_base)) {
error (get_string('nonmeaningfulcontent', 'error'));
}
///Now we assign to each item, its resource (by identifier)
foreach ($items as $key=>$item) {
if (!empty($resources[$item->identifierref])) {
$items[$key]->href = $resources[$item->identifierref];
} else {
$items[$key]->href = '';
}
}
/// Create the INDEX (moodle_inx.ser - where the order of the pages are stored serialized) file
if (!ims_save_serialized_file($resourcedir.'/moodle_inx.ser', $items)) {
error (get_string('errorcreatingfile', 'error', 'moodle_inx.ser'));
}
/// Create the HASH file (moodle_hash.ser - where the hash of the ims is stored serialized) file
$hash = $resource_obj->calculatefilehash($resourcefile);
if (!ims_save_serialized_file($resourcedir.'/moodle_hash.ser', $hash)) {
error (get_string('errorcreatingfile', 'error', 'moodle_hash.ser'));
}
/// End button (go to view mode)
echo '<center>';
print_simple_box(get_string('imspackageloaded', 'resource'), 'center');
$link = $CFG->wwwroot.'/mod/resource/view.php';
$options['r'] = $resource->id;
$label = get_string('viewims', 'resource');
$method = 'post';
print_single_button($link, $options, $label, $method);
echo '</center>';
///
/// End of main process, where everything is deployed
///
/// Print the footer of the page
print_footer();
///
/// Common and useful functions used by the body of the script
///
/*** This function will return a tree of manifests (xmlized) as they are
* found and extracted from one manifest file. The first manifest in the
* will be the main one, while the rest will be submanifests. In the
* future (when IMS CP suppors it, external submanifest will be detected
* and retrieved here too). See IMS specs for more info.
*/
function ims_extract_manifests($data) {
$manifest = new stdClass; //To store found manifests in a tree structure
/// If there are some manifests
if (!empty($data['manifest'])) {
/// Add manifest to results array
$manifest->data = $data['manifest'];
/// Look for submanifests
$submanifests = ims_extract_submanifests($data['manifest']['#']);
/// Add them as child
if (!empty($submanifests)) {
$manifest->childs = $submanifests;
}
}
/// Return tree of manifests found
return $manifest;
}
/* This function will search recursively for submanifests returning an array
* containing them (xmlized) following a tree structure.
*/
function ims_extract_submanifests($data) {
$submanifests = array(); //To store found submanifests
/// If there are some manifests
if (!empty($data['manifest'])) {
/// Get them
foreach ($data['manifest'] as $submanifest) {
/// Create a new submanifest object
$submanifest_object = new stdClass;
$submanifest_object->data = $submanifest;
/// Look for more submanifests recursively
$moresubmanifests = ims_extract_submanifests($submanifest['#']);
/// Add them to results array
if (!empty($moresubmanifests)) {
$submanifest_object->childs = moresubmanifests;
}
/// Add submanifest object to results array
$submanifests[] = $submanifest_object;
}
}
/// Return array of manifests found
return $submanifests;
}
/*** This function will return an ordered and nested array of items
* that is a perfect representation of the prefered organization
*/
function ims_process_organizations($data) {
global $CFG;
/// Get the default organization
$default_organization = $data['@']['default'];
if ($CFG->debug > 7) print_object('default_organization: '.$default_organization);
/// Iterate (reverse) over organizations until we find the default one
if (empty($data['#']['organization'])) { /// Verify <organization> exists
return false;
}
$count_organizations = count($data['#']['organization']);
if ($CFG->debug > 7) print_object('count_organizations: '.$count_organizations);
$current_organization = $count_organizations - 1;
while ($current_organization >= 0) {
/// Load organization and check it
$organization = $data['#']['organization'][$current_organization];
if ($organization['@']['identifier'] == $default_organization) {
$current_organization = -1; //Match, so exit.
}
$current_organization--;
}
/// At this point we MUST have the final organization
if ($CFG->debug > 7) print_object('final organization: '.$organization['#']['title'][0]['#']);
if (empty($organization)) {
return false; //Error, no organization found
}
/// Extract items map from organization
$items = $organization['#']['item'];
if (empty($organization['#']['item'])) { /// Verify <item> exists
return false;
}
if (!$itemmap = ims_process_items($items)) {
return false; //Error, no items found
}
return $itemmap;
}
/*** This function gets the xmlized representation of the items
* and returns an array of items, ordered, with level and info
*/
function ims_process_items($items, $level = 1, $id = 1, $parent = 0) {
global $CFG;
$itemmap = array();
/// Iterate over items from start to end
$count_items = count($items);
if ($CFG->debug > 7) print_object('level '.$level.'-count_items: '.$count_items);
$current_item = 0;
while ($current_item < $count_items) {
/// Load item
$item = $items[$current_item];
$obj_item = new stdClass;
$obj_item->title = $item['#']['title'][0]['#'];
$obj_item->identifier = $item['@']['identifier'];
$obj_item->identifierref = $item['@']['identifierref'];
$obj_item->id = $id;
$obj_item->level = $level;
$obj_item->parent = $parent;
/// Only if the item has everything
if (!empty($obj_item->title) &&
!empty($obj_item->identifier)) {
/// Add to itemmap
$itemmap[$id] = $obj_item;
if ($CFG->debug > 7) print_object('level '.$level.'-id '.$id.'-parent '.$parent.'-'.$obj_item->title);
/// Counters go up
$id++;
/// Check for subitems recursively
$subitems = $item['#']['item'];
if (count($subitems)) {
/// Recursive call
$subitemmap = ims_process_items($subitems, $level+1, $id, $obj_item->id);
/// Add at the end and counters if necessary
if ($count_subitems = count($subitemmap)) {
foreach ($subitemmap as $subitem) {
/// Add the subitem to the main items array
$itemmap[$subitem->id] = $subitem;
/// Counters go up
$id++;
}
}
}
}
$current_item++;
}
return $itemmap;
}
/*** This function will load an array of resources to be used later.
* Keys are identifiers
*/
function ims_load_resources($data, $manifest_base, $resources_base) {
global $CFG;
$resources = array();
if (empty($data)) { /// Verify <resource> exists
return false;
}
$count_resources = count($data);
if ($CFG->debug > 7) print_object('count_resources: '.$count_resources);
$current_resource = 0;
while ($current_resource < $count_resources) {
/// Load resource
$resource = $data[$current_resource];
/// Create a new object resource
$obj_resource = new stdClass;
$obj_resource->identifier = $resource['@']['identifier'];
$obj_resource->resource_base = $resource['@']['xml:base'];
$obj_resource->href = $resource['@']['href'];
if (empty($obj_resource->href)) {
$obj_resource->href = $resource['#']['file']['0']['@']['href'];
}
/// Some packages are poorly done and use \ in roots. This makes them
/// not display since the URLs are not valid.
if (!empty($obj_resource->href)) {
$obj_resource->href = strtr($obj_resource->href, "\\", '/');
}
/// Only if the resource has everything
if (!empty($obj_resource->identifier) &&
!empty($obj_resource->href)) {
/// Add to resources (identifier as key)
/// Depending of $manifest_base, $resources_base and the particular
/// $resource_base variable, concatenate them to build the correct href
$href_base = '';
if (!empty($manifest_base)) {
$href_base = $manifest_base;
}
if (!empty($resources_base)) {
$href_base .= $resources_base;
}
if (!empty($obj_resource->resource_base)) {
$href_base .= $obj_resource->resource_base;
}
$resources[$obj_resource->identifier] = $href_base.$obj_resource->href;
}
/// Counters go up
$current_resource++;
}
return $resources;
}
?>
|