/**
 * Removes directory $dir and recursively all content within. This means all files and subdirectories within the specified directory will be removed without any question!
 *
 * @param string $dir The path to the directory you wish to remove
 * @param bool $pb_delete_dir By default caRemoveDirectory() will remove the specified directory after delete everything within it. Setting this to false will retain the directory after removing everything inside of it, effectively "cleaning" the directory.
 * @return bool Always returns true
 */
function caRemoveDirectory($dir, $pb_delete_dir = true)
{
    if (substr($dir, -1, 1) == "/") {
        $dir = substr($dir, 0, strlen($dir) - 1);
    }
    if ($handle = opendir($dir)) {
        while (false !== ($item = readdir($handle))) {
            if ($item != "." && $item != "..") {
                if (is_dir("{$dir}/{$item}")) {
                    caRemoveDirectory("{$dir}/{$item}", true);
                } else {
                    @unlink("{$dir}/{$item}");
                }
            }
        }
        closedir($handle);
        if ($pb_delete_dir) {
            @rmdir($dir);
        }
    } else {
        return false;
    }
    return true;
}
Exemple #2
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 static function clear_caches($po_opts = null)
 {
     require_once __CA_LIB_DIR__ . "/core/Configuration.php";
     $o_config = Configuration::load();
     $ps_cache = strtolower((string) $po_opts->getOption('cache'));
     if (!in_array($ps_cache, array('all', 'app', 'usermedia'))) {
         $ps_cache = 'all';
     }
     if (in_array($ps_cache, array('all', 'app'))) {
         CLIUtils::addMessage(_t('Clearing application caches...'));
         if (is_writable($o_config->get('taskqueue_tmp_directory'))) {
             caRemoveDirectory($o_config->get('taskqueue_tmp_directory'), false);
         } else {
             CLIUtils::addError(_t('Skipping clearing of application cache because it is not writable'));
         }
     }
     if (in_array($ps_cache, array('all', 'usermedia'))) {
         if (($vs_tmp_directory = $o_config->get('ajax_media_upload_tmp_directory')) && file_exists($vs_tmp_directory)) {
             if (is_writable($vs_tmp_directory)) {
                 CLIUtils::addMessage(_t('Clearing user media cache in %1...', $vs_tmp_directory));
                 caRemoveDirectory($vs_tmp_directory, false);
             } else {
                 CLIUtils::addError(_t('Skipping clearing of user media cache because it is not writable'));
             }
         } else {
             if (!$vs_tmp_directory) {
                 CLIUtils::addError(_t('Skipping clearing of user media cache because no cache directory is configured'));
             } else {
                 CLIUtils::addError(_t('Skipping clearing of user media cache because the configured directory at %1 does not exist', $vs_tmp_directory));
             }
         }
     }
     return true;
 }
 public function performPreInstallTasks()
 {
     $o_config = Configuration::load();
     CompositeCache::flush();
     // avoid stale cache
     // create tmp dir
     if (!file_exists($o_config->get('taskqueue_tmp_directory'))) {
         if (!self::createDirectoryPath($o_config->get('taskqueue_tmp_directory'))) {
             $this->addError("Couldn't create tmp directory at " . $o_config->get('taskqueue_tmp_directory'));
             return false;
         }
     } else {
         // if already exists then remove all contents to avoid stale cache
         caRemoveDirectory($o_config->get('taskqueue_tmp_directory'), false);
     }
     // Create media directories
     $o_media_volumes = new MediaVolumes();
     $va_media_volumes = $o_media_volumes->getAllVolumeInformation();
     $vs_base_dir = $o_config->get('ca_base_dir');
     $va_dir_creation_errors = array();
     foreach ($va_media_volumes as $vs_label => $va_volume_info) {
         if (preg_match('!^' . $vs_base_dir . '!', $va_volume_info['absolutePath'])) {
             if (!self::createDirectoryPath($va_volume_info['absolutePath'])) {
                 $this->addError("Couldn't create directory for media volume {$vs_label}");
                 return false;
             }
         }
     }
     return true;
 }
