예제 #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;
 }