Ejemplo n.º 1
0
    /**
     * Performs synchronisation of an external file if the previous one has expired.
     *
     * This function must be implemented for external repositories supporting
     * FILE_REFERENCE, it is called for existing aliases when their filesize,
     * contenthash or timemodified are requested. It is not called for internal
     * repositories (see {@link repository::has_moodle_files()}), references to
     * internal files are updated immediately when source is modified.
     *
     * Referenced files may optionally keep their content in Moodle filepool (for
     * thumbnail generation or to be able to serve cached copy). In this
     * case both contenthash and filesize need to be synchronized. Otherwise repositories
     * should use contenthash of empty file and correct filesize in bytes.
     *
     * Note that this function may be run for EACH file that needs to be synchronised at the
     * moment. If anything is being downloaded or requested from external sources there
     * should be a small timeout. The synchronisation is performed to update the size of
     * the file and/or to update image and re-generated image preview. There is nothing
     * fatal if syncronisation fails but it is fatal if syncronisation takes too long
     * and hangs the script generating a page.
     *
     * Note: If you wish to call $file->get_filesize(), $file->get_contenthash() or
     * $file->get_timemodified() make sure that recursion does not happen.
     *
     * Called from {@link stored_file::sync_external_file()}
     *
     * @uses stored_file::set_missingsource()
     * @uses stored_file::set_synchronized()
     * @param stored_file $file
     * @return bool false when file does not need synchronisation, true if it was synchronised
     */
    public function sync_reference(stored_file $file) {
        if ($file->get_repository_id() != $this->id) {
            // This should not really happen because the function can be called from stored_file only.
            return false;
        }

        if ($this->has_moodle_files()) {
            // References to local files need to be synchronised only once.
            // Later they will be synchronised automatically when the source is changed.
            if ($file->get_referencelastsync()) {
                return false;
            }
            $fs = get_file_storage();
            $params = file_storage::unpack_reference($file->get_reference(), true);
            if (!is_array($params) || !($storedfile = $fs->get_file($params['contextid'],
                    $params['component'], $params['filearea'], $params['itemid'], $params['filepath'],
                    $params['filename']))) {
                $file->set_missingsource();
            } else {
                $file->set_synchronized($storedfile->get_contenthash(), $storedfile->get_filesize());
            }
            return true;
        }

        // Backward compatibility (Moodle 2.3-2.5) implementation that calls
        // methods repository::get_reference_file_lifetime(), repository::sync_individual_file()
        // and repository::get_file_by_reference(). These methods are removed from the
        // base repository class but may still be implemented by the child classes.

        // THIS IS NOT A GOOD EXAMPLE of implementation. For good examples see the overwriting methods.

        if (!method_exists($this, 'get_file_by_reference')) {
            // Function get_file_by_reference() is not implemented. No synchronisation.
            return false;
        }

        // Check if the previous sync result is still valid.
        if (method_exists($this, 'get_reference_file_lifetime')) {
            $lifetime = $this->get_reference_file_lifetime($file->get_reference());
        } else {
            // Default value that was hardcoded in Moodle 2.3 - 2.5.
            $lifetime =  60 * 60 * 24;
        }
        if (($lastsynced = $file->get_referencelastsync()) && $lastsynced + $lifetime >= time()) {
            return false;
        }

        $cache = cache::make('core', 'repositories');
        if (($lastsyncresult = $cache->get('sync:'.$file->get_referencefileid())) !== false) {
            if ($lastsyncresult === true) {
                // We are in the process of synchronizing this reference.
                // Avoid recursion when calling $file->get_filesize() and $file->get_contenthash().
                return false;
            } else {
                // We have synchronised the same reference inside this request already.
                // It looks like the object $file was created before the synchronisation and contains old data.
                if (!empty($lastsyncresult['missing'])) {
                    $file->set_missingsource();
                } else {
                    $cache->set('sync:'.$file->get_referencefileid(), true);
                    if ($file->get_contenthash() != $lastsyncresult['contenthash'] ||
                            $file->get_filesize() != $lastsyncresult['filesize']) {
                        $file->set_synchronized($lastsyncresult['contenthash'], $lastsyncresult['filesize']);
                    }
                    $cache->set('sync:'.$file->get_referencefileid(), $lastsyncresult);
                }
                return true;
            }
        }

        // Weird function sync_individual_file() that was present in API in 2.3 - 2.5, default value was true.
        if (method_exists($this, 'sync_individual_file') && !$this->sync_individual_file($file)) {
            return false;
        }

        // Set 'true' into the cache to indicate that file is in the process of synchronisation.
        $cache->set('sync:'.$file->get_referencefileid(), true);

        // Create object with the structure that repository::get_file_by_reference() expects.
        $reference = new stdClass();
        $reference->id = $file->get_referencefileid();
        $reference->reference = $file->get_reference();
        $reference->referencehash = sha1($file->get_reference());
        $reference->lastsync = $file->get_referencelastsync();
        $reference->lifetime = $lifetime;

        $fileinfo = $this->get_file_by_reference($reference);

        $contenthash = null;
        $filesize = null;
        $fs = get_file_storage();
        if (!empty($fileinfo->filesize)) {
            // filesize returned
            if (!empty($fileinfo->contenthash) && $fs->content_exists($fileinfo->contenthash)) {
                // contenthash is specified and valid
                $contenthash = $fileinfo->contenthash;
            } else if ($fileinfo->filesize == $file->get_filesize()) {
                // we don't know the new contenthash but the filesize did not change,
                // assume the contenthash did not change either
                $contenthash = $file->get_contenthash();
            } else {
                // we can't save empty contenthash so generate contenthash from empty string
                list($contenthash, $unused1, $unused2) = $fs->add_string_to_pool('');
            }
            $filesize = $fileinfo->filesize;
        } else if (!empty($fileinfo->filepath)) {
            // File path returned
            list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($fileinfo->filepath);
        } else if (!empty($fileinfo->handle) && is_resource($fileinfo->handle)) {
            // File handle returned
            $contents = '';
            while (!feof($fileinfo->handle)) {
                $contents .= fread($fileinfo->handle, 8192);
            }
            fclose($fileinfo->handle);
            list($contenthash, $filesize, $newfile) = $fs->add_string_to_pool($contents);
        } else if (isset($fileinfo->content)) {
            // File content returned
            list($contenthash, $filesize, $newfile) = $fs->add_string_to_pool($fileinfo->content);
        }

        if (!isset($contenthash) or !isset($filesize)) {
            $file->set_missingsource(null);
            $cache->set('sync:'.$file->get_referencefileid(), array('missing' => true));
        } else {
            // update files table
            $file->set_synchronized($contenthash, $filesize);
            $cache->set('sync:'.$file->get_referencefileid(),
                    array('contenthash' => $contenthash, 'filesize' => $filesize));
        }

        return true;
    }
