Exemple #1
0
 /**
  * Perform media processing for the given field if something has been uploaded
  *
  * @access private
  * @param string $ps_field field name
  * @param array options
  * 
  * Supported options:
  * 		delete_old_media = set to zero to prevent that old media files are deleted; defaults to 1
  *		these_versions_only = if set to an array of valid version names, then only the specified versions are updated with the currently updated file; ignored if no media already exists
  *		dont_allow_duplicate_media = if set to true, and the model as a field named "md5" then media will be rejected if a row already exists with the same MD5 signature
  */
 public function _processMedia($ps_field, $pa_options = null)
 {
     global $AUTH_CURRENT_USER_ID;
     if (!is_array($pa_options)) {
         $pa_options = array();
     }
     if (!isset($pa_options['delete_old_media'])) {
         $pa_options['delete_old_media'] = true;
     }
     if (!isset($pa_options['these_versions_only'])) {
         $pa_options['these_versions_only'] = null;
     }
     $vs_sql = "";
     $vn_max_execution_time = ini_get('max_execution_time');
     set_time_limit(7200);
     $o_tq = new TaskQueue();
     $o_media_proc_settings = new MediaProcessingSettings($this, $ps_field);
     # only set file if something was uploaded
     # (ie. don't nuke an existing file because none
     #      was uploaded)
     $va_field_info = $this->getFieldInfo($ps_field);
     if (isset($this->_FILES_CLEAR[$ps_field]) && $this->_FILES_CLEAR[$ps_field]) {
         //
         // Clear files
         //
         $va_versions = $this->getMediaVersions($ps_field);
         #--- delete files
         foreach ($va_versions as $v) {
             $this->_removeMedia($ps_field, $v);
         }
         $this->_removeMedia($ps_field, '_undo_');
         $this->_FILES[$ps_field] = null;
         $this->_FIELD_VALUES[$ps_field] = null;
         $vs_sql = "{$ps_field} = " . $this->quote(caSerializeForDatabase($this->_FILES[$ps_field], true)) . ",";
     } else {
         // Don't try to process files when no file is actually set
         if (isset($this->_SET_FILES[$ps_field]['tmp_name'])) {
             $o_tq = new TaskQueue();
             $o_media_proc_settings = new MediaProcessingSettings($this, $ps_field);
             //
             // Process incoming files
             //
             $m = new Media();
             $va_media_objects = array();
             // is it a URL?
             $vs_url_fetched_from = null;
             $vn_url_fetched_on = null;
             $vb_allow_fetching_of_urls = (bool) $this->_CONFIG->get('allow_fetching_of_media_from_remote_urls');
             $vb_is_fetched_file = false;
             if ($vb_allow_fetching_of_urls && (bool) ini_get('allow_url_fopen') && isURL($vs_url = html_entity_decode($this->_SET_FILES[$ps_field]['tmp_name']))) {
                 $vs_tmp_file = tempnam(__CA_APP_DIR__ . '/tmp', 'caUrlCopy');
                 $r_incoming_fp = fopen($vs_url, 'r');
                 if (!$r_incoming_fp) {
                     $this->postError(1600, _t('Cannot open remote URL [%1] to fetch media', $vs_url), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                     set_time_limit($vn_max_execution_time);
                     return false;
                 }
                 $r_outgoing_fp = fopen($vs_tmp_file, 'w');
                 if (!$r_outgoing_fp) {
                     $this->postError(1600, _t('Cannot open file for media fetched from URL [%1]', $vs_url), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                     set_time_limit($vn_max_execution_time);
                     return false;
                 }
                 while (($vs_content = fgets($r_incoming_fp, 4096)) !== false) {
                     fwrite($r_outgoing_fp, $vs_content);
                 }
                 fclose($r_incoming_fp);
                 fclose($r_outgoing_fp);
                 $vs_url_fetched_from = $vs_url;
                 $vn_url_fetched_on = time();
                 $this->_SET_FILES[$ps_field]['tmp_name'] = $vs_tmp_file;
                 $vb_is_fetched_file = true;
             }
             // is it server-side stored user media?
             if (preg_match("!^userMedia[\\d]+/!", $this->_SET_FILES[$ps_field]['tmp_name'])) {
                 // use configured directory to dump media with fallback to standard tmp directory
                 if (!is_writeable($vs_tmp_directory = $this->getAppConfig()->get('ajax_media_upload_tmp_directory'))) {
                     $vs_tmp_directory = caGetTempDirPath();
                 }
                 $this->_SET_FILES[$ps_field]['tmp_name'] = "{$vs_tmp_directory}/" . $this->_SET_FILES[$ps_field]['tmp_name'];
                 // read metadata
                 if (file_exists("{$vs_tmp_directory}/" . $this->_SET_FILES[$ps_field]['tmp_name'] . "_metadata")) {
                     if (is_array($va_tmp_metadata = json_decode(file_get_contents("{$vs_tmp_directory}/" . $this->_SET_FILES[$ps_field]['tmp_name'] . "_metadata")))) {
                         $this->_SET_FILES[$ps_field]['original_filename'] = $va_tmp_metadata['original_filename'];
                     }
                 }
             }
             if (isset($this->_SET_FILES[$ps_field]['tmp_name']) && file_exists($this->_SET_FILES[$ps_field]['tmp_name'])) {
                 if (!isset($pa_options['dont_allow_duplicate_media'])) {
                     $pa_options['dont_allow_duplicate_media'] = (bool) $this->getAppConfig()->get('dont_allow_duplicate_media');
                 }
                 if (isset($pa_options['dont_allow_duplicate_media']) && $pa_options['dont_allow_duplicate_media']) {
                     if ($this->hasField('md5')) {
                         $qr_dupe_chk = $this->getDb()->query("\n\t\t\t\t\t\t\t\tSELECT " . $this->primaryKey() . " FROM " . $this->tableName() . " WHERE md5 = ? " . ($this->hasField('deleted') ? ' AND deleted = 0' : '') . "\n\t\t\t\t\t\t\t", (string) md5_file($this->_SET_FILES[$ps_field]['tmp_name']));
                         if ($qr_dupe_chk->nextRow()) {
                             $this->postError(1600, _t("Media already exists in database"), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                             return false;
                         }
                     }
                 }
                 // allow adding zip and (gzipped) tape archives
                 $vb_is_archive = false;
                 $vs_original_filename = $this->_SET_FILES[$ps_field]['original_filename'];
                 $vs_original_tmpname = $this->_SET_FILES[$ps_field]['tmp_name'];
                 $va_matches = array();
                 if (preg_match("/(\\.zip|\\.tar\\.gz|\\.tgz)\$/", $vs_original_filename, $va_matches)) {
                     $vs_archive_extension = $va_matches[1];
                     // add file extension to temporary file if necessary; otherwise phar barfs when handling the archive
                     $va_tmp = array();
                     preg_match("/[.]*\\.([a-zA-Z0-9]+)\$/", $vs_original_tmpname, $va_tmp);
                     if (!isset($va_tmp[1])) {
                         @rename($this->_SET_FILES[$ps_field]['tmp_name'], $this->_SET_FILES[$ps_field]['tmp_name'] . $vs_archive_extension);
                         $this->_SET_FILES[$ps_field]['tmp_name'] = $this->_SET_FILES[$ps_field]['tmp_name'] . $vs_archive_extension;
                     }
                     if (caIsArchive($this->_SET_FILES[$ps_field]['tmp_name'])) {
                         $va_archive_files = caGetDirectoryContentsAsList('phar://' . $this->_SET_FILES[$ps_field]['tmp_name']);
                         if (sizeof($va_archive_files) > 0) {
                             // get first file we encounter in the archive and use it to generate them previews
                             $vb_is_archive = true;
                             $vs_archive = $this->_SET_FILES[$ps_field]['tmp_name'];
                             $va_tmp = array();
                             // copy primary file from the archive to temporary file (with extension so that *Magick can identify properly)
                             // this is basically a fallback. if the code below fails, we still have a 'fake' original
                             preg_match("/[.]*\\.([a-zA-Z0-9]+)\$/", $va_archive_files[0], $va_tmp);
                             $vs_primary_file_tmp = tempnam(caGetTempDirPath(), "caArchivePrimary");
                             @unlink($vs_primary_file_tmp);
                             $vs_primary_file_tmp = $vs_primary_file_tmp . "." . $va_tmp[1];
                             if (!@copy($va_archive_files[0], $vs_primary_file_tmp)) {
                                 $this->postError(1600, _t("Couldn't extract first file from archive. There is probably a invalid character in a directory or file name inside the archive"), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                                 set_time_limit($vn_max_execution_time);
                                 if ($vb_is_fetched_file) {
                                     @unlink($vs_tmp_file);
                                 }
                                 if ($vb_is_archive) {
                                     @unlink($vs_archive);
                                     @unlink($vs_primary_file_tmp);
                                 }
                                 return false;
                             }
                             $this->_SET_FILES[$ps_field]['tmp_name'] = $vs_primary_file_tmp;
                             // prepare to join archive contents to form a better downloadable "original" than the zip/tgz archive (e.g. a multi-page tiff)
                             // to do that, we have to 'extract' the archive so that command-line utilities like *Magick can operate
                             @caRemoveDirectory(caGetTempDirPath() . '/caArchiveExtract');
                             // remove left-overs, just to be sure we don't include other files in the tiff
                             $va_archive_tmp_files = array();
                             @mkdir(caGetTempDirPath() . '/caArchiveExtract');
                             foreach ($va_archive_files as $vs_archive_file) {
                                 $vs_basename = basename($vs_archive_file);
                                 $vs_tmp_file_name = caGetTempDirPath() . '/caArchiveExtract/' . str_replace(" ", "_", $vs_basename);
                                 $va_archive_tmp_files[] = $vs_tmp_file_name;
                                 @copy($vs_archive_file, $vs_tmp_file_name);
                             }
                         }
                     }
                     if (!$vb_is_archive) {
                         // something went wrong (i.e. no valid or empty archive) -> restore previous state
                         @rename($this->_SET_FILES[$ps_field]['tmp_name'] . $vs_archive_extension, $vs_original_tmpname);
                         $this->_SET_FILES[$ps_field]['tmp_name'] = $vs_original_tmpname;
                     }
                 }
                 // ImageMagick partly relies on file extensions to properly identify images (RAW images in particular)
                 // therefore we rename the temporary file here (using the extension of the original filename, if any)
                 $va_matches = array();
                 $vb_renamed_tmpfile = false;
                 preg_match("/[.]*\\.([a-zA-Z0-9]+)\$/", $this->_SET_FILES[$ps_field]['tmp_name'], $va_matches);
                 if (!isset($va_matches[1])) {
                     // file has no extension, i.e. is probably PHP upload tmp file
                     $va_matches = array();
                     preg_match("/[.]*\\.([a-zA-Z0-9]+)\$/", $this->_SET_FILES[$ps_field]['original_filename'], $va_matches);
                     if (strlen($va_matches[1]) > 0) {
                         $va_parts = explode("/", $this->_SET_FILES[$ps_field]['tmp_name']);
                         $vs_new_filename = sys_get_temp_dir() . "/" . $va_parts[sizeof($va_parts) - 1] . "." . $va_matches[1];
                         if (!move_uploaded_file($this->_SET_FILES[$ps_field]['tmp_name'], $vs_new_filename)) {
                             rename($this->_SET_FILES[$ps_field]['tmp_name'], $vs_new_filename);
                         }
                         $this->_SET_FILES[$ps_field]['tmp_name'] = $vs_new_filename;
                         $vb_renamed_tmpfile = true;
                     }
                 }
                 $input_mimetype = $m->divineFileFormat($this->_SET_FILES[$ps_field]['tmp_name']);
                 if (!($input_type = $o_media_proc_settings->canAccept($input_mimetype))) {
                     # error - filetype not accepted by this field
                     $this->postError(1600, $input_mimetype ? _t("File type %1 not accepted by %2", $input_mimetype, $ps_field) : _t("Unknown file type not accepted by %1", $ps_field), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                     set_time_limit($vn_max_execution_time);
                     if ($vb_is_fetched_file) {
                         @unlink($vs_tmp_file);
                     }
                     if ($vb_is_archive) {
                         @unlink($vs_archive);
                         @unlink($vs_primary_file_tmp);
                     }
                     return false;
                 }
                 # ok process file...
                 if (!$m->read($this->_SET_FILES[$ps_field]['tmp_name'])) {
                     $this->errors = array_merge($this->errors, $m->errors());
                     // copy into model plugin errors
                     set_time_limit($vn_max_execution_time);
                     if ($vb_is_fetched_file) {
                         @unlink($vs_tmp_file);
                     }
                     if ($vb_is_archive) {
                         @unlink($vs_archive);
                         @unlink($vs_primary_file_tmp);
                     }
                     return false;
                 }
                 // if necessary, join archive contents to form a better downloadable "original" than the zip/tgz archive (e.g. a multi-page tiff)
                 // by this point, a backend plugin was picked using the first file of the archive. this backend is also used to prepare the new original.
                 if ($vb_is_archive && sizeof($va_archive_tmp_files) > 0) {
                     if ($vs_archive_original = $m->joinArchiveContents($va_archive_tmp_files)) {
                         // mangle filename, so that the uploaded archive.zip becomes archive.tif or archive.gif or whatever extension the Media plugin prefers
                         $va_new_original_pathinfo = pathinfo($vs_archive_original);
                         $va_archive_pathinfo = pathinfo($this->_SET_FILES[$ps_field]['original_filename']);
                         $this->_SET_FILES[$ps_field]['original_filename'] = $va_archive_pathinfo['filename'] . "." . $va_new_original_pathinfo['extension'];
                         // this is now our original, disregard the uploaded archive
                         $this->_SET_FILES[$ps_field]['tmp_name'] = $vs_archive_original;
                         // re-run mimetype detection and read on the new original
                         $m->reset();
                         $input_mimetype = $m->divineFileFormat($vs_archive_original);
                         $input_type = $o_media_proc_settings->canAccept($input_mimetype);
                         $m->read($vs_archive_original);
                     }
                     @caRemoveDirectory(caGetTempDirPath() . '/caArchiveExtract');
                 }
                 $va_media_objects['_original'] = $m;
                 // preserve center setting from any existing media
                 $va_center = null;
                 if (is_array($va_tmp = $this->getMediaInfo($ps_field))) {
                     $va_center = caGetOption('_CENTER', $va_tmp, array());
                 }
                 $media_desc = array("ORIGINAL_FILENAME" => $this->_SET_FILES[$ps_field]['original_filename'], "_CENTER" => $va_center, "_SCALE" => caGetOption('_SCALE', $va_tmp, array()), "_SCALE_UNITS" => caGetOption('_SCALE_UNITS', $va_tmp, array()), "INPUT" => array("MIMETYPE" => $m->get("mimetype"), "WIDTH" => $m->get("width"), "HEIGHT" => $m->get("height"), "MD5" => md5_file($this->_SET_FILES[$ps_field]['tmp_name']), "FILESIZE" => filesize($this->_SET_FILES[$ps_field]['tmp_name']), "FETCHED_FROM" => $vs_url_fetched_from, "FETCHED_ON" => $vn_url_fetched_on));
                 if (isset($this->_SET_FILES[$ps_field]['options']['TRANSFORMATION_HISTORY']) && is_array($this->_SET_FILES[$ps_field]['options']['TRANSFORMATION_HISTORY'])) {
                     $media_desc['TRANSFORMATION_HISTORY'] = $this->_SET_FILES[$ps_field]['options']['TRANSFORMATION_HISTORY'];
                 }
                 #
                 # Extract metadata from file
                 #
                 $media_metadata = $m->getExtractedMetadata();
                 # get versions to create
                 $va_versions = $this->getMediaVersions($ps_field, $input_mimetype);
                 $error = 0;
                 # don't process files that are not going to be processed or converted
                 # we don't want to waste time opening file we're not going to do anything with
                 # also, we don't want to recompress JPEGs...
                 $media_type = $o_media_proc_settings->canAccept($input_mimetype);
                 $version_info = $o_media_proc_settings->getMediaTypeVersions($media_type);
                 $va_default_queue_settings = $o_media_proc_settings->getMediaTypeQueueSettings($media_type);
                 if (!($va_media_write_options = $this->_FILES[$ps_field]['options'])) {
                     $va_media_write_options = $this->_SET_FILES[$ps_field]['options'];
                 }
                 # Is an "undo" version set in options?
                 if (isset($this->_SET_FILES[$ps_field]['options']['undo']) && file_exists($this->_SET_FILES[$ps_field]['options']['undo'])) {
                     if ($volume = $version_info['original']['VOLUME']) {
                         $vi = $this->_MEDIA_VOLUMES->getVolumeInformation($volume);
                         if ($vi["absolutePath"] && strlen($dirhash = $this->_getDirectoryHash($vi["absolutePath"], $this->getPrimaryKey()))) {
                             $magic = rand(0, 99999);
                             $vs_filename = $this->_genMediaName($ps_field) . "_undo_";
                             $filepath = $vi["absolutePath"] . "/" . $dirhash . "/" . $magic . "_" . $vs_filename;
                             if (copy($this->_SET_FILES[$ps_field]['options']['undo'], $filepath)) {
                                 $media_desc['_undo_'] = array("VOLUME" => $volume, "FILENAME" => $vs_filename, "HASH" => $dirhash, "MAGIC" => $magic, "MD5" => md5_file($filepath));
                             }
                         }
                     }
                 }
                 $va_process_these_versions_only = array();
                 if (isset($pa_options['these_versions_only']) && is_array($pa_options['these_versions_only']) && sizeof($pa_options['these_versions_only'])) {
                     $va_tmp = $this->_FIELD_VALUES[$ps_field];
                     foreach ($pa_options['these_versions_only'] as $vs_this_version_only) {
                         if (in_array($vs_this_version_only, $va_versions)) {
                             if (is_array($this->_FIELD_VALUES[$ps_field])) {
                                 $va_process_these_versions_only[] = $vs_this_version_only;
                             }
                         }
                     }
                     // Copy metadata for version we're not processing
                     if (sizeof($va_process_these_versions_only)) {
                         foreach (array_keys($va_tmp) as $v) {
                             if (!in_array($v, $va_process_these_versions_only)) {
                                 $media_desc[$v] = $va_tmp[$v];
                             }
                         }
                     }
                 }
                 $va_files_to_delete = array();
                 $va_queued_versions = array();
                 $queue_enabled = !sizeof($va_process_these_versions_only) && $this->getAppConfig()->get('queue_enabled') ? true : false;
                 $vs_path_to_queue_media = null;
                 foreach ($va_versions as $v) {
                     $vs_use_icon = null;
                     if (sizeof($va_process_these_versions_only) && !in_array($v, $va_process_these_versions_only)) {
                         // only processing certain versions... and this one isn't it so skip
                         continue;
                     }
                     $queue = $va_default_queue_settings['QUEUE'];
                     $queue_threshold = isset($version_info[$v]['QUEUE_WHEN_FILE_LARGER_THAN']) ? intval($version_info[$v]['QUEUE_WHEN_FILE_LARGER_THAN']) : (int) $va_default_queue_settings['QUEUE_WHEN_FILE_LARGER_THAN'];
                     $rule = isset($version_info[$v]['RULE']) ? $version_info[$v]['RULE'] : '';
                     $volume = isset($version_info[$v]['VOLUME']) ? $version_info[$v]['VOLUME'] : '';
                     $basis = isset($version_info[$v]['BASIS']) ? $version_info[$v]['BASIS'] : '';
                     if (isset($media_desc[$basis]) && isset($media_desc[$basis]['FILENAME'])) {
                         if (!isset($va_media_objects[$basis])) {
                             $o_media = new Media();
                             $basis_vi = $this->_MEDIA_VOLUMES->getVolumeInformation($media_desc[$basis]['VOLUME']);
                             if ($o_media->read($p = $basis_vi['absolutePath'] . "/" . $media_desc[$basis]['HASH'] . "/" . $media_desc[$basis]['MAGIC'] . "_" . $media_desc[$basis]['FILENAME'])) {
                                 $va_media_objects[$basis] = $o_media;
                             } else {
                                 $m = $va_media_objects['_original'];
                             }
                         } else {
                             $m = $va_media_objects[$basis];
                         }
                     } else {
                         $m = $va_media_objects['_original'];
                     }
                     $m->reset();
                     # get volume
                     $vi = $this->_MEDIA_VOLUMES->getVolumeInformation($volume);
                     if (!is_array($vi)) {
                         print "Invalid volume '{$volume}'<br>";
                         exit;
                     }
                     // Send to queue if it's too big to process here
                     if ($queue_enabled && $queue && $queue_threshold > 0 && $queue_threshold < (int) $media_desc["INPUT"]["FILESIZE"] && $va_default_queue_settings['QUEUE_USING_VERSION'] != $v) {
                         $va_queued_versions[$v] = array('VOLUME' => $volume);
                         $media_desc[$v]["QUEUED"] = $queue;
                         if ($version_info[$v]["QUEUED_MESSAGE"]) {
                             $media_desc[$v]["QUEUED_MESSAGE"] = $version_info[$v]["QUEUED_MESSAGE"];
                         } else {
                             $media_desc[$v]["QUEUED_MESSAGE"] = $va_default_queue_settings['QUEUED_MESSAGE'] ? $va_default_queue_settings['QUEUED_MESSAGE'] : _t("Media is being processed and will be available shortly.");
                         }
                         if ($pa_options['delete_old_media']) {
                             $va_files_to_delete[] = array('field' => $ps_field, 'version' => $v);
                         }
                         continue;
                     }
                     # get transformation rules
                     $rules = $o_media_proc_settings->getMediaTransformationRule($rule);
                     if (sizeof($rules) == 0) {
                         $output_mimetype = $input_mimetype;
                         $m->set("version", $v);
                         #
                         # don't process this media, just copy the file
                         #
                         $ext = $m->mimetype2extension($output_mimetype);
                         if (!$ext) {
                             $this->postError(1600, _t("File could not be copied for %1; can't convert mimetype '%2' to extension", $ps_field, $output_mimetype), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                             $m->cleanup();
                             set_time_limit($vn_max_execution_time);
                             if ($vb_is_fetched_file) {
                                 @unlink($vs_tmp_file);
                             }
                             if ($vb_is_archive) {
                                 @unlink($vs_archive);
                                 @unlink($vs_primary_file_tmp);
                                 @unlink($vs_archive_original);
                             }
                             return false;
                         }
                         if (($dirhash = $this->_getDirectoryHash($vi["absolutePath"], $this->getPrimaryKey())) === false) {
                             $this->postError(1600, _t("Could not create subdirectory for uploaded file in %1. Please ask your administrator to check the permissions of your media directory.", $vi["absolutePath"]), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                             set_time_limit($vn_max_execution_time);
                             if ($vb_is_fetched_file) {
                                 @unlink($vs_tmp_file);
                             }
                             if ($vb_is_archive) {
                                 @unlink($vs_archive);
                                 @unlink($vs_primary_file_tmp);
                                 @unlink($vs_archive_original);
                             }
                             return false;
                         }
                         if ((bool) $version_info[$v]["USE_EXTERNAL_URL_WHEN_AVAILABLE"]) {
                             $filepath = $this->_SET_FILES[$ps_field]['tmp_name'];
                             if ($pa_options['delete_old_media']) {
                                 $va_files_to_delete[] = array('field' => $ps_field, 'version' => $v);
                             }
                             $media_desc[$v] = array("VOLUME" => $volume, "MIMETYPE" => $output_mimetype, "WIDTH" => $m->get("width"), "HEIGHT" => $m->get("height"), "PROPERTIES" => $m->getProperties(), "EXTERNAL_URL" => $media_desc['INPUT']['FETCHED_FROM'], "FILENAME" => null, "HASH" => null, "MAGIC" => null, "EXTENSION" => $ext, "MD5" => md5_file($filepath));
                         } else {
                             $magic = rand(0, 99999);
                             $filepath = $vi["absolutePath"] . "/" . $dirhash . "/" . $magic . "_" . $this->_genMediaName($ps_field) . "_" . $v . "." . $ext;
                             if (!copy($this->_SET_FILES[$ps_field]['tmp_name'], $filepath)) {
                                 $this->postError(1600, _t("File could not be copied. Ask your administrator to check permissions and file space for %1", $vi["absolutePath"]), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                                 $m->cleanup();
                                 set_time_limit($vn_max_execution_time);
                                 if ($vb_is_fetched_file) {
                                     @unlink($vs_tmp_file);
                                 }
                                 if ($vb_is_archive) {
                                     @unlink($vs_archive);
                                     @unlink($vs_primary_file_tmp);
                                     @unlink($vs_archive_original);
                                 }
                                 return false;
                             }
                             if ($v === $va_default_queue_settings['QUEUE_USING_VERSION']) {
                                 $vs_path_to_queue_media = $filepath;
                             }
                             if ($pa_options['delete_old_media']) {
                                 $va_files_to_delete[] = array('field' => $ps_field, 'version' => $v, 'dont_delete_path' => $vi["absolutePath"] . "/" . $dirhash . "/" . $magic . "_" . $this->_genMediaName($ps_field) . "_" . $v, 'dont_delete_extension' => $ext);
                             }
                             if (is_array($vi["mirrors"]) && sizeof($vi["mirrors"]) > 0) {
                                 $vs_entity_key = join("/", array($this->tableName(), $ps_field, $this->getPrimaryKey(), $v));
                                 $vs_row_key = join("/", array($this->tableName(), $this->getPrimaryKey()));
                                 foreach ($vi["mirrors"] as $vs_mirror_code => $va_mirror_info) {
                                     $vs_mirror_method = $va_mirror_info["method"];
                                     $vs_queue = $vs_mirror_method . "mirror";
                                     if (!$o_tq->cancelPendingTasksForEntity($vs_entity_key)) {
                                         //$this->postError(560, _t("Could not cancel pending tasks: %1", $this->error),"BaseModel->_processMedia()");
                                         //$m->cleanup();
                                         //return false;
                                     }
                                     if ($o_tq->addTask($vs_queue, array("MIRROR" => $vs_mirror_code, "VOLUME" => $volume, "FIELD" => $ps_field, "TABLE" => $this->tableName(), "VERSION" => $v, "FILES" => array(array("FILE_PATH" => $filepath, "ABS_PATH" => $vi["absolutePath"], "HASH" => $dirhash, "FILENAME" => $magic . "_" . $this->_genMediaName($ps_field) . "_" . $v . "." . $ext)), "MIRROR_INFO" => $va_mirror_info, "PK" => $this->primaryKey(), "PK_VAL" => $this->getPrimaryKey()), array("priority" => 100, "entity_key" => $vs_entity_key, "row_key" => $vs_row_key, 'user_id' => $AUTH_CURRENT_USER_ID))) {
                                         continue;
                                     } else {
                                         $this->postError(100, _t("Couldn't queue mirror using '%1' for version '%2' (handler '%3')", $vs_mirror_method, $v, $queue), "BaseModel->_processMedia()");
                                     }
                                 }
                             }
                             $media_desc[$v] = array("VOLUME" => $volume, "MIMETYPE" => $output_mimetype, "WIDTH" => $m->get("width"), "HEIGHT" => $m->get("height"), "PROPERTIES" => $m->getProperties(), "FILENAME" => $this->_genMediaName($ps_field) . "_" . $v . "." . $ext, "HASH" => $dirhash, "MAGIC" => $magic, "EXTENSION" => $ext, "MD5" => md5_file($filepath));
                         }
                     } else {
                         $m->set("version", $v);
                         while (list($operation, $parameters) = each($rules)) {
                             if ($operation === 'SET') {
                                 foreach ($parameters as $pp => $pv) {
                                     if ($pp == 'format') {
                                         $output_mimetype = $pv;
                                     } else {
                                         $m->set($pp, $pv);
                                     }
                                 }
                             } else {
                                 if (is_array($this->_FIELD_VALUES[$ps_field]) && is_array($va_media_center = $this->getMediaCenter($ps_field))) {
                                     $parameters['_centerX'] = caGetOption('x', $va_media_center, 0.5);
                                     $parameters['_centerY'] = caGetOption('y', $va_media_center, 0.5);
                                     if ($parameters['_centerX'] < 0 || $parameters['_centerX'] > 1) {
                                         $parameters['_centerX'] = 0.5;
                                     }
                                     if ($parameters['_centerY'] < 0 || $parameters['_centerY'] > 1) {
                                         $parameters['_centerY'] = 0.5;
                                     }
                                 }
                                 if (!$m->transform($operation, $parameters)) {
                                     $error = 1;
                                     $error_msg = "Couldn't do transformation '{$operation}'";
                                     break 2;
                                 }
                             }
                         }
                         if (!$output_mimetype) {
                             $output_mimetype = $input_mimetype;
                         }
                         if (!($ext = $m->mimetype2extension($output_mimetype))) {
                             $this->postError(1600, _t("File could not be processed for %1; can't convert mimetype '%2' to extension", $ps_field, $output_mimetype), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                             $m->cleanup();
                             set_time_limit($vn_max_execution_time);
                             if ($vb_is_fetched_file) {
                                 @unlink($vs_tmp_file);
                             }
                             if ($vb_is_archive) {
                                 @unlink($vs_archive);
                                 @unlink($vs_primary_file_tmp);
                                 @unlink($vs_archive_original);
                             }
                             return false;
                         }
                         if (($dirhash = $this->_getDirectoryHash($vi["absolutePath"], $this->getPrimaryKey())) === false) {
                             $this->postError(1600, _t("Could not create subdirectory for uploaded file in %1. Please ask your administrator to check the permissions of your media directory.", $vi["absolutePath"]), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                             set_time_limit($vn_max_execution_time);
                             if ($vb_is_fetched_file) {
                                 @unlink($vs_tmp_file);
                             }
                             if ($vb_is_archive) {
                                 @unlink($vs_archive);
                                 @unlink($vs_primary_file_tmp);
                                 @unlink($vs_archive_original);
                             }
                             return false;
                         }
                         $magic = rand(0, 99999);
                         $filepath = $vi["absolutePath"] . "/" . $dirhash . "/" . $magic . "_" . $this->_genMediaName($ps_field) . "_" . $v;
                         if (!($vs_output_file = $m->write($filepath, $output_mimetype, $va_media_write_options))) {
                             $this->postError(1600, _t("Couldn't write file: %1", join("; ", $m->getErrors())), "BaseModel->_processMedia()", $this->tableName() . '.' . $ps_field);
                             $m->cleanup();
                             set_time_limit($vn_max_execution_time);
                             if ($vb_is_fetched_file) {
                                 @unlink($vs_tmp_file);
                             }
                             if ($vb_is_archive) {
                                 @unlink($vs_archive);
                                 @unlink($vs_primary_file_tmp);
                                 @unlink($vs_archive_original);
                             }
                             return false;
                             break;
                         } else {
                             if ($vs_output_file === __CA_MEDIA_VIDEO_DEFAULT_ICON__ || $vs_output_file === __CA_MEDIA_AUDIO_DEFAULT_ICON__ || $vs_output_file === __CA_MEDIA_DOCUMENT_DEFAULT_ICON__ || $vs_output_file === __CA_MEDIA_3D_DEFAULT_ICON__) {
                                 $vs_use_icon = $vs_output_file;
                             }
                         }
                         if ($v === $va_default_queue_settings['QUEUE_USING_VERSION']) {
                             $vs_path_to_queue_media = $vs_output_file;
                             $vs_use_icon = __CA_MEDIA_QUEUED_ICON__;
                         }
                         if ($pa_options['delete_old_media'] && !$error) {
                             if ($vs_old_media_path = $this->getMediaPath($ps_field, $v)) {
                                 $va_files_to_delete[] = array('field' => $ps_field, 'version' => $v, 'dont_delete_path' => $filepath, 'dont_delete_extension' => $ext);
                             }
                         }
                         if (is_array($vi["mirrors"]) && sizeof($vi["mirrors"]) > 0) {
                             $vs_entity_key = join("/", array($this->tableName(), $ps_field, $this->getPrimaryKey(), $v));
                             $vs_row_key = join("/", array($this->tableName(), $this->getPrimaryKey()));
                             foreach ($vi["mirrors"] as $vs_mirror_code => $va_mirror_info) {
                                 $vs_mirror_method = $va_mirror_info["method"];
                                 $vs_queue = $vs_mirror_method . "mirror";
                                 if (!$o_tq->cancelPendingTasksForEntity($vs_entity_key)) {
                                     //$this->postError(560, _t("Could not cancel pending tasks: %1", $this->error),"BaseModel->_processMedia()");
                                     //$m->cleanup();
                                     //return false;
                                 }
                                 if ($o_tq->addTask($vs_queue, array("MIRROR" => $vs_mirror_code, "VOLUME" => $volume, "FIELD" => $ps_field, "TABLE" => $this->tableName(), "VERSION" => $v, "FILES" => array(array("FILE_PATH" => $filepath . "." . $ext, "ABS_PATH" => $vi["absolutePath"], "HASH" => $dirhash, "FILENAME" => $magic . "_" . $this->_genMediaName($ps_field) . "_" . $v . "." . $ext)), "MIRROR_INFO" => $va_mirror_info, "PK" => $this->primaryKey(), "PK_VAL" => $this->getPrimaryKey()), array("priority" => 100, "entity_key" => $vs_entity_key, "row_key" => $vs_row_key, 'user_id' => $AUTH_CURRENT_USER_ID))) {
                                     continue;
                                 } else {
                                     $this->postError(100, _t("Couldn't queue mirror using '%1' for version '%2' (handler '%3')", $vs_mirror_method, $v, $queue), "BaseModel->_processMedia()");
                                 }
                             }
                         }
                         if ($vs_use_icon) {
                             $media_desc[$v] = array("MIMETYPE" => $output_mimetype, "USE_ICON" => $vs_use_icon, "WIDTH" => $m->get("width"), "HEIGHT" => $m->get("height"));
                         } else {
                             $media_desc[$v] = array("VOLUME" => $volume, "MIMETYPE" => $output_mimetype, "WIDTH" => $m->get("width"), "HEIGHT" => $m->get("height"), "PROPERTIES" => $m->getProperties(), "FILENAME" => $this->_genMediaName($ps_field) . "_" . $v . "." . $ext, "HASH" => $dirhash, "MAGIC" => $magic, "EXTENSION" => $ext, "MD5" => md5_file($vi["absolutePath"] . "/" . $dirhash . "/" . $magic . "_" . $this->_genMediaName($ps_field) . "_" . $v . "." . $ext));
                         }
                         $m->reset();
                     }
                 }
                 if (sizeof($va_queued_versions)) {
                     $vs_entity_key = md5(join("/", array_merge(array($this->tableName(), $ps_field, $this->getPrimaryKey()), array_keys($va_queued_versions))));
                     $vs_row_key = join("/", array($this->tableName(), $this->getPrimaryKey()));
                     if (!$o_tq->cancelPendingTasksForEntity($vs_entity_key, $queue)) {
                         // TODO: log this
                     }
                     if (!($filename = $vs_path_to_queue_media)) {
                         // if we're not using a designated not-queued representation to generate the queued ones
                         // then copy the uploaded file to the tmp dir and use that
                         $filename = $o_tq->copyFileToQueueTmp($va_default_queue_settings['QUEUE'], $this->_SET_FILES[$ps_field]['tmp_name']);
                     }
                     if ($filename) {
                         if ($o_tq->addTask($va_default_queue_settings['QUEUE'], array("TABLE" => $this->tableName(), "FIELD" => $ps_field, "PK" => $this->primaryKey(), "PK_VAL" => $this->getPrimaryKey(), "INPUT_MIMETYPE" => $input_mimetype, "FILENAME" => $filename, "VERSIONS" => $va_queued_versions, "OPTIONS" => $va_media_write_options, "DONT_DELETE_OLD_MEDIA" => $filename == $vs_path_to_queue_media ? true : false), array("priority" => 100, "entity_key" => $vs_entity_key, "row_key" => $vs_row_key, 'user_id' => $AUTH_CURRENT_USER_ID))) {
                             if ($pa_options['delete_old_media']) {
                                 foreach ($va_queued_versions as $vs_version => $va_version_info) {
                                     $va_files_to_delete[] = array('field' => $ps_field, 'version' => $vs_version);
                                 }
                             }
                         } else {
                             $this->postError(100, _t("Couldn't queue processing for version '%1' using handler '%2'", !$v, $queue), "BaseModel->_processMedia()");
                         }
                     } else {
                         $this->errors = $o_tq->errors;
                     }
                 } else {
                     // Generate preview frames for media that support that (Eg. video)
                     // and add them as "multifiles" assuming the current model supports that (ca_object_representations does)
                     if (!sizeof($va_process_these_versions_only) && ((bool) $this->_CONFIG->get('video_preview_generate_frames') || (bool) $this->_CONFIG->get('document_preview_generate_pages')) && method_exists($this, 'addFile')) {
                         if (method_exists($this, 'removeAllFiles')) {
                             $this->removeAllFiles();
                             // get rid of any previously existing frames (they might be hanging ar
                         }
                         $va_preview_frame_list = $m->writePreviews(array('width' => $m->get("width"), 'height' => $m->get("height"), 'minNumberOfFrames' => $this->_CONFIG->get('video_preview_min_number_of_frames'), 'maxNumberOfFrames' => $this->_CONFIG->get('video_preview_max_number_of_frames'), 'numberOfPages' => $this->_CONFIG->get('document_preview_max_number_of_pages'), 'frameInterval' => $this->_CONFIG->get('video_preview_interval_between_frames'), 'pageInterval' => $this->_CONFIG->get('document_preview_interval_between_pages'), 'startAtTime' => $this->_CONFIG->get('video_preview_start_at'), 'endAtTime' => $this->_CONFIG->get('video_preview_end_at'), 'startAtPage' => $this->_CONFIG->get('document_preview_start_page'), 'outputDirectory' => __CA_APP_DIR__ . '/tmp'));
                         if (is_array($va_preview_frame_list)) {
                             foreach ($va_preview_frame_list as $vn_time => $vs_frame) {
                                 $this->addFile($vs_frame, $vn_time, true);
                                 // the resource path for each frame is it's time, in seconds (may be fractional) for video, or page number for documents
                                 @unlink($vs_frame);
                                 // clean up tmp preview frame file
                             }
                         }
                     }
                 }
                 if (!$error) {
                     #
                     # --- Clean up old media from versions that are not supported in the new media
                     #
                     if ($pa_options['delete_old_media']) {
                         foreach ($this->getMediaVersions($ps_field) as $old_version) {
                             if (!is_array($media_desc[$old_version])) {
                                 $this->_removeMedia($ps_field, $old_version);
                             }
                         }
                     }
                     foreach ($va_files_to_delete as $va_file_to_delete) {
                         $this->_removeMedia($va_file_to_delete['field'], $va_file_to_delete['version'], $va_file_to_delete['dont_delete_path'], $va_file_to_delete['dont_delete_extension']);
                     }
                     # Remove old _undo_ file if defined
                     if ($vs_undo_path = $this->getMediaPath($ps_field, '_undo_')) {
                         @unlink($vs_undo_path);
                     }
                     $this->_FILES[$ps_field] = $media_desc;
                     $this->_FIELD_VALUES[$ps_field] = $media_desc;
                     $vs_serialized_data = caSerializeForDatabase($this->_FILES[$ps_field], true);
                     $vs_sql = "{$ps_field} = " . $this->quote($vs_serialized_data) . ",";
                     if (($vs_metadata_field_name = $o_media_proc_settings->getMetadataFieldName()) && $this->hasField($vs_metadata_field_name)) {
                         $this->set($vs_metadata_field_name, $media_metadata);
                         $vs_sql .= " " . $vs_metadata_field_name . " = " . $this->quote(caSerializeForDatabase($media_metadata, true)) . ",";
                     }
                     if (($vs_content_field_name = $o_media_proc_settings->getMetadataContentName()) && $this->hasField($vs_content_field_name)) {
                         $this->_FIELD_VALUES[$vs_content_field_name] = $this->quote($m->getExtractedText());
                         $vs_sql .= " " . $vs_content_field_name . " = " . $this->_FIELD_VALUES[$vs_content_field_name] . ",";
                     }
                     if (is_array($va_locs = $m->getExtractedTextLocations())) {
                         MediaContentLocationIndexer::clear($this->tableNum(), $this->getPrimaryKey());
                         foreach ($va_locs as $vs_content => $va_loc_list) {
                             foreach ($va_loc_list as $va_loc) {
                                 MediaContentLocationIndexer::index($this->tableNum(), $this->getPrimaryKey(), $vs_content, $va_loc['p'], $va_loc['x1'], $va_loc['y1'], $va_loc['x2'], $va_loc['y2']);
                             }
                         }
                         MediaContentLocationIndexer::write();
                     }
                 } else {
                     # error - invalid media
                     $this->postError(1600, _t("File could not be processed for %1: %2", $ps_field, $error_msg), "BaseModel->_processMedia()");
                     #	    return false;
                 }
                 $m->cleanup();
                 if ($vb_renamed_tmpfile) {
                     @unlink($this->_SET_FILES[$ps_field]['tmp_name']);
                 }
             } elseif (is_array($this->_FIELD_VALUES[$ps_field])) {
                 // Just set field values in SQL (assume in-place update of media metadata) because no tmp_name is set
                 // [This generally should not happen]
                 $this->_FILES[$ps_field] = $this->_FIELD_VALUES[$ps_field];
                 $vs_sql = "{$ps_field} = " . $this->quote(caSerializeForDatabase($this->_FILES[$ps_field], true)) . ",";
             }
             $this->_SET_FILES[$ps_field] = null;
         } elseif (is_array($this->_FIELD_VALUES[$ps_field])) {
             // Just set field values in SQL (usually in-place update of media metadata)
             $this->_FILES[$ps_field] = $this->_FIELD_VALUES[$ps_field];
             $vs_sql = "{$ps_field} = " . $this->quote(caSerializeForDatabase($this->_FILES[$ps_field], true)) . ",";
         }
     }
     set_time_limit($vn_max_execution_time);
     if ($vb_is_fetched_file) {
         @unlink($vs_tmp_file);
     }
     if ($vb_is_archive) {
         @unlink($vs_archive);
         @unlink($vs_primary_file_tmp);
         @unlink($vs_archive_original);
     }
     return $vs_sql;
 }
 /**
  * 
  */
 public function SearchWithinMedia()
 {
     $pn_representation_id = $this->request->getParameter('representation_id', pInteger);
     $ps_q = $this->request->getParameter('q', pString);
     $va_results = MediaContentLocationIndexer::SearchWithinMedia($ps_q, 'ca_object_representations', $pn_representation_id, 'media');
     $this->view->setVar('results', $va_results);
     $this->render('Details/object_representation_within_media_search_results_json.php');
 }
Exemple #3
0
 /**
  * Reindex PDF media by content for in-PDF search
  */
 public static function reindex_pdfs($po_opts = null)
 {
     require_once __CA_LIB_DIR__ . "/core/Db.php";
     require_once __CA_MODELS_DIR__ . "/ca_object_representations.php";
     if (!caPDFMinerInstalled()) {
         CLIUtils::addError(_t("Can't reindex PDFs: PDFMiner is not installed."));
         return false;
     }
     $o_db = new Db();
     $t_rep = new ca_object_representations();
     $t_rep->setMode(ACCESS_WRITE);
     $va_versions = array("original");
     $va_kinds = ($vs_kinds = $po_opts->getOption("kinds")) ? explode(",", $vs_kinds) : array();
     if (!is_array($va_kinds) || !sizeof($va_kinds)) {
         $va_kinds = array('all');
     }
     $va_kinds = array_map('strtolower', $va_kinds);
     if (in_array('all', $va_kinds) || in_array('ca_object_representations', $va_kinds)) {
         if (!($vn_start = (int) $po_opts->getOption('start_id'))) {
             $vn_start = null;
         }
         if (!($vn_end = (int) $po_opts->getOption('end_id'))) {
             $vn_end = null;
         }
         if ($vn_id = (int) $po_opts->getOption('id')) {
             $vn_start = $vn_id;
             $vn_end = $vn_id;
         }
         $va_ids = array();
         if ($vs_ids = (string) $po_opts->getOption('ids')) {
             if (sizeof($va_tmp = explode(",", $vs_ids))) {
                 foreach ($va_tmp as $vn_id) {
                     if ((int) $vn_id > 0) {
                         $va_ids[] = (int) $vn_id;
                     }
                 }
             }
         }
         $vs_sql_where = null;
         $va_params = array();
         if (sizeof($va_ids)) {
             $vs_sql_where = "WHERE representation_id IN (?)";
             $va_params[] = $va_ids;
         } else {
             if ($vn_start > 0 && $vn_end > 0 && $vn_start <= $vn_end || $vn_start > 0 && $vn_end == null) {
                 $vs_sql_where = "WHERE representation_id >= ?";
                 $va_params[] = $vn_start;
                 if ($vn_end) {
                     $vs_sql_where .= " AND representation_id <= ?";
                     $va_params[] = $vn_end;
                 }
             }
         }
         if ($vs_sql_where) {
             $vs_sql_where .= " AND mimetype = 'application/pdf'";
         } else {
             $vs_sql_where = " WHERE mimetype = 'application/pdf'";
         }
         $qr_reps = $o_db->query("\n\t\t\t\t\tSELECT * \n\t\t\t\t\tFROM ca_object_representations \n\t\t\t\t\t{$vs_sql_where}\n\t\t\t\t\tORDER BY representation_id\n\t\t\t\t", $va_params);
         print CLIProgressBar::start($qr_reps->numRows(), _t('Reindexing PDF representations'));
         $vn_rep_table_num = $t_rep->tableNum();
         while ($qr_reps->nextRow()) {
             $va_media_info = $qr_reps->getMediaInfo('media');
             $vs_original_filename = $va_media_info['ORIGINAL_FILENAME'];
             print CLIProgressBar::next(1, _t("Reindexing PDF %1", $vs_original_filename ? $vs_original_filename . " (" . $qr_reps->get('representation_id') . ")" : $qr_reps->get('representation_id')));
             $t_rep->load($qr_reps->get('representation_id'));
             $vn_rep_id = $t_rep->getPrimaryKey();
             $m = new Media();
             if ($m->read($vs_path = $t_rep->getMediaPath('media', 'original')) && is_array($va_locs = $m->getExtractedTextLocations())) {
                 MediaContentLocationIndexer::clear($vn_rep_table_num, $vn_rep_id);
                 foreach ($va_locs as $vs_content => $va_loc_list) {
                     foreach ($va_loc_list as $va_loc) {
                         MediaContentLocationIndexer::index($vn_rep_table_num, $vn_rep_id, $vs_content, $va_loc['p'], $va_loc['x1'], $va_loc['y1'], $va_loc['x2'], $va_loc['y2']);
                     }
                 }
                 MediaContentLocationIndexer::write();
             } else {
                 //CLIUtils::addError(_t("[Warning] No content to reindex for PDF representation: %1", $vs_path));
             }
         }
         print CLIProgressBar::finish();
     }
     if (in_array('all', $va_kinds) || in_array('ca_attributes', $va_kinds)) {
         // get all Media elements
         $va_elements = ca_metadata_elements::getElementsAsList(false, null, null, true, false, true, array(16));
         // 16=media
         $qr_c = $o_db->query("\n\t\t\t\t\tSELECT count(*) c \n\t\t\t\t\tFROM ca_attribute_values\n\t\t\t\t\tWHERE\n\t\t\t\t\t\telement_id in (?)\n\t\t\t\t", caExtractValuesFromArrayList($va_elements, 'element_id', array('preserveKeys' => false)));
         if ($qr_c->nextRow()) {
             $vn_count = $qr_c->get('c');
         } else {
             $vn_count = 0;
         }
         $t_attr_val = new ca_attribute_values();
         $vn_attr_table_num = $t_attr_val->tableNum();
         print CLIProgressBar::start($vn_count, _t('Reindexing metadata attribute media'));
         foreach ($va_elements as $vs_element_code => $va_element_info) {
             $qr_vals = $o_db->query("SELECT value_id FROM ca_attribute_values WHERE element_id = ?", (int) $va_element_info['element_id']);
             $va_vals = $qr_vals->getAllFieldValues('value_id');
             foreach ($va_vals as $vn_value_id) {
                 $t_attr_val = new ca_attribute_values($vn_value_id);
                 if ($t_attr_val->getPrimaryKey()) {
                     $t_attr_val->setMode(ACCESS_WRITE);
                     $t_attr_val->useBlobAsMediaField(true);
                     $va_media_info = $t_attr_val->getMediaInfo('value_blob');
                     $vs_original_filename = $va_media_info['ORIGINAL_FILENAME'];
                     if (!is_array($va_media_info) || $va_media_info['MIMETYPE'] !== 'application/pdf') {
                         continue;
                     }
                     print CLIProgressBar::next(1, _t("Reindexing %1", $vs_original_filename ? $vs_original_filename . " ({$vn_value_id})" : $vn_value_id));
                     $m = new Media();
                     if ($m->read($vs_path = $t_attr_val->getMediaPath('value_blob', 'original')) && is_array($va_locs = $m->getExtractedTextLocations())) {
                         MediaContentLocationIndexer::clear($vn_attr_table_num, $vn_attr_table_num);
                         foreach ($va_locs as $vs_content => $va_loc_list) {
                             foreach ($va_loc_list as $va_loc) {
                                 MediaContentLocationIndexer::index($vn_attr_table_num, $vn_value_id, $vs_content, $va_loc['p'], $va_loc['x1'], $va_loc['y1'], $va_loc['x2'], $va_loc['y2']);
                             }
                         }
                         MediaContentLocationIndexer::write();
                     } else {
                         //CLIUtils::addError(_t("[Warning] No content to reindex for PDF in metadata attribute: %1", $vs_path));
                     }
                 }
             }
         }
         print CLIProgressBar::finish();
     }
     return true;
 }
 /**
  *
  */
 static function SearchWithinMedia($ps_query, $pm_table, $pn_row_id, $ps_field)
 {
     $o_dm = Datamodel::load();
     $o_config = Configuration::load();
     $o_search_config = Configuration::load($o_config->get('search_config'));
     $vs_indexing_regex = $o_search_config->get('indexing_tokenizer_regex');
     $va_words = preg_split("![{$vs_indexing_regex}]!", $ps_query);
     $va_results = array('matches' => 0, 'results' => array(), 'locations' => array(), 'query' => $ps_query);
     if (!($t_instance = is_numeric($pm_table) ? $o_dm->getInstanceByTableNum($pm_table) : $o_dm->getInstanceByTableName($pm_table))) {
         throw new Exception(_t("Invalid table %1", $pm_table));
     }
     if (!$t_instance->load($pn_row_id)) {
         throw new Exception(_t("Invalid row %2 for table %1", $pm_table, $pn_row_id));
     }
     if (!$t_instance->hasField($ps_field)) {
         throw new Exception(_t("Invalid field %2 for table %1", $pm_table, $ps_field));
     }
     $va_media_info = $t_instance->getMediaInfo($ps_field);
     $vn_page_width = $va_media_info['INPUT']['WIDTH'];
     $vn_page_height = $va_media_info['INPUT']['HEIGHT'];
     $vn_page_image_width = $va_media_info['large']['WIDTH'];
     $vn_page_image_height = $va_media_info['large']['HEIGHT'];
     $va_hit_acc = array();
     foreach ($va_words as $vn_word_num => $vs_word) {
         $va_hits = MediaContentLocationIndexer::find($t_instance->tableName(), $pn_row_id, $vs_word);
         $va_hit_acc_matched = array();
         if (is_array($va_hits) && sizeof($va_hits)) {
             $va_pages = array();
             foreach ($va_hits as $va_hit) {
                 $x1_percent = $va_hit['x1'] / $vn_page_width;
                 $x2_percent = $va_hit['x2'] / $vn_page_width;
                 $y1_percent = ($vn_page_height - $va_hit['y2']) / $vn_page_height;
                 $y2_percent = ($vn_page_height - $va_hit['y1']) / $vn_page_height;
                 // Is this hit part of a phrase match?
                 if ($vn_word_num > 0) {
                     if (!is_array($va_hit_acc[$va_hit['p']]) || !sizeof($va_hit_acc[$va_hit['p']])) {
                         continue;
                     }
                     // if page is empty after the first word is processed then we can skip checking the rest of the words
                     $vn_i = -1;
                     foreach ($va_hit_acc[$va_hit['p']] as $vn_i => $va_existing_loc) {
                         if ($va_existing_loc['c'] >= $vn_word_num + 1) {
                             continue;
                         }
                         // Check if word is to the right of and on the same line as the previous one
                         if (abs($x1_percent - $va_existing_loc['x2']) > 0.08 || abs($y1_percent - $va_existing_loc['y1']) > 0.005) {
                             // Check if word to to the bottom and right of the previous one
                             if (abs($y2_percent - ($va_existing_loc['y2'] + ($va_existing_loc['y2'] - $va_existing_loc['y1']))) < 0.003 && $va_existing_loc['x1'] > $x1_percent) {
                                 if (isset($va_hit_acc[$va_hit['p']][$vn_i]['isNewlined']) && $va_hit_acc[$va_hit['p']][$vn_i]['isNewlined']) {
                                     continue;
                                 }
                                 $va_hit_acc[$va_hit['p']][$vn_i]['c'] = $vn_word_num + 1;
                                 $va_hit_acc[$va_hit['p']][$vn_i]['isNewlined'] = true;
                                 // word is part of phrase but on new line so create new hit for it
                                 array_splice($va_hit_acc[$va_hit['p']], $vn_i, 0, array(array('word' => "newline {$vs_word}", 'x1' => $x1_percent, 'y1' => $y1_percent, 'x2' => $x2_percent, 'y2' => $y2_percent, 'c' => $vn_word_num + 1, 'previousLine' => &$va_hit_acc[$va_hit['p']][$vn_i])));
                                 continue;
                             } else {
                                 // Word isn't near the previous one so skip the hit
                                 continue;
                             }
                         }
                         // extend selection to encompass this word in the same line as previous
                         $va_hit_acc[$va_hit['p']][$vn_i]['x2'] = $x2_percent;
                         $va_hit_acc[$va_hit['p']][$vn_i]['y2'] = $y2_percent;
                         $va_hit_acc[$va_hit['p']][$vn_i]['c'] = $vn_word_num + 1;
                         $va_hit_acc[$va_hit['p']][$vn_i]['word'] .= "extend {$vs_word}";
                         if ($va_hit_acc[$va_hit['p']][$vn_i]['previousLine']) {
                             $va_hit_acc[$va_hit['p']][$vn_i]['previousLine']['c'] = $vn_word_num + 1;
                         }
                         break;
                     }
                 } else {
                     $va_hit_acc[$va_hit['p']][] = array('word' => "add {$vs_word}", 'x1' => $x1_percent, 'y1' => $y1_percent, 'x2' => $x2_percent, 'y2' => $y2_percent, 'c' => $vn_word_num + 1);
                 }
             }
         }
         // Remove all previous hits that didn't line up with the current word
         foreach ($va_hit_acc as $vn_p => $va_hits_per_page) {
             foreach ($va_hits_per_page as $vn_i => $va_hit) {
                 if ($va_hit['c'] < $vn_word_num + 1) {
                     unset($va_hit_acc[$vn_p][$vn_i]);
                 }
             }
         }
     }
     // Copy hits into final locations list with coordinates translated into pixel values
     foreach ($va_hit_acc as $vn_p => $va_hits_per_page) {
         foreach ($va_hits_per_page as $vn_i => $va_hit) {
             if ($va_hit['c'] < sizeof($va_words)) {
                 continue;
             }
             $va_results['results'][] = $vn_p;
             $x1r = $va_hit['x1'] * $vn_page_image_width + 2;
             $x2r = $va_hit['x2'] * $vn_page_image_width + 12;
             $y1r = $va_hit['y1'] * $vn_page_image_height;
             $y2r = $va_hit['y2'] * $vn_page_image_height;
             $va_results['locations'][$vn_p][] = array('c' => $va_hit['c'], 'word' => $va_hit['word'], 'x1' => $x1r, 'y1' => $y1r, 'x2' => $x2r, 'y2' => $y2r);
         }
     }
     $va_results['matches'] = sizeof($va_results['results']);
     return $va_results;
 }