dokeos-learnpath-aicc
[ class tree: dokeos-learnpath-aicc ] [ index: dokeos-learnpath-aicc ] [ all elements ]

Source for file aicc.class.php

Documentation is available at aicc.class.php

  1. <?php //$id:$
  2. /**
  3.  * Defines the AICC class, which is meant to contain the aicc items (nuclear elements)
  4.  * @package dokeos.learnpath.aicc
  5.  * @author    Yannick Warnier <ywarnier@beeznest.org>
  6.  * @license    GNU/GPL - See Dokeos license directory for details
  7.  */
  8. /**
  9.  * Defines the "aicc" child of class "learnpath"
  10.  * @package dokeos.learnpath.aicc
  11.  */
  12. require_once('aiccItem.class.php');
  13. //require_once('aiccMetadata.class.php');
  14. //require_once('aiccOrganization.class.php');
  15. require_once('aiccResource.class.php');
  16. require_once('aiccBlock.class.php');
  17. class aicc extends learnpath {
  18.  
  19.     var $config = array();
  20.     var $config_basename = '';  //the configuration files might be multiple and might have
  21.                                 //funny names. We need to keep the name of that file while we
  22.                                 //install the content.
  23.     var $config_files = array();
  24.     var $config_exts = array(
  25.             'crs'=>0//Course description file (mandatory)
  26.             'au' =>0//Assignable Unit file (mandatory)
  27.             'des'=>0//Descriptor file (mandatory)
  28.             'cst'=>0//Course structure file (mandatory)
  29.             'ore'=>0//Objectives relationshops file (optional)
  30.             'pre'=>0//Prerequisites file (optional)
  31.             'cmp'=>0  //Completion Requirements file (optional)
  32.     );
  33.     var $aulist = array();
  34.     var $au_order_list = array();
  35.     var $au_order_list_new_id = array();
  36.     var $deslist = array();
  37.     var $cstlist = array();
  38.     var $orelist = array();
  39.     
  40.     var $subdir = ''//path between the scorm/ directory and the config files e.g. maritime_nav/maritime_nav. This is the path that will be used in the lp_path when importing a package
  41.     var $zipname = ''//keeps the zipfile safe for the object's life so that we can use it if no title avail
  42.     var $lastzipnameindex = 0//keeps an index of the number of uses of the zipname so far
  43.     var $config_encoding = 'ISO-8859-1';
  44.     var $debug = 0;
  45.     /**
  46.      * Class constructor. Based on the parent constructor.
  47.      * @param    string    Course code
  48.      * @param    integer    Learnpath ID in DB
  49.      * @param    integer    User ID
  50.      */
  51.     function aicc($course_code=null,$resource_id=null,$user_id=null{
  52.         if($this->debug>0){error_log('In aicc::aicc()',0);}
  53.         if(!empty($course_codeand !empty($resource_idand !empty($user_id))
  54.         {
  55.             parent::learnpath($course_code$resource_id$user_id);
  56.         }else{
  57.             //do nothing but still build the aicc object
  58.         }
  59.     }
  60.     /**
  61.      * Opens a resource
  62.      * @param    integer    Database ID of the resource
  63.      */
  64.     function open($id)
  65.     {
  66.         if($this->debug>0){error_log('In aicc::open()',0);}
  67.         // redefine parent method
  68.     }
  69.     /**
  70.      * Parses a set of AICC config files and puts everything into the $config array
  71.      * @param    string    Path to the config files dir on the system. If not defined, uses the base path of the course's scorm dir
  72.      * @return    array    Structured array representing the config files' contents
  73.      */
  74.      function parse_config_files($dir='')
  75.      {
  76.         if($this->debug>0){error_log('New LP - In aicc::parse_config_files('.$dir.')',0);}
  77.         if(empty($dir)){
  78.              //get the path of the AICC config files dir
  79.             $dir $this->subdir;
  80.          }
  81.          if(is_dir($dirand is_readable($dir))
  82.          {
  83.              // Now go through all the config files one by one and parse everything into
  84.              // AICC objects.
  85.              
  86.              // The basename for the config files is stored in $this->config_basename
  87.  
  88.              // Parse the Course Description File (.crs) - ini-type
  89.              $crs_file $dir.'/'.$this->config_files['crs'];
  90.              $crs_params $this->parse_ini_file_quotes_safe($crs_file);
  91.              //echo '<pre>crs:'.print_r($crs_params,true).'</pre>';
  92.             if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$crs_file.' has been parsed',0);}
  93.             
  94.             //CRS distribute crs params into the aicc object
  95.             if(!empty($crs_params['course']['course_creator'])){
  96.                 $this->course_creator mysql_real_escape_string($crs_params['course']['course_creator']);
  97.             }
  98.             if(!empty($crs_params['course']['course_id'])){
  99.                 $this->course_id mysql_real_escape_string($crs_params['course']['course_id']);
  100.             }
  101.             if(!empty($crs_params['course']['course_system'])){
  102.                 $this->course_system $crs_params['course']['course_system'];
  103.             }
  104.             if(!empty($crs_params['course']['course_title'])){
  105.                 $this->course_title mysql_real_escape_string($crs_params['course']['course_title']);
  106.             }
  107.             if(!empty($crs_params['course']['course_level'])){
  108.                 $this->course_level $crs_params['course']['course_level'];
  109.             }
  110.             if(!empty($crs_params['course']['max_fields_cst'])){
  111.                 $this->course_max_fields_cst $crs_params['course']['max_fields_cst'];
  112.             }
  113.             if(!empty($crs_params['course']['max_fields_ort'])){
  114.                 $this->course_max_fields_ort $crs_params['course']['max_fields_ort'];
  115.             }
  116.             if(!empty($crs_params['course']['total_aus'])){
  117.                 $this->course_total_aus $crs_params['course']['total_aus'];
  118.             }
  119.             if(!empty($crs_params['course']['total_blocks'])){
  120.                 $this->course_total_blocks $crs_params['course']['total_blocks'];
  121.             }
  122.             if(!empty($crs_params['course']['total_objectives'])){
  123.                 $this->course_total_objectives $crs_params['course']['total_objectives'];
  124.             }
  125.             if(!empty($crs_params['course']['total_complex_objectives'])){
  126.                 $this->course_total_complex_objectives $crs_params['course']['total_complex_objectives'];
  127.             }
  128.             if(!empty($crs_params['course']['version'])){
  129.                 $this->course_version $crs_params['course']['version'];
  130.             }
  131.             if(!empty($crs_params['course_description'])){
  132.                 $this->course_description mysql_real_escape_string($crs_params['course_description']);
  133.             }
  134.              
  135.              // Parse the Descriptor File (.des) - csv-type
  136.              $des_file $dir.'/'.$this->config_files['des'];
  137.             $des_params $this->parse_csv_file($des_file);
  138.              //echo '<pre>des:'.print_r($des_params,true).'</pre>';
  139.             if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$des_file.' has been parsed',0);}
  140.             //distribute des params into the aicc object
  141.             foreach($des_params as $des){
  142.                 //one AU in AICC is equivalent to one SCO in SCORM (scormItem class)
  143.                 $oDes new aiccResource('config',$des);
  144.                 $this->deslist[$oDes->identifier$oDes;                
  145.             }
  146.             
  147.              // Parse the Assignable Unit File (.au) - csv-type
  148.              $au_file $dir.'/'.$this->config_files['au'];
  149.              $au_params $this->parse_csv_file($au_file);
  150.              //echo '<pre>au:'.print_r($au_params,true).'</pre>';
  151.             if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$au_file.' has been parsed',0);}
  152.             //distribute au params into the aicc object
  153.             foreach($au_params as $au){
  154.                 $oAu new aiccItem('config',$au);
  155.                 $this->aulist[$oAu->identifier$oAu;
  156.                 $this->au_order_list[$oAu->identifier;
  157.             }
  158.          
  159.              // Parse the Course Structure File (.cst) - csv-type
  160.              $cst_file $dir.'/'.$this->config_files['cst'];
  161.              $cst_params $this->parse_csv_file($cst_file,',','"',true);
  162.              //echo '<pre>cst:'.print_r($cst_params,true).'</pre>';
  163.             if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$cst_file.' has been parsed',0);}
  164.             //distribute cst params into the aicc object
  165.             foreach($cst_params as $cst){
  166.                 $oCst new aiccBlock('config',$cst);
  167.                 $this->cstlist[$oCst->identifier$oCst;
  168.             }
  169.             
  170.              // Parse the Objectives Relationships File (.ore) - csv-type - if exists
  171.              //TODO @TODO implement these objectives. For now they're just parsed
  172.              if(!empty($this->config_files['ore'])){
  173.                  $ore_file $dir.'/'.$this->config_files['ore'];
  174.                  $ore_params $this->parse_csv_file($ore_file,',','"',true);
  175.                  //echo '<pre>ore:'.print_r($ore_params,true).'</pre>';
  176.                 if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$ore_file.' has been parsed',0);}
  177.                 //distribute ore params into the aicc object
  178.                 foreach($ore_params as $ore){
  179.                     $oOre new aiccObjective('config',$ore);
  180.                     $this->orelist[$oOre->identifier$oOre;
  181.                 }
  182.              }
  183.  
  184.              // Parse the Prerequisites File (.pre) - csv-type - if exists
  185.              if(!empty($this->config_files['pre'])){
  186.                  $pre_file $dir.'/'.$this->config_files['pre'];
  187.                  $pre_params $this->parse_csv_file($pre_file);
  188.                  //echo '<pre>pre:'.print_r($pre_params,true).'</pre>';
  189.                 if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$pre_file.' has been parsed',0);}
  190.                 //distribute pre params into the aicc object
  191.                 foreach($pre_params as $pre){
  192.                     //place a constraint on the corresponding block or AU
  193.                     if(in_array(strtolower($pre['structure_element']),array_keys($this->cstlist))){
  194.                         //if this references a block element
  195.                         $this->cstlist[strtolower($pre['structure_element'])]->prereq_string strtolower($pre['prerequisite']);
  196.                     }
  197.                     if(in_array(strtolower($pre['structure_element']),array_keys($this->aulist))){
  198.                         //if this references a block element
  199.                         $this->aulist[strtolower($pre['structure_element'])]->prereq_string strtolower($pre['prerequisite']);
  200.                     }
  201.                 }
  202.              }         
  203.  
  204.              // Parse the Completion Requirements File (.cmp) - csv-type - if exists
  205.              //TODO @TODO implement this set of requirements (needs database changes)
  206.              if(!empty($this->config_files['cmp'])){
  207.                  $cmp_file $dir.'/'.$this->config_files['cmp'];
  208.                  $cmp_params $this->parse_csv_file($cmp_file);
  209.                  //echo '<pre>cmp:'.print_r($cmp_params,true).'</pre>';
  210.                 if($this->debug>1){error_log('New LP - In aicc::parse_config_files() - '.$cmp_file.' has been parsed',0);}
  211.                 //distribute cmp params into the aicc object
  212.                 foreach($cmp_params as $cmp){
  213.                     //$oCmp = new aiccCompletionRequirements('config',$cmp);
  214.                     //$this->cmplist[$oCmp->identifier] =& $oCmp;
  215.                 }
  216.              }         
  217.          }
  218.          return $this->config;
  219.      }
  220.      /**
  221.       * Import the aicc object (as a result from the parse_config_files function) into the database structure
  222.       * @param    string    Unique course code
  223.       * @return    bool    Returns -1 on error
  224.       */
  225.      function import_aicc($course_code){
  226.          if($this->debug>0){error_log('New LP - In aicc::import_aicc('.$course_code.')',0);}
  227.          //get table names
  228.          $new_lp 'lp';
  229.          $new_lp_item 'lp_item';
  230.          
  231.          //The previous method wasn't safe to get the database name, so do it manually with the course_code
  232.          $sql "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)." WHERE code='$course_code'";
  233.         $res api_sql_query($sql,__FILE__,__LINE__);
  234.         if(Database::num_rows($res)<1)error_log('New LP - Database for '.$course_code.' not found '.__FILE__.' '.__LINE__,0);return -1;}
  235.         $row Database::fetch_array($res);
  236.         $dbname Database::get_course_table_prefix().$row['db_name'].Database::get_database_glue();
  237.         
  238.         $new_lp Database::get_course_table('lp');
  239.         $new_lp_item Database::get_course_table('lp_item');
  240.         $get_max "SELECT MAX(display_order) FROM $new_lp";
  241.         $res_max api_sql_query($get_max);
  242.         if(Database::num_rows($res_max)<1){
  243.             $dsp 1;
  244.         }else{
  245.             $row Database::fetch_array($res_max);
  246.             $dsp $row[0]+1;
  247.         }
  248.  
  249.         $this->config_encoding = "ISO-8859-1";
  250.         
  251.         $sql "INSERT INTO $new_lp .
  252.                 "(lp_type, name, ref, description, " .
  253.                 "path, force_commit, default_view_mod, default_encoding, " .
  254.                 "js_lib, content_maker,display_order)" .
  255.                 "VALUES " .
  256.                 "(3,'".$this->course_title."', '".$this->course_id."','".$this->course_description."'," .
  257.                 "'".$this->subdir."', 0, 'embedded', '".$this->config_encoding."'," .
  258.                 "'aicc_api.php','".$this->course_creator."',$dsp)";
  259.         if($this->debug>2){error_log('New LP - In import_aicc(), inserting path: '$sql,0);}
  260.         $res api_sql_query($sql);
  261.         $lp_id Database::get_last_insert_id();
  262.         $this->lp_id = $lp_id;
  263.         api_item_property_update(api_get_course_info($course_code),TOOL_LEARNPATH,$this->lp_id,'LearnpathAdded',api_get_user_id());
  264.         api_item_property_update(api_get_course_info($course_code),TOOL_LEARNPATH,$this->lp_id,'visible',api_get_user_id());
  265.         
  266.         $previous 0;
  267.         foreach($this->aulist as $identifier => $dummy)
  268.         {
  269.             $oAu =$this->aulist[$identifier];
  270.             //echo "Item ".$oAu->identifier;
  271.             $field_add '';
  272.             $value_add '';
  273.             if(!empty($oAu->masteryscore)){
  274.                 $field_add 'mastery_score, ';
  275.                 $value_add $oAu->masteryscore.',';
  276.             }
  277.             $title $oAu->identifier;
  278.             if(is_object($this->deslist[$identifier])){
  279.                 $title $this->deslist[$identifier]->title;
  280.             }
  281.             $path $oAu->path;
  282.             //$max_score = $oAu->max_score //TODO check if special constraint exists for this item
  283.             //$min_score = $oAu->min_score //TODO check if special constraint exists for this item
  284.             $parent 0//TODO deal with parent
  285.             $previous 0;
  286.             $prereq $oAu->prereq_string;
  287.             //$previous = (!empty($this->au_order_list_new_id[x])?$this->au_order_list_new_id[x]:0); //TODO deal with previous
  288.             $sql_item "INSERT INTO $new_lp_item .
  289.                     "(lp_id,item_type,ref,title," .
  290.                     "path,min_score,max_score, $field_add.
  291.                     "parent_item_id,previous_item_id,next_item_id," .
  292.                     "prerequisite,display_order) " .
  293.                     "VALUES " .
  294.                     "($lp_id, 'au','".$oAu->identifier."','".$title."'," .
  295.                     "'$path',0,100, $value_add.
  296.                     "$parent$previous, 0, .
  297.                     "'$prereq', 0.
  298.                     ")";
  299.             $res_item api_sql_query($sql_item);
  300.             if($this->debug>1){error_log('New LP - In aicc::import_aicc() - inserting item : '.$sql_item.' : '.mysql_error(),0);}
  301.             $item_id Database::get_last_insert_id();
  302.             //now update previous item to change next_item_id
  303.             if($previous != 0){
  304.                 $upd "UPDATE $new_lp_item SET next_item_id = $item_id WHERE id = $previous";
  305.                 $upd_res api_sql_query($upd);
  306.                 //update previous item id
  307.             }
  308.             $previous $item_id;
  309.         }
  310.      }
  311.       /**
  312.       * Intermediate to import_package only to allow import from local zip files
  313.       * @param    string    Path to the zip file, from the dokeos sys root
  314.       * @param    string    Current path (optional)
  315.       * @return string    Absolute path to the AICC description files or empty string on error
  316.       */
  317.      function import_local_package($file_path,$current_dir='')
  318.      {
  319.          //todo prepare info as given by the $_FILES[''] vector
  320.          $file_info array();
  321.          $file_info['tmp_name'$file_path;
  322.          $file_info['name'basename($file_path);
  323.          //call the normal import_package function
  324.          return $this->import_package($file_info,$current_dir)
  325.      }
  326.      /**
  327.       * Imports a zip file (presumably AICC) into the Dokeos structure
  328.       * @param    string    Zip file info as given by $_FILES['userFile']
  329.       * @return    string    Absolute path to the AICC config files directory or empty string on error
  330.       */
  331.      function import_package($zip_file_info,$current_dir '')
  332.      {
  333.          if($this->debug>0){error_log('In aicc::import_package('.print_r($zip_file_info,true).',"'.$current_dir.'") method',0);}
  334.          //ini_set('error_log','E_ALL');
  335.          $maxFilledSpace 1000000000;
  336.          $zip_file_path $zip_file_info['tmp_name'];
  337.          $zip_file_name $zip_file_info['name'];
  338.          
  339.          if($this->debug>0){error_log('New LP - aicc::import_package() - Zip file path = '.$zip_file_path.', zip file name = '.$zip_file_name,0);}
  340.          $course_rel_dir  api_get_course_path().'/scorm'//scorm dir web path starting from /courses
  341.         $course_sys_dir api_get_path(SYS_COURSE_PATH).$course_rel_dir//absolute system path for this course
  342.         $current_dir replace_dangerous_char(trim($current_dir),'strict')//current dir we are in, inside scorm/
  343.          if($this->debug>0){error_log('New LP - aicc::import_package() - Current_dir = '.$current_dir,0);}
  344.          
  345.          //$uploaded_filename = $_FILES['userFile']['name'];
  346.         //get name of the zip file without the extension
  347.         if($this->debug>0){error_log('New LP - aicc::import_package() - Received zip file name: '.$zip_file_path,0);}
  348.         $file_info pathinfo($zip_file_name);
  349.         $filename $file_info['basename'];
  350.         $extension $file_info['extension'];
  351.         $file_base_name str_replace('.'.$extension,'',$filename)//filename without its extension
  352.         $this->zipname = $file_base_name//save for later in case we don't have a title
  353.         
  354.         if($this->debug>0){error_log('New LP - aicc::import_package() - Base file name is : '.$file_base_name,0);}
  355.         $new_dir replace_dangerous_char(trim($file_base_name),'strict');
  356.         $this->subdir = $new_dir;
  357.         if($this->debug>0){error_log('New LP - aicc::import_package() - Subdir is first set to : '.$this->subdir,0);}
  358.     
  359. /*        
  360.         if( check_name_exist($course_sys_dir.$current_dir."/".$new_dir) )
  361.         {
  362.             $dialogBox = get_lang('FileExists');
  363.             $stopping_error = true;
  364.         }
  365. */
  366.         $zipFile new pclZip($zip_file_path);
  367.     
  368.         // Check the zip content (real size and file extension)
  369.  
  370.         $zipContentArray $zipFile->listContent();
  371.  
  372.         $package_type=''//the type of the package. Should be 'aicc' after the next few lines
  373.         $package ''//the basename of the config files (if 'courses.crs' => 'courses')
  374.         $at_root false//check if the config files are at zip root
  375.         $config_dir ''//the directory in which the config files are. May remain empty
  376.         $files_found array();
  377.         $subdir_isset false;
  378.         //the following loop should be stopped as soon as we found the right config files (.crs, .au, .des and .cst)
  379.         foreach($zipContentArray as $thisContent)
  380.         {
  381.             if preg_match('~.(php.*|phtml)$~i'$thisContent['filename']) )
  382.             {
  383.                 //if a php file is found, do not authorize (security risk)
  384.                 if($this->debug>1){error_log('New LP - aicc::import_package() - Found unauthorized file: '.$thisContent['filename'],0);}        
  385.                 return api_failure::set_failure('php_file_in_zip_file');
  386.             }elseif(preg_match('?.*/aicc/$?',$thisContent['filename'])){
  387.                 //if a directory named 'aicc' is found, package type = aicc, but continue
  388.                 //because we need to find the right AICC files 
  389.                 if($this->debug>1){error_log('New LP - aicc::import_package() - Found aicc directory: '.$thisContent['filename'],0);}        
  390.                 $package_type 'aicc';
  391.             }else{
  392.                 //else, look for one of the files we're searching for (something.crs case insensitive)
  393.                 $res array();
  394.                 if(preg_match('?^(.*)\.(crs|au|des|cst|ore|pre|cmp)$?i',$thisContent['filename'],$res))
  395.                 {
  396.                     if($this->debug>1){error_log('New LP - aicc::import_package() - Found AICC config file: '.$thisContent['filename'].'. Now splitting: '.$res[1].' and '.$res[2],0);}
  397.                     if($thisContent['filename'== basename($thisContent['filename'])){
  398.                         if($this->debug>2){error_log('New LP - aicc::import_package() - '.$thisContent['filename'].' is at root level',0);}
  399.                         $at_root true;
  400.                         if(!is_array($files_found[$res[1]])){
  401.                             $files_found[$res[1]] $this->config_exts//initialise list of expected extensions (defined in class definition)
  402.                         }
  403.                         $files_found[$res[1]][strtolower($res[2])$thisContent['filename'];
  404.                         $subdir_isset true;
  405.                     }else{
  406.                         if(!$subdir_isset){
  407.                             if(preg_match('?^.*/aicc$?i',dirname($thisContent['filename']))){
  408.                                 //echo "Cutting subdir<br/>";
  409.                                 $this->subdir .= '/'.substr(dirname($thisContent['filename']),0,-5);                            
  410.                             }else{
  411.                                 //echo "Not cutting subdir<br/>";
  412.                                 $this->subdir .= '/'.dirname($thisContent['filename']);
  413.                             }
  414.                             $subdir_isset true;
  415.                         }
  416.                         if($this->debug>2){error_log('New LP - aicc::import_package() - '.$thisContent['filename'].' is not at root level - recording subdir '.$this->subdir,0);}
  417.                         $config_dir dirname($thisContent['filename'])//just the relative directory inside scorm/
  418.                         if(!is_array($files_found[basename($res[1])])){
  419.                             $files_found[basename($res[1])$this->config_exts;
  420.                         }
  421.                         $files_found[basename($res[1])][strtolower($res[2])basename($thisContent['filename']);
  422.                     }
  423.                     $package_type 'aicc';
  424.                 }else{
  425.                     if($this->debug>3){error_log('New LP - aicc::import_package() - File '.$thisContent['filename'].' didnt match any check',0);}        
  426.                 }
  427.             }
  428.             $realFileSize += $thisContent['size'];
  429.         }
  430.         if($this->debug>2){error_log('New LP - aicc::import_package() - $files_found: '.print_r($files_found,true),0);}
  431.         if($this->debug>1){error_log('New LP - aicc::import_package() - Package type is now '.$package_type,0);}
  432.         $mandatory false;
  433.         foreach($files_found as $file_name => $file_exts){
  434.             $temp (
  435.                 !empty($files_found[$file_name]['crs'])
  436.                 AND !empty($files_found[$file_name]['au']
  437.                 AND !empty($files_found[$file_name]['des'])
  438.                 AND !empty($files_found[$file_name]['cst'])
  439.             );
  440.             if($temp){
  441.                 if($this->debug>1){error_log('New LP - aicc::import_package() - Found all config files for '.$file_name,0);}
  442.                 $mandatory true;
  443.                 $package $file_name;
  444.                 //store base config file name for reuse in parse_config_files()
  445.                 $this->config_basename = $file_name;
  446.                 //store filenames for reuse in parse_config_files()
  447.                 $this->config_files = $files_found[$file_name];
  448.                 //get out, we only want one config files set
  449.                 break;
  450.             }
  451.         }
  452.         
  453.         if($package_type== '' OR $mandatory!=true)
  454.          // && defined('CHECK_FOR_AICC') && CHECK_FOR_AICC)
  455.         {
  456.             return api_failure::set_failure('not_aicc_content');
  457.         }
  458.     
  459.         if (enough_size($realFileSize$course_sys_dir$maxFilledSpace) )
  460.         {
  461.             return api_failure::set_failure('not_enough_space');
  462.         }
  463.     
  464.         // it happens on Linux that $new_dir sometimes doesn't start with '/'
  465.         if($new_dir[0!= '/')
  466.         {
  467.             $new_dir='/'.$new_dir;
  468.         }
  469.         //cut trailing slash
  470.         if($new_dir[strlen($new_dir)-1== '/')
  471.         {
  472.             $new_dir=substr($new_dir,0,-1);
  473.         }
  474.     
  475.         /*
  476.         --------------------------------------
  477.             Uncompressing phase
  478.         --------------------------------------
  479.         */
  480.         /*
  481.             We need to process each individual file in the zip archive to
  482.             - add it to the database
  483.             - parse & change relative html links
  484.             - make sure the filenames are secure (filter funny characters or php extensions)
  485.         */
  486.         if(is_dir($course_sys_dir.$new_dirOR @mkdir($course_sys_dir.$new_dir))
  487.         {
  488.             // PHP method - slower...
  489.             if($this->debug>=1){error_log('New LP - Changing dir to '.$course_sys_dir.$new_dir,0);}
  490.             $saved_dir getcwd();
  491.             chdir($course_sys_dir.$new_dir);
  492.             $unzippingState $zipFile->extract();
  493.             for($j=0;$j<count($unzippingState);$j++)
  494.             {
  495.                 $state=$unzippingState[$j];
  496.     
  497.                 //TODO fix relative links in html files (?)
  498.                 $extension strrchr($state["stored_filename"]".");
  499.                 //if($this->debug>1){error_log('New LP - found extension '.$extension.' in '.$state['stored_filename'],0);}
  500.                 
  501.             }
  502.     
  503.             if(!empty($new_dir))
  504.             {
  505.                 $new_dir $new_dir.'/';
  506.             }
  507.             //rename files, for example with \\ in it
  508.             if($dir=@opendir($course_sys_dir.$new_dir))
  509.             {
  510.                 if($this->debug==1){error_log('New LP - Opened dir '.$course_sys_dir.$new_dir,0);}
  511.                 while($file=readdir($dir))
  512.                 {
  513.                     if($file != '.' && $file != '..')
  514.                     {
  515.                         $filetype="file";
  516.     
  517.                         if(is_dir($course_sys_dir.$new_dir.$file)) $filetype="folder";
  518.                         
  519.                         //TODO RENAMING FILES CAN BE VERY DANGEROUS AICC-WISE, avoid that as much as possible!
  520.                         //$safe_file=replace_dangerous_char($file,'strict');
  521.                         $find_str array('\\','.php','.phtml');
  522.                         $repl_str array('/''.txt','.txt');
  523.                         $safe_file str_replace($find_str,$repl_str,$file);
  524.     
  525.                         if($safe_file != $file){
  526.                             //@rename($course_sys_dir.$new_dir,$course_sys_dir.'/'.$safe_file);
  527.                             $mydir dirname($course_sys_dir.$new_dir.$safe_file);
  528.                             if(!is_dir($mydir)){
  529.                                 $mysubdirs split('/',$mydir);
  530.                                 $mybasedir '/';
  531.                                 foreach($mysubdirs as $mysubdir){
  532.                                     if(!empty($mysubdir)){
  533.                                         $mybasedir $mybasedir.$mysubdir.'/';
  534.                                         if(!is_dir($mybasedir)){
  535.                                             @mkdir($mybasedir);
  536.                                             if($this->debug==1){error_log('New LP - Dir '.$mybasedir.' doesnt exist. Creating.',0);}
  537.                                         }
  538.                                     }
  539.                                 }
  540.                             }
  541.                             @rename($course_sys_dir.$new_dir.$file,$course_sys_dir.$new_dir.$safe_file);
  542.                             if($this->debug==1){error_log('New LP - Renaming '.$course_sys_dir.$new_dir.$file.' to '.$course_sys_dir.$new_dir.$safe_file,0);}
  543.                         }    
  544.                         //set_default_settings($course_sys_dir,$safe_file,$filetype);
  545.                     }
  546.                 }
  547.     
  548.                 closedir($dir);
  549.                 chdir($saved_dir);
  550.             }
  551.         }else{
  552.             return '';
  553.         }
  554.         return $course_sys_dir.$new_dir.$config_dir;
  555.     }
  556.     /**
  557.      * Sets the proximity setting in the database
  558.      * @param    string    Proximity setting
  559.      */
  560.      function set_proximity($proxy=''){
  561.         if($this->debug>0){error_log('In aicc::set_proximity('.$proxy.') method',0);}
  562.          $lp $this->get_id();
  563.          if($lp!=0){
  564.              $tbl_lp Database::get_course_table('lp');
  565.              $sql "UPDATE $tbl_lp SET content_local = '$proxy' WHERE id = ".$lp;
  566.              $res api_sql_query($sql);
  567.              return $res;
  568.          }else{
  569.              return false;
  570.          }
  571.      }
  572.      
  573.      /**
  574.      * Sets the theme setting in the database
  575.      * @param    string    Theme setting
  576.      */
  577.      function set_theme($theme=''){
  578.         if($this->debug>0){error_log('In aicc::set_theme('.$theme.') method',0);}
  579.          $lp $this->get_id();
  580.          if($lp!=0){
  581.              $tbl_lp Database::get_course_table('lp');
  582.              $sql "UPDATE $tbl_lp SET theme = '$theme' WHERE id = ".$lp;
  583.              $res api_sql_query($sql);
  584.              return $res;
  585.          }else{
  586.              return false;
  587.          }
  588.      }
  589.      
  590.     /**
  591.      * Sets the content maker setting in the database
  592.      * @param    string    Proximity setting
  593.      */
  594.      function set_maker($maker=''){
  595.         if($this->debug>0){error_log('In aicc::set_maker method('.$maker.')',0);}
  596.          $lp $this->get_id();
  597.          if($lp!=0){
  598.              $tbl_lp Database::get_course_table('lp');
  599.              $sql "UPDATE $tbl_lp SET content_maker = '$maker' WHERE id = ".$lp;
  600.              $res api_sql_query($sql);
  601.              return $res;
  602.          }else{
  603.              return false;
  604.          }
  605.      }
  606.      /**
  607.       * Exports the current AICC object's files as a zip. Excerpts taken from learnpath_functions.inc.php::exportpath()
  608.       * @param    integer    Learnpath ID (optional, taken from object context if not defined)
  609.       */
  610.       function export_zip($lp_id=null){
  611.         if($this->debug>0){error_log('In aicc::export_zip method('.$lp_id.')',0);}
  612.          if(empty($lp_id)){
  613.             if(!is_object($this))
  614.             {
  615.                 return false;
  616.             }
  617.             else{
  618.                 $id $this->get_id();
  619.                 if(empty($id)){
  620.                     return false;
  621.                 }
  622.                  else{
  623.                      $lp_id $this->get_id();
  624.                  }
  625.             }
  626.          }
  627.          //error_log('New LP - in export_zip()',0);
  628.          //zip everything that is in the corresponding scorm dir
  629.          //write the zip file somewhere (might be too big to return)
  630.         require_once (api_get_path(LIBRARY_PATH)."fileUpload.lib.php");
  631.         require_once (api_get_path(LIBRARY_PATH)."fileManage.lib.php");
  632.         require_once (api_get_path(LIBRARY_PATH)."document.lib.php");
  633.         require_once (api_get_path(LIBRARY_PATH)."pclzip/pclzip.lib.php");
  634.         require_once ("learnpath_functions.inc.php");
  635.         $tbl_lp Database::get_course_table('lp');
  636.         $_course Database::get_course_info(api_get_course_id());
  637.  
  638.         $sql "SELECT * FROM $tbl_lp WHERE id=".$lp_id;
  639.         $result api_sql_query($sql__FILE____LINE__);
  640.         $row mysql_fetch_array($result);
  641.         $LPname $row['path'];
  642.         $list split('/',$LPname);
  643.         $LPnamesafe $list[0];
  644.         //$zipfoldername = '/tmp';
  645.         //$zipfoldername = '../../courses/'.$_course['directory']."/temp/".$LPnamesafe;
  646.         $zipfoldername api_get_path('SYS_COURSE_PATH').$_course['directory']."/temp/".$LPnamesafe;
  647.         $scormfoldername api_get_path('SYS_COURSE_PATH').$_course['directory']."/scorm/".$LPnamesafe;
  648.         $zipfilename $zipfoldername."/".$LPnamesafe.".zip";
  649.     
  650.         //Get a temporary dir for creating the zip file    
  651.         
  652.         //error_log('New LP - cleaning dir '.$zipfoldername,0);
  653.         deldir($zipfoldername)//make sure the temp dir is cleared
  654.         $res mkdir($zipfoldername);
  655.         //error_log('New LP - made dir '.$zipfoldername,0);
  656.         
  657.         //create zipfile of given directory
  658.         $zip_folder new PclZip($zipfilename);
  659.         $zip_folder->create($scormfoldername.'/'PCLZIP_OPT_REMOVE_PATH$scormfoldername.'/');
  660.         
  661.         //$zipfilename = '/var/www/dokeos-comp/courses/TEST2/scorm/example_document.html';
  662.         //this file sending implies removing the default mime-type from php.ini
  663.         //DocumentManager :: file_send_for_download($zipfilename, true, $LPnamesafe.".zip");
  664.         DocumentManager :: file_send_for_download($zipfilenametrue);
  665.  
  666.         // Delete the temporary zip file and directory in fileManage.lib.php
  667.         my_delete($zipfilename);
  668.         my_delete($zipfoldername);
  669.     
  670.         return true;
  671.     }
  672.     /**
  673.       * Gets a resource's path if available, otherwise return empty string
  674.       * @param    string    Resource ID as used in resource array
  675.       * @return string    The resource's path as declared in config file course.crs
  676.       */
  677.       function get_res_path($id){
  678.         if($this->debug>0){error_log('In aicc::get_res_path('.$id.') method',0);}
  679.           $path '';
  680.           if(isset($this->resources[$id])){
  681.             $oRes =$this->resources[$id];
  682.             $path @$oRes->get_path();
  683.         }
  684.         return $path;
  685.       }
  686.      /**
  687.       * Gets a resource's type if available, otherwise return empty string
  688.       * @param    string    Resource ID as used in resource array
  689.       * @return string    The resource's type as declared in the assignable unit (.au) file
  690.       */
  691.       function get_res_type($id){
  692.         if($this->debug>0){error_log('In aicc::get_res_type('.$id.') method',0);}
  693.           $type '';
  694.         if(isset($this->resources[$id])){
  695.             $oRes =$this->resources[$id];
  696.             $temptype $oRes->get_scorm_type();
  697.             if(!empty($temptype)){
  698.                 $type $temptype;
  699.             }
  700.         }
  701.         return $type;
  702.       }
  703.       /**
  704.        * Gets the default organisation's title
  705.        * @return    string    The organization's title
  706.        */
  707.       function get_title(){
  708.         if($this->debug>0){error_log('In aicc::get_title() method',0);}
  709.           $title '';
  710.           if(isset($this->config['organizations']['default'])){
  711.               $title $this->organizations[$this->config['organizations']['default']]->get_name();
  712.           }elseif(count($this->organizations)==1){
  713.               //this will only get one title but so we don't need to know the index
  714.               foreach($this->organizations as $id => $value){
  715.                   $title $this->organizations[$id]->get_name();
  716.                   break;
  717.               }
  718.           }
  719.           return $title;
  720.       }
  721.       /**
  722.        * //TODO @TODO implement this function to restore items data from a set of AICC config files,
  723.        * updating the existing table... This will prove very useful in case initial data
  724.        * from config files were not imported well enough
  725.        */
  726.       function reimport_aicc(){
  727.         if($this->debug>0){error_log('In aicc::reimport_aicc() method',0);}
  728.           //query current items list
  729.           //get the identifiers
  730.           //parse the config files
  731.           //match both
  732.           //update DB accordingly
  733.           return true;
  734.       }
  735.       /**
  736.        * Static function to parse AICC ini files.
  737.        * Based on work by sinedeo at gmail dot com published on php.net (parse_ini_file())
  738.        * @param    string    File path
  739.        * @return    array    Structured array
  740.        */
  741.         function parse_ini_file_quotes_safe($f)
  742.         {
  743.             $null "";
  744.             $r=$null;
  745.             $sec=$null;
  746.             $f=@file($f);
  747.             for ($i=0;$i<@count($f);$i++)
  748.             {
  749.                 $newsec=0;
  750.                 $w=@trim($f[$i]);
  751.                 if ($w)
  752.                 {
  753.                     if ((!$ror ($sec))
  754.                     {
  755.                         if ((@substr($w,0,1)=="["and (@substr($w,-1,1))=="]"
  756.                         {
  757.                             $sec=@substr($w,1,@strlen($w)-2);
  758.                             $newsec=1;
  759.                         }
  760.                     }
  761.                     if (!$newsec)
  762.                     {
  763.                         $w=@explode("=",$w);
  764.                         $k=@trim($w[0]);
  765.                         unset($w[0])
  766.                         $v=@trim(@implode("=",$w));
  767.                         if ((@substr($v,0,1)=="\""and (@substr($v,-1,1)=="\"")) 
  768.                         {
  769.                             $v=@substr($v,1,@strlen($v)-2);
  770.                         }
  771.                         if ($sec
  772.                         {
  773.                             if(strtolower($sec)=='course_description'){//special case
  774.                                 $r[strtolower($sec)]=$k;
  775.                             }else{
  776.                                 $r[strtolower($sec)][strtolower($k)]=$v;
  777.                             }
  778.                         else 
  779.                         {
  780.                             $r[strtolower($k)]=$v;
  781.                         }
  782.                     }
  783.                 }
  784.             }
  785.             return $r;
  786.         }
  787.       /**
  788.        * Static function to parse AICC ini strings.
  789.        * Based on work by sinedeo at gmail dot com published on php.net (parse_ini_file())
  790.        * @param        string    INI File string
  791.        * @param        array    List of names of sections that should be considered as containing only hard string data (no variables), provided in lower case
  792.        * @return    array    Structured array
  793.        */
  794.         function parse_ini_string_quotes_safe($s,$pure_strings=array())
  795.         {
  796.             $null "";
  797.             $r=$null;
  798.             $sec=$null;
  799.             $f split("\r\n",$s);
  800.             for ($i=0;$i<@count($f);$i++)
  801.             {
  802.                 $newsec=0;
  803.                 $w=@trim($f[$i]);
  804.                 if ($w)
  805.                 {
  806.                     if ((!$ror ($sec))
  807.                     {
  808.                         if ((@substr($w,0,1)=="["and (@substr($w,-1,1))=="]"
  809.                         {
  810.                             $sec=@substr($w,1,@strlen($w)-2);
  811.                             $pure_data 0;
  812.                             if(in_array(strtolower($sec),$pure_strings)){
  813.                                 //this section can only be considered as pure string data (until the next section)
  814.                                 $pure_data 1;
  815.                                 $r[strtolower($sec)'';
  816.                             }
  817.                             $newsec=1;
  818.                         }
  819.                     }
  820.                     if (!$newsec)
  821.                     {
  822.                         $w=@explode("=",$w);
  823.                         $k=@trim($w[0]);
  824.                         unset($w[0])
  825.                         $v=@trim(@implode("=",$w));
  826.                         if ((@substr($v,0,1)=="\""and (@substr($v,-1,1)=="\"")) 
  827.                         {
  828.                             $v=@substr($v,1,@strlen($v)-2);
  829.                         }
  830.                         if ($sec
  831.                         {
  832.                             if($pure_data){
  833.                                 $r[strtolower($sec).= $f[$i];
  834.                             }else{
  835.                                 if(strtolower($sec)=='course_description'){//special case
  836.                                     $r[strtolower($sec)]=$k;
  837.                                 }else{
  838.                                     $r[strtolower($sec)][strtolower($k)]=$v;
  839.                                 }
  840.                             }
  841.                         else 
  842.                         {
  843.                             $r[strtolower($k)]=$v;
  844.                         }
  845.                     }
  846.                 }
  847.             }
  848.             return $r;
  849.         }
  850.       /**
  851.        * Static function that parses CSV files into simple arrays, based on a function
  852.        * by spam at cyber-space dot nl published on php.net (fgetcsv())
  853.        * @param    string    Filepath
  854.        * @param    string    CSV delimiter
  855.        * @param    string    CSV enclosure
  856.        * @param    boolean    Might one field name happen more than once on the same line? (then split by comma in the values)
  857.        * @return array    Simple structured array
  858.        */
  859.         function parse_csv_file($f,$delim=',',$enclosure='"',$multiples=false)
  860.         {
  861.             $data file_get_contents($f);
  862.             $enclosed=false;
  863.             $fldcount=0;
  864.             $linecount=0;
  865.             $fldval='';
  866.             for($i=0;$i<strlen($data);$i++)
  867.             {
  868.                 $chr=$data{$i};
  869.                 switch($chr)
  870.                 {
  871.                     case $enclosure:
  872.                        if($enclosed&&$data{$i+1}==$enclosure)
  873.                        {
  874.                            $fldval.=$chr;
  875.                            ++$i//skip next char
  876.                        }
  877.                        else
  878.                          $enclosed=!$enclosed;
  879.                        break;
  880.                     case $delim:
  881.                        if(!$enclosed)
  882.                        {
  883.                          $ret_array[$linecount][$fldcount++]=$fldval;
  884.                          $fldval='';
  885.                        }
  886.                        else
  887.                          $fldval.=$chr;
  888.                        break;
  889.                     case "\r":
  890.                        if(!$enclosed&&$data{$i+1}=="\n")
  891.                          continue;
  892.                     case "\n":
  893.                         if(!$enclosed)
  894.                         {
  895.                             $ret_array[$linecount++][$fldcount]=$fldval;
  896.                             $fldcount=0;
  897.                             $fldval='';
  898.                         }
  899.                         else
  900.                             $fldval.=$chr;
  901.                         break;
  902.                     case "\\r":
  903.                        if(!$enclosed&&$data{$i+1}=="\\n")
  904.                          continue;
  905.                     case "\\n":
  906.                         if(!$enclosed)
  907.                         {
  908.                             $ret_array[$linecount++][$fldcount]=$fldval;
  909.                             $fldcount=0;
  910.                             $fldval='';
  911.                         }
  912.                         else
  913.                             $fldval.=$chr;
  914.                         break;
  915.                     default:
  916.                         $fldval.=$chr;
  917.                 }
  918.             }
  919.             if($fldval){
  920.                 $ret_array[$linecount][$fldcount]=$fldval;
  921.             }
  922.             //transform the array to use the first line as titles
  923.             $titles array();
  924.             $ret_ret_array array();
  925.             foreach($ret_array as $line_idx => $line){
  926.                 if($line_idx == 0){
  927.                     $titles $line;
  928.                 }else{
  929.                     $ret_ret_array[$line_idxarray();
  930.                     foreach($line as $idx=>$val)
  931.                     {
  932.                         if($multiples && !empty($ret_ret_array[$line_idx][strtolower($titles[$idx])])){
  933.                             $ret_ret_array[$line_idx][strtolower($titles[$idx])].=",".$val;
  934.                         }else{
  935.                             $ret_ret_array[$line_idx][strtolower($titles[$idx])]=$val;
  936.                         }
  937.                     }
  938.                 }
  939.             }
  940.             return $ret_ret_array;
  941.         }
  942.         
  943. }
  944. ?>

Documentation generated on Thu, 12 Jun 2008 12:57:01 -0500 by phpDocumentor 1.4.1