Ejemplo n.º 2
0
 /**
  * Downloads the file from external repository and saves it in moodle filepool.
  * This function is different from {@link repository::sync_reference()} because it has
  * bigger request timeout and always downloads the content.
  *
  * This function is invoked when we try to unlink the file from the source and convert
  * a reference into a true copy.
  *
  * @throws exception when file could not be imported
  *
  * @param stored_file $file
  * @param int $maxbytes throw an exception if file size is bigger than $maxbytes (0 means no limit)
  */
 public function import_external_file_contents(stored_file $file, $maxbytes = 0)
 {
     if (!$file->is_external_file()) {
         // nothing to import if the file is not a reference
         return;
     } else {
         if ($file->get_repository_id() != $this->id) {
             // error
             debugging('Repository instance id does not match');
             return;
         } else {
             if ($this->has_moodle_files()) {
                 // files that are references to local files are already in moodle filepool
                 // just validate the size
                 if ($maxbytes > 0 && $file->get_filesize() > $maxbytes) {
                     throw new file_exception('maxbytes');
                 }
                 return;
             } else {
                 if ($maxbytes > 0 && $file->get_filesize() > $maxbytes) {
                     // note that stored_file::get_filesize() also calls synchronisation
                     throw new file_exception('maxbytes');
                 }
                 $fs = get_file_storage();
                 $contentexists = $fs->content_exists($file->get_contenthash());
                 if ($contentexists && $file->get_filesize() && $file->get_contenthash() === sha1('')) {
                     // even when 'file_storage::content_exists()' returns true this may be an empty
                     // content for the file that was not actually downloaded
                     $contentexists = false;
                 }
                 if (!$file->get_status() && $contentexists) {
                     // we already have the content in moodle filepool and it was synchronised recently.
                     // Repositories may overwrite it if they want to force synchronisation anyway!
                     return;
                 } else {
                     // attempt to get a file
                     try {
                         $fileinfo = $this->get_file($file->get_reference());
                         if (isset($fileinfo['path'])) {
                             list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($fileinfo['path']);
                             // set this file and other similar aliases synchronised
                             $file->set_synchronized($contenthash, $filesize);
                         } else {
                             throw new moodle_exception('errorwhiledownload', 'repository', '', '');
                         }
                     } catch (Exception $e) {
                         if ($contentexists) {
                             // better something than nothing. We have a copy of file. It's sync time
                             // has expired but it is still very likely that it is the last version
                         } else {
                             throw $e;
                         }
                     }
                 }
             }
         }
     }
 }
