~ubuntu-branches/ubuntu/dapper/moodle/dapper-backports

« back to all changes in this revision

Viewing changes to mod/resource/type/ims/repository_deploy.php

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2006-12-01 14:00:21 UTC
  • mfrom: (6.1.5 feisty)
  • Revision ID: james.westby@ubuntu.com-20061201140021-rivugg5tgx6mujzg
Tags: 1.6.3-1ubuntu1~dapper1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

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