예제 #1
0
 /**
  * 
  *
  * @param string $ps_field
  * @param string $ps_target
  * @return bool
  */
 public function replicateMedia($ps_field, $ps_target)
 {
     global $AUTH_CURRENT_USER_ID;
     $va_targets = $this->getMediaReplicationTargets($ps_field, 'original');
     $va_target_info = $va_targets[$ps_target];
     // TODO: generalize this metadata? Perhaps let the plugin deal with it?
     $pa_data = array('title' => $va_target_info['options']['title'] ? caProcessTemplateForIDs($va_target_info['options']['title'], $this->tableNum(), array($this->getPrimaryKey()), array('requireLinkTags' => true)) : "", 'description' => $va_target_info['options']['description'] ? caProcessTemplateForIDs($va_target_info['options']['description'], $this->tableNum(), array($this->getPrimaryKey()), array('requireLinkTags' => true)) : "", 'tags' => $va_target_info['options']['tags'] ? caProcessTemplateForIDs($va_target_info['options']['tags'], $this->tableNum(), array($this->getPrimaryKey()), array('requireLinkTags' => true)) : "", 'category' => $va_target_info['options']['category']);
     $vs_version = $va_target_info['version'];
     if (!in_array($vs_version, $this->getMediaVersions($ps_field))) {
         $vs_version = 'original';
     }
     $o_replicator = new MediaReplicator();
     if ($this->getAppConfig()->get('queue_enabled')) {
         // Queue replication
         $o_tq = new TaskQueue();
         $vs_row_key = join("/", array($this->tableName(), $this->getPrimaryKey()));
         $vs_entity_key = join("/", array($this->tableName(), $ps_field, $this->getPrimaryKey(), $vs_version));
         if (!$o_tq->cancelPendingTasksForEntity($vs_entity_key)) {
             //$this->postError(560, _t("Could not cancel pending tasks: %1", $this->error),"BaseModel->replicateMedia()");
             //return false;
         }
         if ($o_tq->addTask('mediaReplication', array("FIELD" => $ps_field, "TARGET" => $ps_target, "TABLE" => $this->tableName(), "VERSION" => $vs_version, "TARGET_INFO" => $va_target_info, "DATA" => $pa_data, "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))) {
             $va_media_info = $this->getMediaInfo($ps_field);
             $va_media_info['REPLICATION_STATUS'][$ps_target] = __CA_MEDIA_REPLICATION_STATE_PENDING__;
             // pending means it's queued
             $va_media_info['REPLICATION_LOG'][$ps_target][] = array('STATUS' => __CA_MEDIA_REPLICATION_STATE_PENDING__, 'DATETIME' => time());
             $va_media_info['REPLICATION_KEYS'][$ps_target] = null;
             $this->setMediaInfo($ps_field, $va_media_info);
             $this->setMode(ACCESS_WRITE);
             $this->update();
             return null;
         } else {
             $this->postError(100, _t("Couldn't queue mirror using '%1' for version '%2'", 'mediaReplication', $vs_version), "BaseModel->replicateMedia()");
         }
         $vs_key = null;
     } else {
         // Do replication right now, in-process
         // (mark replication as started)
         $va_media_info = $this->getMediaInfo($ps_field);
         $va_media_info['REPLICATION_STATUS'][$ps_target] = __CA_MEDIA_REPLICATION_STATE_UPLOADING__;
         $va_media_info['REPLICATION_LOG'][$ps_target][] = array('STATUS' => __CA_MEDIA_REPLICATION_STATE_UPLOADING__, 'DATETIME' => time());
         $va_media_info['REPLICATION_KEYS'][$ps_target] = null;
         $this->setMediaInfo($ps_field, $va_media_info);
         $this->setMode(ACCESS_WRITE);
         $this->update(array('processingMediaForReplication' => true));
         if (!is_array($va_media_desc = $this->_FIELD_VALUES[$ps_field])) {
             throw new Exception(_t("Could not record replication status: %1 has no media description data", $ps_field));
         }
         try {
             if ($vs_key = $o_replicator->replicateMedia($this->getMediaPath($ps_field, $vs_version), $va_target_info, $pa_data)) {
                 $vn_status = $o_replicator->getReplicationStatus($va_target_info, $vs_key);
                 $va_media_info['REPLICATION_STATUS'][$ps_target] = $vn_status;
                 $va_media_info['REPLICATION_LOG'][$ps_target][] = array('STATUS' => $vn_status, 'DATETIME' => time());
                 $va_media_info['REPLICATION_KEYS'][$ps_target] = $vs_key;
                 $this->setMediaInfo($ps_field, $va_media_info);
                 $this->update(array('processingMediaForReplication' => true));
             } else {
                 $va_media_info['REPLICATION_STATUS'][$ps_target] = __CA_MEDIA_REPLICATION_STATE_ERROR__;
                 $va_media_info['REPLICATION_LOG'][$ps_target][] = array('STATUS' => __CA_MEDIA_REPLICATION_STATE_ERROR__, 'DATETIME' => time());
                 $va_media_info['REPLICATION_KEYS'][$ps_target] = null;
                 $this->setMediaInfo($ps_field, $va_media_info);
                 $this->update(array('processingMediaForReplication' => true));
                 $this->postError(3300, _t('Media replication for %1 failed', $va_target_info['name']), 'BaseModel->replicateMedia', $this->tableName() . '.' . $ps_field);
                 return null;
             }
         } catch (Exception $e) {
             $va_media_info['REPLICATION_STATUS'][$ps_target] = __CA_MEDIA_REPLICATION_STATE_ERROR__;
             $va_media_info['REPLICATION_LOG'][$ps_target][] = array('STATUS' => __CA_MEDIA_REPLICATION_STATE_ERROR__, 'DATETIME' => time());
             $va_media_info['REPLICATION_KEYS'][$ps_target] = null;
             $this->setMediaInfo($ps_field, $va_media_info);
             $this->update(array('processingMediaForReplication' => true));
             $this->postError(3300, _t('Media replication for %1 failed: %2', $va_target_info['name'], $e->getMessage()), 'BaseModel->replicateMedia', $this->tableName() . '.' . $ps_field);
             return null;
         }
     }
     return $vs_key;
 }
예제 #2
0
 /**
  * Method invoked when the task queue needs to actually execute the task. For mediaproc this means
  * actually doing the processing of media!
  *
  * Return false on failure/error and sets the error property with an error description. Returns an array
  * with processing details on success.
  *
  * @param array $pa_parameters An unserialized parameters array for the current task (eg. unserialized data from ca_task_queue.parameters)
  * @return array Returns false on error, or an array with processing details on success
  */
 public function process($pa_parameters)
 {
     $vs_table = $pa_parameters["TABLE"];
     // name of table of record we're processing
     $vs_field = $pa_parameters["FIELD"];
     // name of field in record we're processing
     $vs_pk = $pa_parameters["PK"];
     // Field name of primary key of record we're processing
     $vn_id = $pa_parameters["PK_VAL"];
     // Value of primary key
     $vs_input_mimetype = $pa_parameters["INPUT_MIMETYPE"];
     // Mimetype of input file
     $vs_input_file = $pa_parameters["FILENAME"];
     // Full path to input file
     // Array of media versions to process; keys are version names,
     // values are arrays with info about processing for that version
     // Currently the info array contains a single key, 'VOLUME', which indicates
     // the volume the version should be written to
     $va_versions = $pa_parameters["VERSIONS"];
     $va_options = $pa_parameters["OPTIONS"];
     // Array of processing options; names of options to employ are keys, settings are values
     // If true, then input media is *not* deleted
     $vb_dont_delete_original_media = (bool) $pa_parameters["DONT_DELETE_OLD_MEDIA"];
     $va_report = array('errors' => array(), 'notes' => array());
     $o_dm = Datamodel::load();
     $o_media_volumes = new MediaVolumes();
     $o_media = new Media();
     $o_media_proc_settings = new MediaProcessingSettings($vs_table, $vs_field);
     $vs_media_type = $o_media_proc_settings->canAccept($vs_input_mimetype);
     $va_version_info = $o_media_proc_settings->getMediaTypeVersions($vs_media_type);
     if (!file_exists($vs_input_file)) {
         $o_eventlog = new EventLog();
         $o_eventlog->log(array("CODE" => "DEBG", "SOURCE" => "TaskQueue->mediaproc->process()", "MESSAGE" => "Record {$vs_table}.field = file '{$vs_input_file}' did not exist; queued file was discarded"));
         $va_report['errors'][] = _t("Record %1.field = file '%2' did not exist; queued file was discarded", $vs_table, $vs_input_file);
         return $va_report;
     }
     if ($t_instance = $o_dm->getInstanceByTableName($vs_table, true)) {
         if ($t_instance->hasField($vs_field)) {
             if (!$t_instance->load($vn_id)) {
                 # record no longer exists
                 if (!$vb_dont_delete_original_media) {
                     @unlink($vs_input_file);
                 }
                 $o_eventlog = new EventLog();
                 $o_eventlog->log(array("CODE" => "DEBG", "SOURCE" => "TaskQueue->mediaproc->process()", "MESSAGE" => "Record {$vs_table}.field = {$vn_id} did not exist; queued file was discarded"));
                 $o_media->cleanup();
                 $va_report['errors'][] = _t("Record %1.field = %2 did not exist; queued file was discarded", $vs_table, $vn_id);
                 return $va_report;
             }
         } else {
             # bad field name
             $this->error->setError(551, _t("Invalid media field '%1' in table '%2'", $vs_field, $vs_table), "mediaproc->process()");
             return false;
         }
     } else {
         # bad table name
         $this->error->setError(550, _t("Invalid media field table '%1'", $vs_table), "mediaproc->process()");
         return false;
     }
     $va_old_media_to_delete = array();
     foreach ($va_versions as $v => $va_version_settings) {
         $vs_use_icon = null;
         if (!file_exists($vs_input_file)) {
             $this->error->setError(505, _t("Input media file '%1' does not exist", $vs_input_file), "mediaproc->process()");
             $o_media->cleanup();
             return false;
         }
         if (!is_readable($vs_input_file)) {
             $this->error->setError(506, _t("Denied permission to read input media file '%1'", $vs_input_file), "mediaproc->process()");
             $o_media->cleanup();
             return false;
         }
         if (!$o_media->read($vs_input_file)) {
             $this->error->setError(1600, _t("Could not process input media file '%1': %2", $vs_input_file, join('; ', $o_media->getErrors())), "mediaproc->process()");
             $o_media->cleanup();
             return false;
         }
         $vs_rule = isset($va_version_info[$v]['RULE']) ? $va_version_info[$v]['RULE'] : '';
         $va_rules = $o_media_proc_settings->getMediaTransformationRule($vs_rule);
         $va_volume_info = $o_media_volumes->getVolumeInformation($va_version_settings['VOLUME']);
         if (sizeof($va_rules) == 0) {
             $vs_output_mimetype = $vs_input_mimetype;
             #
             # don't process this media, just copy the file
             #
             $vs_ext = $o_media->mimetype2extension($vs_output_mimetype);
             if (!$vs_ext) {
                 $this->error->setError(1600, _t("File could not be copied for %1; can't convert mimetype %2 to extension", $vs_field, $vs_output_mimetype), "mediaproc->process()");
                 $o_media->cleanup();
                 return false;
             }
             if (($vs_dirhash = $this->_getDirectoryHash($va_volume_info["absolutePath"], $vn_id)) === false) {
                 $this->error->setError(1600, _t("Couldn't create subdirectory for file for %1", $vs_field), "mediaproc->process()");
                 $o_media->cleanup();
                 return false;
             }
             $vs_magic = rand(0, 99999);
             $vs_filepath = $va_volume_info["absolutePath"] . "/" . $vs_dirhash . "/" . $vs_magic . "_" . $vs_table . "_" . $vs_field . "_" . $vn_id . "_" . $v . "." . $vs_ext;
             if (!copy($vs_input_file, $vs_filepath)) {
                 $this->error->setError(504, _t("File could not be copied for %1", $vs_field), "mediaproc->process()");
                 $o_media->cleanup();
                 return false;
             }
             if (is_array($va_volume_info["mirrors"]) && sizeof($va_volume_info["mirrors"]) > 0) {
                 $entity_key = join("/", array($vs_table, $vs_field, $vn_id, $v));
                 $row_key = join("/", array($vs_table, $vn_id));
                 foreach ($va_volume_info["mirrors"] as $vs_mirror_code => $va_mirror_info) {
                     $vs_mirror_method = $va_mirror_info["method"];
                     $vs_queue = $vs_mirror_method . "mirror";
                     $tq = new TaskQueue();
                     if (!$tq->cancelPendingTasksForEntity($entity_key)) {
                         $this->error->setError(560, _t("Could not cancel pending tasks"), "mediaproc->process()");
                         $o_media->cleanup();
                         return false;
                     }
                     if ($tq->addTask($vs_queue, array("MIRROR" => $vs_mirror_code, "VOLUME" => $va_version_settings['VOLUME'], "FIELD" => $vs_field, "TABLE" => $vs_table, "VERSION" => $v, "FILES" => array(array("FILE_PATH" => $vs_filepath, "ABS_PATH" => $va_volume_info["absolutePath"], "HASH" => $vs_dirhash, "FILENAME" => $vs_magic . "_" . $vs_table . "_" . $vs_field . "_" . $vn_id . "_" . $v . "." . $vs_ext)), "MIRROR_INFO" => $va_mirror_info, "PK" => $vs_pk, "PK_VAL" => $vn_id), array("priority" => 100, "entity_key" => $entity_key, "row_key" => $row_key))) {
                         continue;
                     } else {
                         $this->error->setError(100, _t("Couldn't queue mirror using '%1' for version '%2' (handler '%3')", $vs_mirror_method, $v, $vs_queue), "mediaproc->process()");
                     }
                 }
             }
             $media_desc[$v] = array("VOLUME" => $va_version_settings['VOLUME'], "MIMETYPE" => $vs_output_mimetype, "WIDTH" => $o_media->get("width"), "HEIGHT" => $o_media->get("height"), "PROPERTIES" => $o_media->getProperties(), "FILENAME" => $vs_table . "_" . $vs_field . "_" . $vn_id . "_" . $v . "." . $vs_ext, "HASH" => $vs_dirhash, "MAGIC" => $vs_magic, "EXTENSION" => $vs_ext, "MD5" => md5_file($vs_filepath));
         } else {
             $o_media->set('version', $v);
             while (list($operation, $pa_parameters) = each($va_rules)) {
                 if ($operation === 'SET') {
                     foreach ($pa_parameters as $pp => $pv) {
                         if ($pp == 'format') {
                             $vs_output_mimetype = $pv;
                         } else {
                             $o_media->set($pp, $pv);
                         }
                     }
                 } else {
                     if (!$o_media->transform($operation, $pa_parameters)) {
                         $this->error = $o_media->errors[0];
                         $o_media->cleanup();
                         return false;
                     }
                 }
             }
             if (!$vs_output_mimetype) {
                 $vs_output_mimetype = $vs_input_mimetype;
             }
             if (!($vs_ext = $o_media->mimetype2extension($vs_output_mimetype))) {
                 $this->error->setError(1600, _t("File could not be processed for %1; can't convert mimetype %2 to extension", $vs_field, $vs_output_mimetype), "mediaproc->process()");
                 $o_media->cleanup();
                 return false;
             }
             if (($vs_dirhash = $this->_getDirectoryHash($va_volume_info["absolutePath"], $vn_id)) === false) {
                 $this->error->setError(1600, _t("Couldn't create subdirectory for file for %1", $vs_field), "mediaproc->process()");
                 $o_media->cleanup();
                 return false;
             }
             $vs_magic = rand(0, 99999);
             $vs_filepath = $va_volume_info["absolutePath"] . "/" . $vs_dirhash . "/" . $vs_magic . "_" . $vs_table . "_" . $vs_field . "_" . $vn_id . "_" . $v;
             if (!($vs_output_file = $o_media->write($vs_filepath, $vs_output_mimetype, $va_options))) {
                 $this->error = $o_media->errors[0];
                 $o_media->cleanup();
                 return false;
             } 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_use_icon = $vs_output_file;
                 } else {
                     $va_output_files[] = $vs_output_file;
                 }
             }
             if (is_array($va_volume_info["mirrors"]) && sizeof($va_volume_info["mirrors"]) > 0) {
                 $entity_key = join("/", array($vs_table, $vs_field, $vn_id, $v));
                 $row_key = join("/", array($vs_table, $vn_id));
                 foreach ($va_volume_info["mirrors"] as $vs_mirror_code => $va_mirror_info) {
                     $vs_mirror_method = $va_mirror_info["method"];
                     $vs_queue = $vs_mirror_method . "mirror";
                     $tq = new TaskQueue();
                     if (!$tq->cancelPendingTasksForEntity($entity_key)) {
                         $this->error->setError(560, _t("Could not cancel pending tasks"), "mediaproc->process()");
                         $o_media->cleanup();
                         return false;
                     }
                     if ($tq->addTask($vs_queue, array("MIRROR" => $vs_mirror_code, "VOLUME" => $va_version_settings['VOLUME'], "FIELD" => $vs_field, "TABLE" => $vs_table, "VERSION" => $v, "FILES" => array(array("FILE_PATH" => $vs_filepath, "ABS_PATH" => $va_volume_info["absolutePath"], "HASH" => $vs_dirhash, "FILENAME" => $vs_magic . "_" . $vs_table . "_" . $vs_field . "_" . $vn_id . "_" . $v . "." . $vs_ext)), "MIRROR_INFO" => $va_mirror_info, "PK" => $vs_pk, "PK_VAL" => $vn_id), array("priority" => 100, "entity_key" => $entity_key, "row_key" => $row_key))) {
                         continue;
                     } else {
                         $this->error->setError(100, _t("Couldn't queue mirror using '%1' for version '%2' (handler '%3')", $vs_mirror_method, $v, $vs_queue), "mediaproc->process()");
                     }
                 }
             }
             if ($vs_use_icon) {
                 $media_desc[$v] = array("MIMETYPE" => $vs_output_mimetype, "USE_ICON" => $vs_use_icon, "WIDTH" => $o_media->get("width"), "HEIGHT" => $o_media->get("height"));
             } else {
                 $media_desc[$v] = array("VOLUME" => $va_version_settings['VOLUME'], "MIMETYPE" => $vs_output_mimetype, "WIDTH" => $o_media->get("width"), "HEIGHT" => $o_media->get("height"), "PROPERTIES" => $o_media->getProperties(), "FILENAME" => $vs_table . "_" . $vs_field . "_" . $vn_id . "_" . $v . "." . $vs_ext, "HASH" => $vs_dirhash, "MAGIC" => $vs_magic, "EXTENSION" => $vs_ext, "MD5" => md5_file($vs_filepath . "." . $vs_ext));
             }
         }
         if (!$vb_dont_delete_original_media) {
             $vs_old_media_path = $t_instance->getMediaPath($vs_field, $v);
             if ($vs_old_media_path && $vs_filepath . "." . $vs_ext != $vs_old_media_path && $vs_input_file != vs_old_media_path) {
                 //@unlink($t_instance->getMediaPath($vs_field, $v));
                 $va_old_media_to_delete[] = $vs_old_media_path;
             }
         }
     }
     #
     # Update record
     #
     if ($t_instance->load($vn_id)) {
         if (method_exists($t_instance, "useBlobAsMediaField")) {
             // support for attributes - force field to be FT_MEDIA
             $t_instance->useBlobAsMediaField(true);
         }
         $md = $t_instance->get($vs_field);
         $va_merged_media_desc = is_array($md) ? $md : array();
         foreach ($media_desc as $vs_k => $va_v) {
             $va_merged_media_desc[$vs_k] = $va_v;
         }
         $t_instance->setMode(ACCESS_WRITE);
         $t_instance->setMediaInfo($vs_field, $va_merged_media_desc);
         $t_instance->update();
         if ($t_instance->numErrors()) {
             # get rid of files we just created
             foreach ($va_output_files as $vs_to_delete) {
                 @unlink($vs_to_delete);
             }
             $this->error->setError(560, _t("Could not update %1.%2: %3", $vs_table, $vs_field, join(", ", $t_instance->getErrors())), "mediaproc->process()");
             $o_media->cleanup();
             return false;
         }
         $va_report['notes'][] = _t("Processed file %1", $vs_input_file);
         // 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)
         $o_config = Configuration::load();
         if (((bool) $o_config->get('video_preview_generate_frames') || (bool) $o_config->get('document_preview_generate_pages')) && method_exists($t_instance, 'addFile')) {
             $o_media->read($vs_input_file);
             $va_preview_frame_list = $o_media->writePreviews(array('width' => $o_media->get("width"), 'height' => $o_media->get("height"), 'numberOfFrames' => $o_config->get('video_preview_max_number_of_frames'), 'numberOfPages' => $o_config->get('document_preview_max_number_of_pages'), 'frameInterval' => $o_config->get('video_preview_interval_between_frames'), 'pageInterval' => $o_config->get('document_preview_interval_between_pages'), 'startAtTime' => $o_config->get('video_preview_start_at'), 'endAtTime' => $o_config->get('video_preview_end_at'), 'startAtPage' => $o_config->get('document_preview_start_page'), 'outputDirectory' => __CA_APP_DIR__ . '/tmp'));
             $t_instance->removeAllFiles();
             // get rid of any previously existing frames (they might be hanging around if we're editing an existing record)
             if (is_array($va_preview_frame_list)) {
                 foreach ($va_preview_frame_list as $vn_time => $vs_frame) {
                     $t_instance->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 (!$vb_dont_delete_original_media) {
             @unlink($vs_input_file);
         }
         foreach ($va_old_media_to_delete as $vs_to_delete) {
             @unlink($vs_to_delete);
         }
         $o_media->cleanup();
         return $va_report;
     } else {
         # record no longer exists
         if (!$vb_dont_delete_original_media) {
             @unlink($vs_input_file);
         }
         $o_eventlog = new EventLog();
         $o_eventlog->log(array("CODE" => "DEBG", "SOURCE" => "TaskQueue->mediaproc->process()", "MESSAGE" => "Record {$vs_table}.field = {$vn_id} did not exist; queued file was discarded"));
         $o_media->cleanup();
         $va_report['errors'][] = _t("Record {$vs_table}.field = {$vn_id} did not exist; queued file was discarded");
         return $va_report;
     }
 }