Ejemplo n.º 3
0
 /**
  * Replace the content by providing another stored_file instance
  *
  * @param stored_file $storedfile
  */
 public function replace_content_with(stored_file $storedfile)
 {
     $contenthash = $storedfile->get_contenthash();
     $this->set_contenthash($contenthash);
 }
Ejemplo n.º 4
0
 /**
  * Updates all files that are referencing this file with the new contenthash
  * and filesize
  *
  * @param stored_file $storedfile
  */
 public function update_references_to_storedfile(stored_file $storedfile)
 {
     global $CFG, $DB;
     $params = array();
     $params['contextid'] = $storedfile->get_contextid();
     $params['component'] = $storedfile->get_component();
     $params['filearea'] = $storedfile->get_filearea();
     $params['itemid'] = $storedfile->get_itemid();
     $params['filename'] = $storedfile->get_filename();
     $params['filepath'] = $storedfile->get_filepath();
     $reference = self::pack_reference($params);
     $referencehash = sha1($reference);
     $sql = "SELECT repositoryid, id FROM {files_reference}\n                 WHERE referencehash = ?";
     $rs = $DB->get_recordset_sql($sql, array($referencehash));
     $now = time();
     foreach ($rs as $record) {
         $this->update_references($record->id, $now, null, $storedfile->get_contenthash(), $storedfile->get_filesize(), 0, $storedfile->get_timemodified());
     }
     $rs->close();
 }
Ejemplo n.º 5
0
 /**
  * Replaces the fields that might have changed when file was overriden in filepicker:
  * reference, contenthash, filesize, userid
  *
  * Note that field 'source' must be updated separately because
  * it has different format for draft and non-draft areas and
  * this function will usually be used to replace non-draft area
  * file with draft area file.
  *
  * @param stored_file $newfile
  * @throws coding_exception
  */
 public function replace_file_with(stored_file $newfile)
 {
     if ($newfile->get_referencefileid() && $this->fs->get_references_count_by_storedfile($this)) {
         // The new file is a reference.
         // The current file has other local files referencing to it.
         // Double reference is not allowed.
         throw new moodle_exception('errordoublereference', 'repository');
     }
     $filerecord = new stdClass();
     $contenthash = $newfile->get_contenthash();
     if ($this->fs->content_exists($contenthash)) {
         $filerecord->contenthash = $contenthash;
     } else {
         throw new file_exception('storedfileproblem', 'Invalid contenthash, content must be already in filepool', $contenthash);
     }
     $filerecord->filesize = $newfile->get_filesize();
     $filerecord->referencefileid = $newfile->get_referencefileid();
     $filerecord->userid = $newfile->get_userid();
     $this->update($filerecord);
 }
