[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/repository/boxnet/ -> locallib.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Box.net locallib.
  19   *
  20   * @package    repository_boxnet
  21   * @copyright  2013 Frédéric Massart
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  /**
  26   * Migrate the references to local files.
  27   *
  28   * As the APIv1 is reaching its end of life on the 14th of Dec 2013, and we cannot
  29   * convert the existing references to new references, we need to convert them
  30   * to real files.
  31   *
  32   * @todo   Deprecate/remove this function after the 14th of December 2013.
  33   * @return void
  34   */
  35  function repository_boxnet_migrate_references_from_apiv1() {
  36      global $DB;
  37  
  38      // A string that the old references contain.
  39      $apiv1signature = '/api/1.0/download/';
  40  
  41      // Downloading the files could take a very long time!
  42      @set_time_limit(0);
  43  
  44      // Create directory to download temporary files.
  45      $dir = make_temp_directory('download/repository_boxnet/');
  46  
  47      // Create a dummy file for the broken files.
  48      $fs = get_file_storage();
  49      list($dummyhash, $dummysize, $unused) = $fs->add_string_to_pool('Lost reference from Box.net');
  50  
  51      // Get the Box.net instances. There should be only one.
  52      $sql = "SELECT i.id, i.typeid, r.id, r.type
  53                FROM {repository} r, {repository_instances} i
  54               WHERE i.typeid = r.id
  55                 AND r.type = :type";
  56      $ids = $DB->get_fieldset_sql($sql, array('type' => 'boxnet'));
  57      if (empty($ids)) {
  58          // We did not find any instance of Box.net. Let's just ignore this migration.
  59          mtrace('Could not find any instance of the repository, aborting migration...');
  60          return;
  61      }
  62  
  63      // The next bit is copied from the function file_storage::instance_sql_fields()
  64      // because it is private and there is nothing in file_storage that suits our needs here.
  65      $filefields = array('contenthash', 'pathnamehash', 'contextid', 'component', 'filearea',
  66          'itemid', 'filepath', 'filename', 'userid', 'filesize', 'mimetype', 'status', 'source',
  67          'author', 'license', 'timecreated', 'timemodified', 'sortorder', 'referencefileid');
  68      $referencefields = array('repositoryid' => 'repositoryid',
  69          'reference' => 'reference',
  70          'lastsync' => 'referencelastsync');
  71      $fields = array();
  72      $fields[] = 'f.id AS id';
  73      foreach ($filefields as $field) {
  74          $fields[] = "f.{$field}";
  75      }
  76      foreach ($referencefields as $field => $alias) {
  77          $fields[] = "r.{$field} AS {$alias}";
  78      }
  79      $fields = implode(', ', $fields);
  80  
  81      // We are not using repository::convert_references_to_local() or file_storage::get_external_files()
  82      // because they would select too many records and load everything in memory as it is not using a recordset.
  83      // Also, we filter the results not to get the draft area which should not be converted.
  84      list($sqlfragment, $fragmentparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED);
  85      $sql = "SELECT " . $fields . "
  86                FROM {files_reference} r
  87                LEFT JOIN {files} f
  88                     ON f.referencefileid = r.id
  89               WHERE r.repositoryid $sqlfragment
  90                 AND f.referencefileid IS NOT NULL
  91                 AND NOT (f.component = :component
  92                 AND f.filearea = :filearea)";
  93  
  94      // For each reference we download the file. Then we add it to the file pool and update the references.
  95      // The reason why we are re-inventing the wheel here is because the current API ends up calling
  96      // repository::get_file() which includes a download timeout. As we are trying our best to copy
  97      // the files here, we want to ignre any timeout.
  98      $filerecords = $DB->get_recordset_sql($sql, array_merge($fragmentparams, array('component' => 'user', 'filearea' => 'draft')));
  99      $referenceids = array();
 100      foreach ($filerecords as $filerecord) {
 101          $file = $fs->get_file_instance($filerecord);
 102          $reference = unserialize(repository_boxnet::convert_to_valid_reference($file->get_reference()));
 103  
 104          if (empty($reference->downloadurl)) {
 105              // Something is wrong...
 106              mtrace('Skipping malformed reference (id: ' . $file->get_referencefileid() . ')');
 107              continue;
 108          } else if (strpos($reference->downloadurl, $apiv1signature) === false) {
 109              // This is not an old reference, we are not supposed to work on thos.
 110              mtrace('Skipping non APIv1 reference (id: ' . $file->get_referencefileid() . ')');
 111              continue;
 112          } else if (isset($referenceids[$file->get_referencefileid()])) {
 113              // We have already worked on that reference, we skip any other file related to it.
 114              // We cannot work on them here because they have been updated in the database but our
 115              // recordset does not have those new values. They will be taken care of after this foreach.
 116              continue;
 117          }
 118  
 119          mtrace('Starting migration of file reference ' . $file->get_referencefileid());
 120  
 121          // Manually import the file to the file pool to prevent timeout limitations of the repository method get_file().
 122          // We ignore the fact that the content of the file could exist locally because we want to synchronize the file
 123          // now to prevent the repository to try to download the file as well.
 124          $saveas = $dir . uniqid('', true) . '_' . time() . '.tmp';
 125          $c = new curl();
 126          $result = $c->download_one($reference->downloadurl, null, array('filepath' => $saveas, 'followlocation' => true));
 127          $info = $c->get_info();
 128          if ($result !== true || !isset($info['http_code']) || $info['http_code'] != 200) {
 129              // There was a problem while trying to download the reference...
 130              if ($fs->content_exists($file->get_contenthash()) && $file->get_contenthash() != sha1('')) {
 131                  // Fortunately we already had a local version of this reference, so we keep it. We have to
 132                  // set it synchronized or there is a risk that repository::sync_reference() will try to download
 133                  // the file again. We cannot use $file->get_contenthash() and $file->get_filesize() because they
 134                  // cause repository::sync_reference() to be called.
 135                  $file->set_synchronized($filerecord->contenthash, $filerecord->filesize);
 136                  mtrace('Could not download reference, using last synced file. (id: ' . $file->get_referencefileid() . ')');
 137              } else {
 138                  // We don't know what the file was, but what can we do? In order to prevent a re-attempt to fetch the
 139                  // file in the next bit of this script (import_external_file()), we set a dummy content to the reference.
 140                  $file->set_synchronized($dummyhash, $dummysize);
 141                  mtrace('Could not download reference, dummy file used. (id: ' . $file->get_referencefileid() . ')');
 142              }
 143          } else {
 144              try {
 145                  // The file has been downloaded, we add it to the file pool and synchronize
 146                  // all the files using this reference.
 147                  list($contenthash, $filesize, $unused) = $fs->add_file_to_pool($saveas);
 148                  $file->set_synchronized($contenthash, $filesize);
 149              } catch (moodle_exception $e) {
 150                  // Something wrong happened...
 151                  mtrace('Something went wrong during sync (id: ' . $file->get_referencefileid() . ')');
 152              }
 153          }
 154  
 155          // Log the reference IDs.
 156          $referenceids[$file->get_referencefileid()] = $file->get_referencefileid();
 157  
 158          // Now that the file is downloaded, we can loop over all the files using this reference
 159          // to convert them to local copies. We have chosen to do that in this loop so that if the
 160          // execution fails in the middle, we would not have to redownload the files again and again.
 161          // By the way, we cannot use the records fetched in $filerecords because they will not be updated.
 162          $sql = "SELECT " . $fields . "
 163                    FROM {files} f
 164                    LEFT JOIN {files_reference} r
 165                         ON f.referencefileid = r.id
 166                   WHERE f.referencefileid = :refid
 167                     AND NOT (f.component = :component
 168                     AND f.filearea = :filearea)";
 169          $reffilerecords = $DB->get_recordset_sql($sql, array('component' => 'user', 'filearea' => 'draft',
 170              'refid' => $file->get_referencefileid()));
 171          foreach ($reffilerecords as $reffilerecord) {
 172              $reffile = $fs->get_file_instance($reffilerecord);
 173              try {
 174                  // Updating source to remove trace of APIv1 URL.
 175                  $reffile->set_source('Box APIv1 reference');
 176              } catch (moodle_exception $e) {
 177                  // Do not fail for this lame reason...
 178              }
 179              try {
 180                  $fs->import_external_file($reffile);
 181                  mtrace('File using reference converted to local file (id: ' . $reffile->get_id() . ')');
 182              } catch (moodle_exception $e) {
 183                  // Oh well... we tried what we could!
 184                  $reffile->delete_reference();
 185                  mtrace('Failed to convert file from reference to local file, sorry! (id: ' . $reffile->get_id() . ')');
 186              }
 187          }
 188      }
 189  
 190      mtrace('Migration finished.');
 191  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1