Index: branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php =================================================================== diff -u -N -r15729 -r15733 --- branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php (.../upload_formatter.php) (revision 15729) +++ branches/5.2.x/core/kernel/utility/formatters/upload_formatter.php (.../upload_formatter.php) (revision 15733) @@ -1,6 +1,6 @@ _getMaxFiles($options); + $pending_actions = $object->getPendingActions(); + $files_to_delete = $this->_getFilesToDelete($object); - // don't delete uploaded file, when it's name matches delete file name - $files_to_delete = Array (); - $var_name = $object->getPendingActionVariableName(); - $schedule = $this->Application->RecallVar($var_name); - $schedule = $schedule ? unserialize($schedule) : Array (); - - foreach ($schedule as $data) { - if ( $data['action'] == 'delete' ) { - $files_to_delete[] = $data['file']; - } - } - for ($i = 0; $i < min($max_files, count($swf_uploaded_ids)); $i++) { + // don't delete uploaded file, when it's name matches delete file name $real_name = $this->_getRealFilename($swf_uploaded_names[$i], $options, $object, $files_to_delete); $file_name = $this->FullPath . $real_name; @@ -146,13 +137,39 @@ @chmod($file_name, 0666); $fret[] = getArrayValue($options, 'upload_dir') ? $real_name : $this->DestinationPath . $real_name; + $pending_actions[] = Array ( + 'action' => 'make_live', 'id' => $object->GetID(), 'field' => $field_name, 'file' => $file_name + ); + $this->_renameFileInSorting($swf_uploaded_names[$i], $real_name); } + $object->setPendingActions($pending_actions); + return $this->_sortFiles(array_merge($existing, $fret)); } /** + * Returns files, scheduled for deleting + * + * @param kDBItem $object + * @return Array + * @access protected + */ + protected function _getFilesToDelete($object) + { + $ret = Array (); + + foreach ($object->getPendingActions() as $data) { + if ( $data['action'] == 'delete' ) { + $ret[] = $data['file']; + } + } + + return $ret; + } + + /** * Handles regular file upload * * @param string|Array $value @@ -354,6 +371,8 @@ function getSingleFormat($format) { $single_mapping = Array ( + 'file_raw_urls' => 'raw_url', + 'file_display_names' => 'display_name', 'file_urls' => 'full_url', 'file_paths' => 'full_path', 'file_sizes' => 'file_size', @@ -386,7 +405,7 @@ $format = isset($options['format']) ? $options['format'] : false; } - if ( $format && preg_match('/(file_urls|file_paths|file_names|file_sizes|img_sizes|files_resized|wms)(.*)/', $format, $regs) ) { + if ( $format && preg_match('/(file_raw_urls|file_display_names|file_urls|file_paths|file_names|file_sizes|img_sizes|files_resized|wms)(.*)/', $format, $regs) ) { if ( !$value || $format == 'file_names' ) { // storage format matches display format OR no value return $value; @@ -410,8 +429,7 @@ return $value; } - // force direct links for case, when non-swf uploader is used - return $this->GetFormatted($tc_value, $field_name, $object, $format, true); + return $this->GetFormatted($tc_value, $field_name, $object, $format); } /** @@ -421,10 +439,9 @@ * @param string $field_name * @param kDBItem $object * @param string $format - * @param bool $force_direct_links * @return string */ - function GetFormatted($value, $field_name, &$object, $format = NULL, $force_direct_links = NULL) + function GetFormatted($value, $field_name, &$object, $format = NULL) { if ( !$format || !$value ) { return $value; @@ -441,13 +458,16 @@ } switch ($format) { + case 'display_name': + return kUtil::removeTempExtension($value); + break; + + case 'raw_url': + return $this->fileHelper->pathToUrl(FULL_PATH . $upload_dir . $value); + break; + case 'full_url': - if ( isset($force_direct_links) ) { - $direct_links = $force_direct_links; - } - else { - $direct_links = isset($options['direct_links']) ? $options['direct_links'] : false; - } + $direct_links = isset($options['direct_links']) ? $options['direct_links'] : true; if ( $direct_links ) { return $this->fileHelper->pathToUrl(FULL_PATH . $upload_dir . $value); @@ -583,10 +603,9 @@ * @param string $field_name * @param kDBItem $object * @param string $format - * @param bool $force_direct_links * @return string */ - function GetFormatted($value, $field_name, &$object, $format = NULL, $force_direct_links = NULL) + function GetFormatted($value, $field_name, &$object, $format = NULL) { if ( $format == 'img_size' ) { $options = $object->GetFieldOptions($field_name); @@ -596,6 +615,6 @@ return ' ' . $image_info[3]; } - return parent::GetFormatted($value, $field_name, $object, $format, $force_direct_links); + return parent::GetFormatted($value, $field_name, $object, $format); } } \ No newline at end of file Index: branches/5.2.x/core/kernel/globals.php =================================================================== diff -u -N -r15725 -r15733 --- branches/5.2.x/core/kernel/globals.php (.../globals.php) (revision 15725) +++ branches/5.2.x/core/kernel/globals.php (.../globals.php) (revision 15733) @@ -1,6 +1,6 @@ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', @@ -636,7 +636,7 @@ */ public static function mimeContentTypeByExtension($file) { - $file_extension = mb_strtolower( pathinfo($file, PATHINFO_EXTENSION) ); + $file_extension = mb_strtolower(pathinfo(self::removeTempExtension($file), PATHINFO_EXTENSION)); $mapping = '(xls:application/excel)(hqx:application/macbinhex40)(doc,dot,wrd:application/msword)(pdf:application/pdf) (pgp:application/pgp)(ps,eps,ai:application/postscript)(ppt:application/powerpoint)(rtf:application/rtf) @@ -662,6 +662,19 @@ } /** + * Strips ".tmp" suffix (added by flash uploader) from a filename + * + * @param string $file + * @return string + * @access public + * @static + */ + public static function removeTempExtension($file) + { + return preg_replace('/(_[\d]+)?\.tmp$/', '', $file); + } + + /** * Return param value and removes it from params array * * @param string $name Index: branches/5.2.x/core/admin_templates/js/uploader/upload_manager.js =================================================================== diff -u -N -r15729 -r15733 --- branches/5.2.x/core/admin_templates/js/uploader/upload_manager.js (.../upload_manager.js) (revision 15729) +++ branches/5.2.x/core/admin_templates/js/uploader/upload_manager.js (.../upload_manager.js) (revision 15733) @@ -119,7 +119,7 @@ var $uploader = this._Uploaders[uploader_id]; $.get( - $uploader.deleteURL.replace('#FILE#', encodeURIComponent(fname)).replace('#FIELD#', $uploader.params.field), + $uploader.deleteURL.replace('#FILE#', encodeURIComponent(fname)).replace('#FIELD_ID#', $uploader.id), function ($data) { $uploader.removeFile({id:fname}); $uploader.deleted.push(fname); Index: branches/5.2.x/core/kernel/db/dbitem.php =================================================================== diff -u -N -r15729 -r15733 --- branches/5.2.x/core/kernel/db/dbitem.php (.../dbitem.php) (revision 15729) +++ branches/5.2.x/core/kernel/db/dbitem.php (.../dbitem.php) (revision 15733) @@ -1,6 +1,6 @@ Application->GetTopmostWid($this->Prefix); return $this->Prefix . '_file_pending_actions' . $window_id; } /** + * Returns pending actions + * + * @param mixed $id + * @return Array + * @access public + */ + public function getPendingActions($id = null) + { + if ( !isset($id) ) { + $id = $this->GetID(); + } + + $pending_actions = $this->Application->RecallVar($this->_getPendingActionVariableName()); + $pending_actions = $pending_actions ? unserialize($pending_actions) : Array (); + + if ( is_numeric($id) ) { + // filter by given/current id + $ret = Array (); + + foreach ($pending_actions as $pending_action) { + if ( $pending_action['id'] == $id ) { + $ret[] = $pending_action; + } + } + + return $ret; + } + + return $pending_actions; + } + + /** + * Sets new pending actions + * + * @param Array|null $new_pending_actions + * @param mixed $id + * @return void + * @access public + */ + public function setPendingActions($new_pending_actions = null, $id = null) + { + if ( !isset($new_pending_actions) ) { + $new_pending_actions = Array (); + } + + if ( !isset($id) ) { + $id = $this->GetID(); + } + + $pending_actions = Array (); + $old_pending_actions = $this->getPendingActions(true); + + if ( is_numeric($id) ) { + // remove old actions for this id + foreach ($old_pending_actions as $pending_action) { + if ( $pending_action['id'] != $id ) { + $pending_actions[] = $pending_action; + } + } + + // add new actions for this id + $pending_actions = array_merge($pending_actions, $new_pending_actions); + } + else { + $pending_actions = $new_pending_actions; + } + + // save changes + $var_name = $this->_getPendingActionVariableName(); + + if ( !$pending_actions ) { + $this->Application->RemoveVar($var_name); + } + else { + $this->Application->StoreVar($var_name, serialize($pending_actions)); + } + } + + /** * Allows to skip certain fields from getting into sql queries * * @param string $field_name Index: branches/5.2.x/core/admin_templates/js/uploader/uploader.js =================================================================== diff -u -N -r15729 -r15733 --- branches/5.2.x/core/admin_templates/js/uploader/uploader.js (.../uploader.js) (revision 15729) +++ branches/5.2.x/core/admin_templates/js/uploader/uploader.js (.../uploader.js) (revision 15733) @@ -265,14 +265,16 @@ } Uploader.prototype.isImage = function($filename) { - $filename.match(/\.([^.]*)$/); + this.removeTempExtension($filename).match(/\.([^.]*)$/); + var $ext = RegExp.$1.toLowerCase(); return $ext.match(/^(bmp|gif|jpg|jpeg|png)$/); } Uploader.prototype.getFileIcon = function($filename) { - $filename.match(/\.([^.]*)$/); + this.removeTempExtension($filename).match(/\.([^.]*)$/); + var $ext = RegExp.$1.toLowerCase(), $ext_overrides = { 'doc': '^(docx|dotx|docm|dotm)$', @@ -297,10 +299,14 @@ return this.IconPath + '/' + $icon + '.gif'; } +Uploader.prototype.removeTempExtension = function ($file) { + return $file.replace(/(_[\d]+)?\.tmp$/, ''); +} + Uploader.prototype.getQueueElement = function($file) { var $ret = ''; var $icon_image = this.getFileIcon($file.name); - var $file_label = $file.name + ' (' + this._formatSize($file.size) + ')'; + var $file_label = this.removeTempExtension($file.name) + ' (' + this._formatSize($file.size) + ')'; var $need_preview = false; if (isset($file.uploaded)) { @@ -533,7 +539,7 @@ this.files[$file_index].uploaded = 1; this.files[$file_index].progress = 100; this.files[$file_index].temp = 1; - this.files[$file_index].url = this.params.tmp_url.replace('#ID#', file.id).replace('#FILE#', encodeURIComponent(file.name)).replace('#FIELD#', this.params.field); + this.files[$file_index].url = this.params.tmp_url.replace('#ID#', file.id).replace('#FILE#', encodeURIComponent(this.files[$file_index].name)).replace('#FIELD#', this.params.field); this.updateInfo($file_index); } Index: branches/5.2.x/core/kernel/db/db_event_handler.php =================================================================== diff -u -N -r15729 -r15733 --- branches/5.2.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 15729) +++ branches/5.2.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 15733) @@ -1,6 +1,6 @@ getEventParam('parent_event'); + /* @var $parent_event kEvent */ if ( is_object($parent_event) ) { $object->setParentEvent($parent_event); @@ -1818,7 +1819,7 @@ $object = $event->getObject(Array('skip_autoload' => true)); /* @var $object kDBItem */ - $this->Application->RemoveVar($object->getPendingActionVariableName()); + $object->setPendingActions(null, true); $changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix); $this->Application->RemoveVar($changes_var_name); @@ -2402,7 +2403,7 @@ /* @var $object kDBItem */ if ( !$object->IsTempTable() ) { - $this->_proccessPendingActions($event); + $this->_processPendingActions($event); } } @@ -2431,7 +2432,7 @@ /* @var $object kDBItem */ if ( !$object->IsTempTable() ) { - $this->_proccessPendingActions($event); + $this->_processPendingActions($event); } } @@ -2585,7 +2586,13 @@ */ protected function OnAfterCopyToLive(kEvent $event) { - $this->_proccessPendingActions($event); + $object = $event->getObject(); + /* @var $object kDBItem */ + + $object->SwitchToLive(); + $object->Load($event->getEventParam('id')); + + $this->_processPendingActions($event); } /** @@ -2595,24 +2602,45 @@ * @return void * @access protected */ - protected function _proccessPendingActions(kEvent $event) + protected function _processPendingActions(kEvent $event) { $object = $event->getObject(); /* @var $object kDBItem */ - $var_name = $object->getPendingActionVariableName(); - $schedule = $this->Application->RecallVar($var_name); + $update_required = false; + $temp_id = $event->getEventParam('temp_id'); + $id = $temp_id !== false ? $temp_id : $object->GetID(); - if ( $schedule ) { - $schedule = unserialize($schedule); - - foreach ($schedule as $data) { - if ( $data['action'] == 'delete' ) { + foreach ($object->getPendingActions($id) as $data) { + switch ( $data['action'] ) { + case 'delete': unlink($data['file']); - } + break; + + case 'make_live': + $file_helper = $this->Application->recallObject('FileHelper'); + /* @var $file_helper FileHelper */ + + $old_name = basename($data['file']); + $new_name = $file_helper->ensureUniqueFilename(dirname($data['file']), kUtil::removeTempExtension($old_name)); + rename($data['file'], dirname($data['file']) . '/' . $new_name); + + $db_value = $object->GetDBField($data['field']); + $object->SetDBField($data['field'], str_replace($old_name, $new_name, $db_value)); + $update_required = true; + break; + + default: + trigger_error('Unsupported pending action "' . $data['action'] . '" for "' . $event->getPrefixSpecial() . '" unit', E_USER_WARNING); + break; } + } - $this->Application->RemoveVar($var_name); + // remove pending actions before updating to prevent recursion + $object->setPendingActions(); + + if ( $update_required ) { + $object->Update(); } } @@ -2970,7 +2998,7 @@ */ public function getCustomExportColumns(kEvent $event) { - return Array(); + return Array (); } /** @@ -3123,21 +3151,13 @@ } $tmp_path = WRITEABLE . '/tmp/'; - $fname = $value['name']; + $filename = $value['name'] . '.tmp'; $id = $this->Application->GetVar('id'); if ( $id ) { - $fname = $id . '_' . $fname; + $filename = $id . '_' . $filename; } - $field_name = $this->Application->GetVar('field'); - $fields = $this->Application->getUnitOption($event->Prefix, 'Fields'); - $virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields'); - $field_options = array_key_exists($field_name, $fields) ? $fields[$field_name] : $virtual_fields[$field_name]; - - $upload_dir = $field_options['upload_dir']; - $storage_format = array_key_exists('storage_format', $field_options) ? $field_options['storage_format'] : false; - if ( !is_writable($tmp_path) ) { // 500 Internal Server Error // check both temp and live upload directory @@ -3149,7 +3169,8 @@ $file_helper = $this->Application->recallObject('FileHelper'); /* @var $file_helper FileHelper */ - $fname = $file_helper->ensureUniqueFilename($tmp_path, $fname); + $filename = $file_helper->ensureUniqueFilename($tmp_path, $filename); + $storage_format = $this->_getStorageFormat($this->Application->GetVar('field'), $event); if ( $storage_format ) { $image_helper = $this->Application->recallObject('ImageHelper'); @@ -3158,13 +3179,13 @@ move_uploaded_file($value['tmp_name'], $value['tmp_name'] . '.jpg'); // add extension, so ResizeImage can work $url = $image_helper->ResizeImage($value['tmp_name'] . '.jpg', $storage_format); $tmp_name = preg_replace('/^' . preg_quote($this->Application->BaseURL(), '/') . '/', '/', $url); - rename($tmp_name, $tmp_path . $fname); + rename($tmp_name, $tmp_path . $filename); } else { - move_uploaded_file($value['tmp_name'], $tmp_path . $fname); + move_uploaded_file($value['tmp_name'], $tmp_path . $filename); } - echo preg_replace('/^' . preg_quote($id, '/') . '_/', '', $fname); + echo preg_replace('/^' . preg_quote($id, '/') . '_/', '', $filename); $this->deleteTempFiles($tmp_path); @@ -3174,6 +3195,23 @@ } /** + * Gets storage format for a given field + * + * @param string $field_name + * @param kEvent $event + * @return bool + * @access protected + */ + protected function _getStorageFormat($field_name, kEvent $event) + { + $fields = $this->Application->getUnitOption($event->Prefix, 'Fields'); + $virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields'); + $field_options = array_key_exists($field_name, $fields) ? $fields[$field_name] : $virtual_fields[$field_name]; + + return isset($field_options['storage_format']) ? $field_options['storage_format'] : false; + } + + /** * Delete temporary files, that won't be used for sure * * @param string $path @@ -3253,13 +3291,22 @@ $object = $event->getObject(Array ('skip_autoload' => true)); /* @var $object kDBItem */ - $upload_dir = $object->GetFieldOption($this->Application->GetVar('field'), 'upload_dir'); + $field_id = $this->Application->GetVar('field_id'); - $var_name = $object->getPendingActionVariableName(); - $schedule = $this->Application->RecallVar($var_name); - $schedule = $schedule ? unserialize($schedule) : Array (); - $schedule[] = Array ('action' => 'delete', 'file' => FULL_PATH . $upload_dir . $filename); - $this->Application->StoreVar($var_name, serialize($schedule)); + if ( !preg_match_all('/\[([^\[\]]*)\]/', $field_id, $regs) ) { + return; + } + + $field = $regs[1][1]; + $record_id = $regs[1][0]; + $pending_actions = $object->getPendingActions($record_id); + $upload_dir = $object->GetFieldOption($field, 'upload_dir'); + + $pending_actions[] = Array ( + 'action' => 'delete', 'id' => $record_id, 'field' => $field, 'file' => FULL_PATH . $upload_dir . $filename + ); + + $object->setPendingActions($pending_actions, $record_id); } /** @@ -3301,7 +3348,7 @@ $url = $object->GetField($field, $options['thumb_format']); } else { - $url = $object->GetField($field, 'full_url'); // don't use "file_urls" format to prevent recursion + $url = $object->GetField($field, 'raw_url'); } $file_helper = $this->Application->recallObject('FileHelper'); @@ -3315,7 +3362,7 @@ header('Content-Length: ' . filesize($path)); $this->Application->setContentType(kUtil::mimeContentType($path), false); - header('Content-Disposition: inline; filename="' . $filename . '"'); + header('Content-Disposition: inline; filename="' . kUtil::removeTempExtension($filename) . '"'); readfile($path); } Index: branches/5.2.x/core/admin_templates/incs/form_blocks.tpl =================================================================== diff -u -N -r15729 -r15733 --- branches/5.2.x/core/admin_templates/incs/form_blocks.tpl (.../form_blocks.tpl) (revision 15729) +++ branches/5.2.x/core/admin_templates/incs/form_blocks.tpl (.../form_blocks.tpl) (revision 15733) @@ -371,7 +371,7 @@ sizes : '', flashsid : '', uploadURL : '', - deleteURL : '', + deleteURL : '', tmp_url : '', // Button settings