Ejemplo n.º 6
0
/**
 * Resize the image, if required, then generate an img tag and, if required, a link to the full-size image
 * @param stored_file $file the image file to process
 * @param int $maxwidth the maximum width allowed for the image
 * @param int $maxheight the maximum height allowed for the image
 * @return string HTML fragment to add to the label
 */
function label_generate_resized_image(stored_file $file, $maxwidth, $maxheight)
{
    global $CFG;
    $fullurl = moodle_url::make_draftfile_url($file->get_itemid(), $file->get_filepath(), $file->get_filename());
    $link = null;
    $attrib = array('alt' => $file->get_filename(), 'src' => $fullurl);
    if ($imginfo = $file->get_imageinfo()) {
        // Work out the new width / height, bounded by maxwidth / maxheight
        $width = $imginfo['width'];
        $height = $imginfo['height'];
        if (!empty($maxwidth) && $width > $maxwidth) {
            $height *= (double) $maxwidth / $width;
            $width = $maxwidth;
        }
        if (!empty($maxheight) && $height > $maxheight) {
            $width *= (double) $maxheight / $height;
            $height = $maxheight;
        }
        $attrib['width'] = $width;
        $attrib['height'] = $height;
        // If the size has changed and the image is of a suitable mime type, generate a smaller version
        if ($width != $imginfo['width']) {
            $mimetype = $file->get_mimetype();
            if ($mimetype === 'image/gif' or $mimetype === 'image/jpeg' or $mimetype === 'image/png') {
                require_once $CFG->libdir . '/gdlib.php';
                $tmproot = make_temp_directory('mod_label');
                $tmpfilepath = $tmproot . '/' . $file->get_contenthash();
                $file->copy_content_to($tmpfilepath);
                $data = generate_image_thumbnail($tmpfilepath, $width, $height);
                unlink($tmpfilepath);
                if (!empty($data)) {
                    $fs = get_file_storage();
                    $record = array('contextid' => $file->get_contextid(), 'component' => $file->get_component(), 'filearea' => $file->get_filearea(), 'itemid' => $file->get_itemid(), 'filepath' => '/', 'filename' => 's_' . $file->get_filename());
                    $smallfile = $fs->create_file_from_string($record, $data);
                    // Replace the image 'src' with the resized file and link to the original
                    $attrib['src'] = moodle_url::make_draftfile_url($smallfile->get_itemid(), $smallfile->get_filepath(), $smallfile->get_filename());
                    $link = $fullurl;
                }
            }
        }
    } else {
        // Assume this is an image type that get_imageinfo cannot handle (e.g. SVG)
        $attrib['width'] = $maxwidth;
    }
    $img = html_writer::empty_tag('img', $attrib);
    if ($link) {
        return html_writer::link($link, $img);
    } else {
        return $img;
    }
}
Ejemplo n.º 7
0
 /**
  * Export the data for the given file in relation to this document.
  *
  * @param \stored_file $file The stored file we are talking about.
  * @return array
  */
 public function export_file_for_engine($file)
 {
     $data = $this->export_for_engine();
     // Content is index in the main document.
     unset($data['content']);
     unset($data['description1']);
     unset($data['description2']);
     // Going to append the fileid to give it a unique id.
     $data['id'] = $data['id'] . '-solrfile' . $file->get_id();
     $data['type'] = \core_search\manager::TYPE_FILE;
     $data['solr_fileid'] = $file->get_id();
     $data['solr_filecontenthash'] = $file->get_contenthash();
     $data['solr_fileindexstatus'] = self::INDEXED_FILE_TRUE;
     $data['title'] = $file->get_filename();
     $data['modified'] = self::format_time_for_engine($file->get_timemodified());
     return $data;
 }