Exemple #5
0
 public function performPreInstallTasks()
 {
     $o_config = Configuration::load();
     CompositeCache::flush();
     // avoid stale cache
     // create tmp dir
     if (!file_exists($o_config->get('taskqueue_tmp_directory'))) {
         if (!self::createDirectoryPath($o_config->get('taskqueue_tmp_directory'))) {
             $this->addError("Couldn't create tmp directory at " . $o_config->get('taskqueue_tmp_directory'));
             return false;
         }
     } else {
         // if already exists then remove all contents to avoid stale cache
         caRemoveDirectory($o_config->get('taskqueue_tmp_directory'), false);
     }
     // Create media directories
     $o_media_volumes = new MediaVolumes();
     $va_media_volumes = $o_media_volumes->getAllVolumeInformation();
     $vs_base_dir = $o_config->get('ca_base_dir');
     $va_dir_creation_errors = array();
     foreach ($va_media_volumes as $vs_label => $va_volume_info) {
         if (preg_match('!^' . $vs_base_dir . '!', $va_volume_info['absolutePath'])) {
             if (!self::createDirectoryPath($va_volume_info['absolutePath'])) {
                 $this->addError("Couldn't create directory for media volume {$vs_label}");
                 return false;
             }
         }
     }
     // nuke search index if we using ElasticSearch (the SqlSearch index is nuked when we drop the database)
     if ($o_config->get('search_engine_plugin') == 'ElasticSearch') {
         require_once __CA_LIB_DIR__ . '/core/Plugins/SearchEngine/ElasticSearch.php';
         $o_es = new WLPlugSearchEngineElasticSearch();
         $o_es->truncateIndex(null, true);
     }
     return true;
 }
 public static function performDatabaseSchemaUpdate()
 {
     $va_messages = array();
     if (($vn_schema_revision = self::getSchemaVersion()) < __CollectiveAccess_Schema_Rev__) {
         for ($vn_i = $vn_schema_revision + 1; $vn_i <= __CollectiveAccess_Schema_Rev__; $vn_i++) {
             if (!($o_updater = ConfigurationCheck::getVersionUpdateInstance($vn_i))) {
                 $o_updater = new GenericVersionUpdater($vn_i);
             }
             $va_methods_that_errored = array();
             // pre-update tasks
             foreach ($o_updater->getPreupdateTasks() as $vs_preupdate_method) {
                 if (!$o_updater->{$vs_preupdate_method}()) {
                     //$va_messages["error_{$vn_i}_{$vs_preupdate_method}_preupdate"] = _t("Pre-update task '{$vs_preupdate_method}' failed");
                     $va_methods_that_errored[] = $vs_preupdate_method;
                 }
             }
             if (is_array($va_new_messages = $o_updater->applyDatabaseUpdate())) {
                 $va_messages = $va_messages + $va_new_messages;
             } else {
                 $va_messages["error_{$vn_i}_sql_fail"] = _t('Could not apply database update for migration %1', $vn_i);
             }
             // post-update tasks
             foreach ($o_updater->getPostupdateTasks() as $vs_postupdate_method) {
                 if (!$o_updater->{$vs_postupdate_method}()) {
                     //$va_messages["error_{$vn_i}_{$vs_postupdate_method}_postupdate"] = _t("Post-update task '{$vs_postupdate_method}' failed");
                     $va_methods_that_errored[] = $vs_postupdate_method;
                 }
             }
             if ($vs_message = $o_updater->getPostupdateMessage()) {
                 $va_messages[(sizeof($va_methods_that_errored) ? "error" : "info") . "_{$vn_i}_{$vs_postupdate_method}_postupdate_message"] = _t("For migration %1", $vn_i) . ": {$vs_message}";
             } else {
                 if (sizeof($va_methods_that_errored)) {
                     $va_messages["error_{$vn_i}_{$vs_postupdate_method}_postupdate_message"] = _t("For migration %1", $vn_i) . ": " . _t("The following tasks did not complete: %1", join(', ', $va_methods_that_errored));
                 } else {
                     $va_messages["info_{$vn_i}_postupdate"] = _t("Applied migration %1", $vn_i);
                 }
             }
         }
     }
     // Clean cache
     caRemoveDirectory(__CA_APP_DIR__ . '/tmp', false);
     return $va_messages;
 }
 /**
  * Import SIPs from specified directory into CollectiveAccess Database
  */
 public function commandImportSIPs()
 {
     $o_conf = $this->getToolConfig();
     $t = new Timer();
     // Get locale from config and translate to numeric code
     $t_locale = new ca_locales();
     $pn_locale_id = $t_locale->localeCodeToID($o_conf->get('locale'));
     $o_log = $this->getLogger();
     $o_progress = $this->getProgressBar(0);
     if ($o_progress) {
         $o_progress->start("Starting import");
     }
     $vs_import_directory = $this->getSetting("import_directory");
     if (!is_readable($vs_import_directory)) {
         if ($o_log) {
             $o_log->logError($vs_err_msg = _t("Import directory %1 is not readable", $vs_import_directory));
         }
         if ($o_progress) {
             $o_progress->setError($vs_err_msg);
             $o_progress->finish();
         }
         return false;
     }
     if ($o_log) {
         $o_log->logDebug(_t("Started SIP import"));
     }
     //print "[1] ".$t->getTime(4)."\n";
     // Look for ZIP files or directories
     $va_files = caGetDirectoryContentsAsList($vs_import_directory, false, false, false, true);
     //print "[2] ".$t->getTime(4)."\n";
     $vn_count = 0;
     foreach ($va_files as $vs_file) {
         if (!preg_match("!\\.zip\$!i", $vs_file) && !is_dir($vs_file)) {
             continue;
         }
         $vn_count++;
     }
     $o_progress->setTotal($vn_count);
     //print "[3] ".$t->getTime(4)."\n";
     foreach ($va_files as $vs_file) {
         // Top level zips or directories
         $vb_is_dir = is_dir($vs_file);
         if (!preg_match("!\\.zip\$!i", $vs_file) && !$vb_is_dir) {
             continue;
         }
         //print "[4] ".$t->getTime(4)."\n";
         $o_progress->setMessage(_t('Processing %1', $vs_file));
         // unpack ZIP
         $va_package_files = caGetDirectoryContentsAsList($vb_is_dir ? $vs_file : 'phar://' . $vs_file . '/', false, false, false, true);
         // files in top level of directory or zip
         //foreach($va_package_files as $vs_package_path) {
         //$va_tmp = explode("/", $vs_package_path);
         //$vs_package_dir = array_pop($va_tmp);
         $va_archive_files = caGetDirectoryContentsAsList($vb_is_dir ? $vs_file : 'phar://' . $vs_file, true);
         // Does it look like a SIP?
         $vb_is_sip = false;
         $vs_idno = $vs_idno_padded = $vs_zip_path = $vs_category = null;
         $va_sides = array();
         foreach ($va_archive_files as $vs_archive_file) {
             if ($o_log) {
                 $o_log->logDebug(_t("Testing file %1 for SIP-ness", $vs_archive_file));
             }
             if (preg_match("!category.txt\$!", $vs_archive_file)) {
                 $vb_is_sip = true;
                 $va_tmp = explode("/", $vs_archive_file);
                 array_pop($va_tmp);
                 // pop category.txt
                 $vs_idno = array_pop($va_tmp);
                 $va_tmp_idno = explode("-", $vs_idno);
                 $va_tmp_idno[2] = str_pad($va_tmp_idno[2], 6, "0", STR_PAD_LEFT);
                 $vs_idno_padded = join("-", $va_tmp_idno);
                 $vs_category = strtolower(preg_replace("![^A-Z \\-a-z0-9]!", "", file_get_contents($vs_archive_file)));
                 // Translate categories
                 switch ($vs_category) {
                     case 'mixed':
                         $vs_category = 'unclassified';
                         break;
                 }
                 $vs_zip_path = join("/", $va_tmp);
                 if ($o_log) {
                     $o_log->logInfo(_t("Found SIP %1 with category %2", $vs_archive_dir, $vs_category));
                 }
                 continue;
             }
         }
         if (!$vb_is_sip) {
             if ($o_progress) {
                 $o_progress->setError(_t('File %1 is not a valid SIP', $vs_file));
             }
             if ($o_log) {
                 $o_log->logWarn(_t('File %1 is not a valid SIP', $vs_file));
             }
             continue;
         }
         //print "[5] ".$t->getTime(4)."\n";
         $va_track_audio_by_side = $va_track_xml_by_side = $va_side_audio = $va_side_xml = $va_artifacts = array();
         // Reset total # of SIPS with contents of ZIP
         $o_progress->setTotal((int) $o_progress->getTotal() - 1 + sizeof($va_archive_files));
         foreach ($va_archive_files as $vs_archive_file) {
             $vs_file_in_zip = str_replace($vb_is_dir ? "{$vs_file}" : "phar://{$vs_file}/{$vs_idno}", "", $vs_archive_file);
             $va_tmp = explode("/", $vs_file_in_zip);
             switch ($va_tmp[1]) {
                 case 'sides':
                     if ($va_tmp[4]) {
                         $vs_ext = pathinfo($va_tmp[4], PATHINFO_EXTENSION);
                         switch ($vs_ext) {
                             case 'mp3':
                                 $va_track_audio_by_side[$va_tmp[2]][] = ($vb_is_dir ? "{$vs_file}/sides/" : "phar://{$vs_file}/{$vs_idno}/sides/") . $va_tmp[2] . "/" . $va_tmp[3] . "/" . $va_tmp[4];
                                 break;
                             case 'xml':
                                 $va_track_xml_by_side[$va_tmp[2]][] = ($vb_is_dir ? "{$vs_file}/sides/" : "phar://{$vs_file}/{$vs_idno}/sides/") . $va_tmp[2] . "/" . $va_tmp[3] . "/" . $va_tmp[4];
                                 break;
                         }
                     } else {
                         if ($va_tmp[2]) {
                             $vs_ext = pathinfo($va_tmp[3], PATHINFO_EXTENSION);
                             switch ($vs_ext) {
                                 case 'mp3':
                                     $va_side_audio[$va_tmp[2]] = $va_tmp[3];
                                     break;
                                 case 'xml':
                                     if (preg_match('!meta!', $va_tmp[3])) {
                                         $va_side_xml[$va_tmp[2]] = ($vb_is_dir ? "{$vs_file}/sides/" : "phar://{$vs_file}/{$vs_idno}/sides/") . $va_tmp[2] . "/" . $va_tmp[3];
                                     }
                                     break;
                             }
                         }
                     }
                     break;
                 case 'artifacts':
                     if (sizeof($va_tmp) == 3) {
                         $va_artifacts[] = ($vb_is_dir ? "{$vs_file}/artifacts/" : "phar://{$vs_file}/{$vs_idno}/artifacts/") . $va_tmp[2];
                     }
                     break;
             }
         }
         //print "[6] ".$t->getTime(4)."\n";
         //print_R($va_side_xml); die;
         // Process
         // Create parent record
         $vn_image_count = 0;
         $o_progress->next(_t('Processing %1', $vs_archive_file));
         $o_progress->setMessage(_t("Creating reel for %1", $vs_idno));
         $va_ids = ca_objects::find(array('idno' => $vs_idno, 'deleted' => 0, 'type_id' => 'reel'), array('returnAs' => 'ids'));
         if (!is_array($va_ids) || !sizeof($va_ids)) {
             $t_object = new ca_objects();
             $t_object->setMode(ACCESS_WRITE);
             $t_object->set(array('status' => 5, 'type_id' => 'reel', 'idno' => $vs_idno));
             $vn_object_id = $t_object->insert();
             if ($t_object->numErrors()) {
                 if ($o_log) {
                     $o_log->logError(_t("Could not add reel record %1: %2", $vs_idno, join("; ", $t_object->getErrors())));
                 }
             }
             $t_object->addLabel(array('name' => $vs_idno_padded), $pn_locale_id, null, true);
             if ($t_object->numErrors()) {
                 if ($o_log) {
                     $o_log->logError(_t("Could not add label to reel record %1: %2", $vs_idno, join("; ", $t_object->getErrors())));
                 }
             }
             if ($t_object->numErrors()) {
                 if ($o_log) {
                     $o_log->logError(_t("Could not add artifct media %1 to reel %2: %3", pathinfo($vs_artifact, PATHINFO_BASENAME), $vs_idno, join("; ", $t_object->getErrors())));
                 }
             }
         } else {
             if ($o_log) {
                 $o_log->logDebug(_t("Found existing reel record %1 for %2", $va_ids[0], $vs_idno));
             }
             $t_object = new ca_objects($vn_object_id = $va_ids[0]);
             $t_object->setMode(ACCESS_WRITE);
             $t_object->set('status', 5);
             $t_object->update();
             if (($vn_image_count = $t_object->numberOfRepresentationsOfClass("image")) > 0) {
                 // skip reels that have images already
                 //if ($o_log) { $o_log->logDebug(_t("Skipped existing reel record %1 because it already has %2 images", $vs_idno, $vn_image_count)); }
                 //if ($o_progress) { $o_progress->setError(_t("Skipped existing reel record %1 because it already has %2 images", $vs_idno, $vn_image_count)); }
                 //continue;
             }
             $t_object->setMode(ACCESS_WRITE);
         }
         //print "[7] ".$t->getTime(4)."\n";
         if ($vn_image_count > 0) {
             $t_object->removeAllRepresentations();
             if ($t_object->numErrors()) {
                 if ($o_log) {
                     $o_log->logError(_t("Could not add remove existing media from reel %1: %2", $vs_idno, join("; ", $t_object->getErrors())));
                 }
             }
         }
         $o_progress->setMessage(_t("Linking artifact images for %1", $vs_idno));
         foreach ($va_artifacts as $vs_artifact) {
             $o_progress->next(_t('Processing artifact image %1', $vs_artifact));
             copy($vs_artifact, $vs_tmp_filepath = "/tmp/pbc" . md5(time()));
             $t_object->addRepresentation($vs_tmp_filepath, 'front', $pn_locale_id, 0, 1, 1);
             $o_progress->setMessage(_t("Added artifact image %1 for %2", $vs_artifact, $vs_idno));
             if ($t_object->numErrors()) {
                 if ($o_log) {
                     $o_log->logError(_t("Could not add artifact media %1 to reel %2: %3", pathinfo($vs_artifact, PATHINFO_BASENAME), $vs_idno, join("; ", $t_object->getErrors())));
                 }
             }
             // remove tmp file
             @unlink($vs_tmp_filepath);
         }
         //
         // Add XML
         //
         $o_progress->setMessage(_t("Adding XML for %1", $vs_track_idno));
         $t_object->removeAttributes('sip_metadata');
         foreach ($va_side_xml as $vs_side => $vs_xml_path) {
             copy($vs_xml_path, $vs_xml_tmppath = "/tmp/" . pathinfo($vs_xml_path, PATHINFO_BASENAME));
             $o_progress->next(_t('Processing XML %1', $vs_xml_tmppath));
             $t_object->addAttribute(array('sip_metadata' => $vs_xml_tmppath, 'locale_id' => $pn_locale_id), 'sip_metadata');
             $t_object->update();
             if ($t_object->numErrors()) {
                 if ($o_log) {
                     $o_log->logError(_t("Could not import XML file %1 into reel %2: %3", pathinfo($va_track_xml_by_side[$vs_side][$vn_i], PATHINFO_BASENAME), $vs_track_idno, join("; ", $t_object->getErrors())));
                 }
             }
         }
         //print "[8] ".$t->getTime(4)."\n";
         // Create tracks
         $o_progress->setMessage(_t("Creating tracks for %1", $vs_idno));
         foreach ($va_track_audio_by_side as $vs_side => $va_tracks) {
             foreach ($va_tracks as $vn_i => $vs_audio) {
                 $o_progress->next(_t('Processing track %1', $vs_audio));
                 $vs_ext = pathinfo($vs_audio, PATHINFO_EXTENSION);
                 copy($vs_audio, $vs_tmp_filepath = "/tmp/pbc" . md5(time()) . ".{$vs_ext}");
                 $vs_track_idno = pathinfo($vs_audio, PATHINFO_FILENAME);
                 // Does track already exist?
                 $va_track_ids = ca_objects::find(array('idno' => $vs_track_idno, 'deleted' => 0), array('returnAs' => 'ids'));
                 if (!is_array($va_track_ids) || !sizeof($va_track_ids)) {
                     $o_progress->setMessage(_t("Creating %2 track for %1", $vs_track_idno, $vs_category));
                     // Create track record
                     $t_track = new ca_objects();
                     $t_track->setMode(ACCESS_WRITE);
                     $va_tmp = explode("/", $vs_audio);
                     $vs_category = strtolower(str_replace(' ', '_', $vs_category));
                     $t_track->set(array('type_id' => $vs_category, 'idno' => $vs_track_idno, 'parent_id' => $vn_object_id));
                     $vn_track_id = $t_track->insert();
                     if ($t_track->numErrors()) {
                         if ($o_log) {
                             $o_log->logError(_t("Could not add track %1: %2", $vs_track_idno, join("; ", $t_track->getErrors())));
                         }
                     }
                     $t_track->addLabel(array('name' => "{$vs_track_idno}"), $pn_locale_id, null, true);
                     if ($t_track->numErrors()) {
                         if ($o_log) {
                             $o_log->logError(_t("Could not add label to track %1: %2", $vs_track_idno, join("; ", $t_track->getErrors())));
                         }
                     }
                 } else {
                     if ($o_log) {
                         $o_log->logDebug(_t("Found existing track record %1 for %2", $va_track_ids[0], $vs_track_idno));
                     }
                     $t_track = new ca_objects($va_track_ids[0]);
                     if (($vn_audio_count = $t_track->numberOfRepresentationsOfClass("audio")) > 0) {
                         // skip tracks that have audio already
                         //if ($o_log) { $o_log->logDebug(_t("Skip existing track record %1 because it already has %2 audio files", $vs_track_idno, $vn_audio_count)); }
                         //continue;
                         $t_track->removeAllRepresentations();
                     }
                 }
                 //
                 // Add track audio
                 //
                 $o_progress->setMessage(_t("Adding track audio for %1", $vs_track_idno));
                 $t_track->addRepresentation($vs_tmp_filepath, 'front', $pn_locale_id, 0, 1, 1);
                 if ($t_track->numErrors()) {
                     if ($o_log) {
                         $o_log->logError($vs_err_msg = _t("Could not import audio file %1 into track %2: %3", pathinfo($vs_audio, PATHINFO_BASENAME), $vs_track_idno, join("; ", $t_track->getErrors())));
                     }
                     if ($o_progress) {
                         $o_progress->setError($vs_err_msg);
                     }
                 }
                 // Remove tmp files
                 @unlink($vs_tmp_filepath);
                 @unlink($vs_xml_tmppath);
             }
         }
         //print "[9] ".$t->getTime(4)."\n";
         //}
         if ((bool) $this->getSetting('delete_after_import')) {
             $o_progress->setMessage(_t("Deleting SIP %1", $vs_file));
             if ($vb_is_dir) {
                 caRemoveDirectory($vs_file);
             } else {
                 @unlink($vs_file);
             }
         }
     }
     //print "[10] ".$t->getTime(4)."\n";
     $o_progress->finish("Completed processing");
     if ($o_log) {
         $o_log->logDebug(_t("Ended SIP import"));
     }
     //print "DONE\n\n";
     return true;
 }
 public function parse($ps_filepath)
 {
     if (!function_exists("simplexml_load_file")) {
         return null;
     }
     $this->init();
     // Is file a KMZ file?
     $o_unzip = new UnZipFile($ps_filepath);
     $vs_tmp_dirname = tempnam(caGetTempDirPath(), 'kml');
     @unlink($vs_tmp_dirname);
     @mkdir($vs_tmp_dirname);
     if ($o_unzip->extract($vs_tmp_dirname, 'doc.kml')) {
         if (file_exists($vs_tmp_dirname . '/doc.kml')) {
             $ps_filepath = $vs_tmp_dirname . '/doc.kml';
         } else {
             return false;
         }
     }
     $o_kml = @simplexml_load_file($ps_filepath);
     if (!$o_kml) {
         return false;
     }
     caRemoveDirectory($vs_tmp_dirname, true);
     //
     // Placemarks
     //
     $va_namespaces = $o_kml->getNamespaces(true);
     foreach ($va_namespaces as $vs_prefix => $vs_schema_url) {
         $o_kml->registerXPathNamespace($vs_prefix ? $vs_prefix : 'g', $vs_schema_url);
     }
     $va_placemarks = $o_kml->xpath('//g:Placemark');
     $this->opa_filedata['placemarks'] = array();
     foreach ($va_placemarks as $va_placemark) {
         $vs_name = '' . $va_placemark->name[0];
         $vs_description = '' . $va_placemark->description[0];
         if (isset($va_placemark->Point)) {
             $vs_coord = $va_placemark->Point->coordinates;
             $va_tmp = explode(',', $vs_coord);
             $this->opa_filedata['placemarks'][] = array('name' => $vs_name, 'type' => 'POINT', 'description' => $vs_description, 'latitude' => $va_tmp[1], 'longitude' => $va_tmp[0]);
         } else {
             if (isset($va_placemark->LineString) && isset($va_placemark->LineString->coordinates)) {
                 $vs_coords = trim($va_placemark->LineString->coordinates);
                 $va_coord_lines = preg_split("/[ \n\r]+/", $vs_coords);
             } else {
                 if (isset($va_placemark->Polygon) && isset($va_placemark->Polygon->outerBoundaryIs) && isset($va_placemark->Polygon->outerBoundaryIs->LinearRing) && isset($va_placemark->Polygon->outerBoundaryIs->LinearRing->coordinates)) {
                     $vs_coords = trim($va_placemark->Polygon->outerBoundaryIs->LinearRing->coordinates);
                     $va_coord_lines = preg_split("/[ \n\r]+/", $vs_coords);
                 }
             }
             if (sizeof($va_coord_lines) > 0) {
                 $va_coord_list = array();
                 foreach ($va_coord_lines as $vs_coord_line) {
                     $va_tmp = explode(',', $vs_coord_line);
                     $va_coord_list[] = array('latitude' => $va_tmp[1], 'longitude' => $va_tmp[0]);
                 }
                 $this->opa_filedata['placemarks'][] = array('name' => $vs_name, 'type' => 'PATH', 'description' => $vs_description, 'coordinates' => $va_coord_list);
             }
         }
     }
     return true;
 }
 /**
  * Applies specified update to system
  *
  * @param int $pn_version Version number of update to apply
  * @param array $pa_options Array of options. Supported options are:
  *		cleanCache = Remove all application caches after database update if true. Default is false.
  * @return bool
  */
 static function performDatabaseUpdate($pn_version, $pa_options = null)
 {
     if (($pn_version = (int) $pn_version) <= 0) {
         return null;
     }
     $va_messages = array();
     $t = new Transaction();
     $o_db = $t->getDb();
     if (!file_exists(__CA_BASE_DIR__ . "/support/sql/migrations/{$pn_version}.sql")) {
         return null;
     }
     $o_handle = fopen(__CA_BASE_DIR__ . "/support/sql/migrations/{$pn_version}.sql", "r");
     $vn_query_total_nb = 0;
     $vs_query = '';
     while (!feof($o_handle)) {
         $vs_line = fgets($o_handle, 8128);
         // $vs_query gets a concat of lines while a ; is not met
         $vs_query .= $vs_line;
         // Reading 1 character before the EOL
         $vs_before_eol = substr(rtrim($vs_line), -1);
         if ($vs_before_eol == ';') {
             //If the line ends with a ; then we will take all what's before and execute it
             //Counts the number of requests contained in the SQL file
             $vn_query_total_nb++;
             //Launching the query
             $o_db->query($vs_query);
             if ($o_db->numErrors() > 0) {
                 // temp array to catch the errors
                 $va_error_array_for_printing = $o_db->getErrors();
                 $va_messages['error_' . $pn_version] = _t("Error applying database migration %1: %2; error was at query %3; query was %4", $pn_version, join('; ', $va_error_array_for_printing), $vn_query_total_nb, $vs_query);
                 $o_db->clearErrors();
                 $t->rollback();
                 return $va_messages;
             }
             // Reset variable
             $vs_query = '';
         }
         $t->commit();
     }
     if (isset($pa_options['cleanCache']) && $pa_options['cleanCache']) {
         // Clean cache
         caRemoveDirectory(__CA_APP_DIR__ . '/tmp', false);
     }
     return $va_messages;
 }