Ejemplo n.º 8
0
 /**
  * Copies a file from somewhere else in moodle
  * to the portfolio temporary working directory
  * associated with this export
  *
  * @param stored_file $oldfile existing stored file object
  * @return stored_file|bool new file object
  */
 public function copy_existing_file($oldfile)
 {
     if (array_key_exists($oldfile->get_contenthash(), $this->newfilehashes)) {
         return $this->newfilehashes[$oldfile->get_contenthash()];
     }
     $fs = get_file_storage();
     $file_record = $this->new_file_record_base($oldfile->get_filename());
     if ($dir = $this->get('format')->get_file_directory()) {
         $file_record->filepath = '/' . $dir . '/';
     }
     try {
         $newfile = $fs->create_file_from_storedfile($file_record, $oldfile->get_id());
         $this->newfilehashes[$newfile->get_contenthash()] = $newfile;
         return $newfile;
     } catch (file_exception $e) {
         return false;
     }
 }
Ejemplo n.º 9
0
 public function sync_reference(stored_file $file)
 {
     if ($file->get_referencelastsync() + 60 > time()) {
         // Does not cost us much to synchronise within our own filesystem, check every 1 minute.
         return false;
     }
     static $issyncing = false;
     if ($issyncing) {
         // Avoid infinite recursion when calling $file->get_filesize() and get_contenthash().
         return false;
     }
     $filepath = $this->get_rootpath() . ltrim($file->get_reference(), '/');
     if ($this->is_in_repository($file->get_reference()) && file_exists($filepath) && is_readable($filepath)) {
         $fs = get_file_storage();
         $issyncing = true;
         if (file_extension_in_typegroup($filepath, 'web_image')) {
             $contenthash = sha1_file($filepath);
             if ($file->get_contenthash() == $contenthash) {
                 // File did not change since the last synchronisation.
                 $filesize = filesize($filepath);
             } else {
                 // Copy file into moodle filepool (used to generate an image thumbnail).
                 list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($filepath);
             }
         } else {
             // Update only file size so file will NOT be copied into moodle filepool.
             $emptyfile = $contenthash = sha1('');
             $currentcontenthash = $file->get_contenthash();
             if ($currentcontenthash !== $emptyfile && $currentcontenthash === sha1_file($filepath)) {
                 // File content was synchronised and has not changed since then, leave it.
                 $contenthash = null;
             }
             $filesize = filesize($filepath);
         }
         $issyncing = false;
         $file->set_synchronized($contenthash, $filesize);
     } else {
         $file->set_missingsource();
     }
     return true;
 }
Ejemplo n.º 10
0
 /**
  * Tries to recover missing content of file from trash.
  *
  * @param stored_file $file stored_file instance
  * @return bool success
  */
 public function try_content_recovery($file)
 {
     $contenthash = $file->get_contenthash();
     $trashfile = $this->trash_path_from_hash($contenthash) . '/' . $contenthash;
     if (!is_readable($trashfile)) {
         if (!is_readable($this->trashdir . '/' . $contenthash)) {
             return false;
         }
         // nice, at least alternative trash file in trash root exists
         $trashfile = $this->trashdir . '/' . $contenthash;
     }
     if (filesize($trashfile) != $file->get_filesize() or sha1_file($trashfile) != $contenthash) {
         //weird, better fail early
         return false;
     }
     $contentdir = $this->path_from_hash($contenthash);
     $contentfile = $contentdir . '/' . $contenthash;
     if (file_exists($contentfile)) {
         //strange, no need to recover anything
         return true;
     }
     if (!is_dir($contentdir)) {
         if (!mkdir($contentdir, $this->dirpermissions, true)) {
             return false;
         }
     }
     return rename($trashfile, $contentfile);
 }
Ejemplo n.º 11
0
 /**
  * Check to see if PDF is version 1.4 (or below); if not: use ghostscript to convert it
  * @param stored_file $file
  * @return string path to copy or converted pdf (false == fail)
  */
 public static function ensure_pdf_compatible(\stored_file $file)
 {
     global $CFG;
     $fp = $file->get_content_file_handle();
     $ident = fread($fp, 10);
     if (substr_compare('%PDF-', $ident, 0, 5) !== 0) {
         return false;
         // This is not a PDF file at all.
     }
     $ident = substr($ident, 5);
     // Remove the '%PDF-' part.
     $ident = explode('\\x0A', $ident);
     // Truncate to first '0a' character.
     list($major, $minor) = explode('.', $ident[0]);
     // Split the major / minor version.
     $major = intval($major);
     $minor = intval($minor);
     if ($major == 0 || $minor == 0) {
         return false;
         // Not a valid PDF version number.
     }
     $temparea = \make_temp_directory('assignfeedback_editpdf');
     $hash = $file->get_contenthash();
     // Use the contenthash to make sure the temp files have unique names.
     $tempsrc = $temparea . "/src-{$hash}.pdf";
     $tempdst = $temparea . "/dst-{$hash}.pdf";
     if ($major = 1 && $minor <= 4) {
         // PDF is valid version - just create a copy we can use.
         $file->copy_content_to($tempdst);
         // Copy the file.
         return $tempdst;
     }
     $file->copy_content_to($tempsrc);
     // Copy the file.
     $gsexec = \get_config('assignfeedback_editpdf', 'gspath');
     $command = "{$gsexec} -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=\"{$tempdst}\" \"{$tempsrc}\"";
     //$command = escapeshellcmd($command);
     exec($command);
     @unlink($tempsrc);
     if (!file_exists($tempdst)) {
         // Something has gone wrong in the conversion.
         return false;
     }
     return $tempdst;
 }
Ejemplo n.º 12
0
    /**
     * Does this file exist in any of the current files supported by this plugin for this user?
     *
     * @param assign $assignment - The assignment instance
     * @param stdClass $user The user matching this uploaded file
     * @param assign_plugin $plugin The matching plugin from the filename
     * @param string $filename The parsed filename from the zip
     * @param stored_file $fileinfo The info about the extracted file from the zip
     * @return bool - True if the file has been modified or is new
     */
    public function is_file_modified($assignment, $user, $plugin, $filename, $fileinfo) {
        $sg = null;

        if ($plugin->get_subtype() == 'assignsubmission') {
            $sg = $assignment->get_user_submission($user->id, false);
        } else if ($plugin->get_subtype() == 'assignfeedback') {
            $sg = $assignment->get_user_grade($user->id, false);
        } else {
            return false;
        }

        if (!$sg) {
            return true;
        }
        foreach ($plugin->get_files($sg, $user) as $pluginfilename => $file) {
            if ($pluginfilename == $filename) {
                // Extract the file and compare hashes.
                $contenthash = '';
                if (is_array($file)) {
                    $content = reset($file);
                    $contenthash = sha1($content);
                } else {
                    $contenthash = $file->get_contenthash();
                }
                if ($contenthash != $fileinfo->get_contenthash()) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        return true;
    }
Ejemplo n.º 13
0
 /**
  * Updates all files that are referencing this file with the new contenthash
  * and filesize
  *
  * @param stored_file $storedfile
  */
 public function update_references_to_storedfile(stored_file $storedfile)
 {
     global $CFG, $DB;
     $params = array();
     $params['contextid'] = $storedfile->get_contextid();
     $params['component'] = $storedfile->get_component();
     $params['filearea'] = $storedfile->get_filearea();
     $params['itemid'] = $storedfile->get_itemid();
     $params['filename'] = $storedfile->get_filename();
     $params['filepath'] = $storedfile->get_filepath();
     $reference = self::pack_reference($params);
     $referencehash = sha1($reference);
     $sql = "SELECT repositoryid, id FROM {files_reference}\n                 WHERE referencehash = ? and reference = ?";
     $rs = $DB->get_recordset_sql($sql, array($referencehash, $reference));
     $now = time();
     foreach ($rs as $record) {
         require_once $CFG->dirroot . '/repository/lib.php';
         $repo = repository::get_instance($record->repositoryid);
         $lifetime = $repo->get_reference_file_lifetime($reference);
         $this->update_references($record->id, $now, $lifetime, $storedfile->get_contenthash(), $storedfile->get_filesize(), 0);
     }
     $rs->close();
 }
Ejemplo n.º 14
0
 /**
  * Check to see if PDF is version 1.4 (or below); if not: use ghostscript to convert it
  * @param stored_file $file
  * @return string path to copy or converted pdf (false == fail)
  */
 public static function ensure_pdf_compatible(\stored_file $file)
 {
     global $CFG;
     $temparea = \make_temp_directory('assignfeedback_editpdf');
     $hash = $file->get_contenthash();
     // Use the contenthash to make sure the temp files have unique names.
     $tempsrc = $temparea . "/src-{$hash}.pdf";
     $tempdst = $temparea . "/dst-{$hash}.pdf";
     $file->copy_content_to($tempsrc);
     // Copy the file.
     $pdf = new pdf();
     $pagecount = 0;
     try {
         $pagecount = $pdf->load_pdf($tempsrc);
     } catch (\Exception $e) {
         // PDF was not valid - try running it through ghostscript to clean it up.
         $pagecount = 0;
     }
     $pdf->Close();
     // PDF loaded and never saved/outputted needs to be closed.
     if ($pagecount > 0) {
         // Page is valid and can be read by tcpdf.
         return $tempsrc;
     }
     $gsexec = \escapeshellarg($CFG->pathtogs);
     $tempdstarg = \escapeshellarg($tempdst);
     $tempsrcarg = \escapeshellarg($tempsrc);
     $command = "{$gsexec} -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile={$tempdstarg} {$tempsrcarg}";
     exec($command);
     @unlink($tempsrc);
     if (!file_exists($tempdst)) {
         // Something has gone wrong in the conversion.
         return false;
     }
     $pdf = new pdf();
     $pagecount = 0;
     try {
         $pagecount = $pdf->load_pdf($tempdst);
     } catch (\Exception $e) {
         // PDF was not valid - try running it through ghostscript to clean it up.
         $pagecount = 0;
     }
     $pdf->Close();
     // PDF loaded and never saved/outputted needs to be closed.
     if ($pagecount <= 0) {
         @unlink($tempdst);
         // Could not parse the converted pdf.
         return false;
     }
     return $tempdst;
 }
Ejemplo n.º 15
0
 static function ensure_pdf_compatible(stored_file $file)
 {
     global $CFG;
     $fp = $file->get_content_file_handle();
     $ident = fread($fp, 10);
     if (substr_compare('%PDF-', $ident, 0, 5) !== 0) {
         return false;
         // This is not a PDF file at all
     }
     $ident = substr($ident, 5);
     // Remove the '%PDF-' part
     $ident = explode('\\x0A', $ident);
     // Truncate to first '0a' character
     list($major, $minor) = explode('.', $ident[0]);
     // Split the major / minor version
     $major = intval($major);
     $minor = intval($minor);
     if ($major == 0 || $minor == 0) {
         return false;
         // Not a valid PDF version number
     }
     if ($major = 1 && $minor <= 4) {
         return true;
         // We can handle this version - nothing else to do
     }
     $temparea = $CFG->dataroot . '/temp/uploadpdf';
     $hash = $file->get_contenthash();
     $tempsrc = $temparea . "/src-{$hash}.pdf";
     $tempdst = $temparea . "/dst-{$hash}.pdf";
     if (!file_exists($temparea)) {
         if (!mkdir($temparea, 0777, true)) {
             die("Unable to create temporary folder {$temparea}");
         }
     }
     $file->copy_content_to($tempsrc);
     // Copy the file
     $gsexec = $CFG->gs_path;
     $command = "{$gsexec} -q -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -sOutputFile=\"{$tempdst}\" \"{$tempsrc}\" 2>&1";
     $result = exec($command);
     if (!file_exists($tempdst)) {
         return false;
         // Something has gone wrong in the conversion
     }
     $file->delete();
     // Delete the original file
     $fs = get_file_storage();
     $fileinfo = array('contextid' => $file->get_contextid(), 'component' => $file->get_component(), 'filearea' => $file->get_filearea(), 'itemid' => $file->get_itemid(), 'filename' => $file->get_filename(), 'filepath' => $file->get_filepath());
     $fs->create_file_from_pathname($fileinfo, $tempdst);
     // Create replacement file
     @unlink($tempsrc);
     // Delete the temporary files
     @unlink($tempdst);
     return true;
 }