Index: branches/5.3.x/core/kernel/db/db_event_handler.php
===================================================================
diff -u -N -r15698 -r15902
--- branches/5.3.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 15698)
+++ branches/5.3.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 15902)
@@ -1,6 +1,6 @@
getPrefixSpecial() . '] in checkItemStatus, leading to "404 Not Found"', E_USER_NOTICE);
- $vars = $this->Application->UrlManager->prepare404();
-
- foreach ($vars as $var_name => $var_value) {
- $this->Application->SetVar($var_name, $var_value);
- }
-
- // in case if missing item is recalled first from event (not from template)
- $this->Application->QuickRun();
- $this->Application->Done();
- exit;
+ $this->Application->UrlManager->show404();
}
/**
@@ -640,7 +631,7 @@
if ( MOD_REWRITE ) {
$redirect_params = Array (
'm_cat_id' => 0,
- 'next_template' => urlencode('external:' . $_SERVER['REQUEST_URI']),
+ 'next_template' => kUtil::escape('external:' . $_SERVER['REQUEST_URI'], kUtil::ESCAPE_URL),
);
}
else {
@@ -668,6 +659,7 @@
/* @var $object kTempTablesHandler */
$parent_event = $event->getEventParam('parent_event');
+ /* @var $parent_event kEvent */
if ( is_object($parent_event) ) {
$object->setParentEvent($parent_event);
@@ -1585,6 +1577,7 @@
list($id, $field_values) = each($items_info);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
+ $event->setEventParam('form_data', $field_values);
$this->customProcessing($event, 'before');
@@ -1638,6 +1631,7 @@
foreach ($items_info as $id => $field_values) {
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
+ $event->setEventParam('form_data', $field_values);
$this->customProcessing($event, 'before');
if ( $object->Update($id) ) {
@@ -1830,15 +1824,11 @@
$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);
- foreach ($ids as $id) {
- $object->resetUploads($id);
- }
-
$temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler', Array ('parent_event' => $event));
/* @var $temp_handler kTempTablesHandler */
@@ -1848,10 +1838,10 @@
$event->SetRedirectParam($event->getPrefixSpecial() . '_id', array_shift($ids));
$event->SetRedirectParam('pass', 'all,' . $event->getPrefixSpecial());
- $simultaneous_edit_message = $this->Application->GetVar('_simultanious_edit_message');
+ $simultaneous_edit_message = $this->Application->GetVar('_simultaneous_edit_message');
if ( $simultaneous_edit_message ) {
- $event->SetRedirectParam('_simultanious_edit_message', urlencode($simultaneous_edit_message));
+ $event->SetRedirectParam('_simultaneous_edit_message', kUtil::escape($simultaneous_edit_message, kUtil::ESCAPE_URL));
}
}
@@ -2077,6 +2067,21 @@
}
/**
+ * Analog of OnPreSave event for usage in AJAX request
+ *
+ * @param kEvent $event
+ *
+ * @return void
+ */
+ protected function OnPreSaveAjax(kEvent $event)
+ {
+ $ajax_form_helper = $this->Application->recallObject('AjaxFormHelper');
+ /* @var $ajax_form_helper AjaxFormHelper */
+
+ $ajax_form_helper->transitEvent($event, 'OnPreSave');
+ }
+
+ /**
* [HOOK] Saves sub-item
*
* @param kEvent $event
@@ -2182,8 +2187,6 @@
$this->Application->SetVar($event->getPrefixSpecial() . '_id', 0);
$this->Application->SetVar($event->getPrefixSpecial() . '_PreCreate', 1);
- $object->resetUploads();
-
$changes_var_name = $this->Prefix . '_changes_' . $this->Application->GetTopmostWid($this->Prefix);
$this->Application->RemoveVar($changes_var_name);
@@ -2205,7 +2208,7 @@
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
-
+ $event->setEventParam('form_data', $field_values);
$this->customProcessing($event, 'before');
if ( $object->Create() ) {
@@ -2421,7 +2424,7 @@
/* @var $object kDBItem */
if ( !$object->IsTempTable() ) {
- $this->_proccessPendingActions($event);
+ $this->_processPendingActions($event);
}
}
@@ -2450,7 +2453,7 @@
/* @var $object kDBItem */
if ( !$object->IsTempTable() ) {
- $this->_proccessPendingActions($event);
+ $this->_processPendingActions($event);
}
}
@@ -2601,7 +2604,13 @@
*/
protected function OnAfterCopyToLive(kEvent $event)
{
- $this->_proccessPendingActions($event);
+ $object = $event->getObject(array('skip_autoload' => true));
+ /* @var $object kDBItem */
+
+ $object->SwitchToLive();
+ $object->Load($event->getEventParam('id'));
+
+ $this->_processPendingActions($event);
}
/**
@@ -2611,37 +2620,45 @@
* @return void
* @access protected
*/
- protected function _proccessPendingActions(kEvent $event)
+ protected function _processPendingActions(kEvent $event)
{
$object = $event->getObject();
/* @var $object kDBItem */
- if ( $object->getUploaderFields() ) {
- // this would prevent SQL error when loading "*-ci" prefix object
- if ( $event->Name == 'OnAfterCopyToLive' ) {
- $object->SwitchToLive();
- $object->Load($event->getEventParam('id'));
+ $update_required = false;
+ $temp_id = $event->getEventParam('temp_id');
+ $id = $temp_id !== false ? $temp_id : $object->GetID();
- $object->processUploads($event->getEventParam('temp_id'));
- }
- else {
- $object->processUploads();
- }
- }
+ foreach ($object->getPendingActions($id) as $data) {
+ switch ( $data['action'] ) {
+ case 'delete':
+ unlink($data['file']);
+ break;
- $var_name = $object->getPendingActionVariableName();
- $schedule = $this->Application->RecallVar($var_name);
+ case 'make_live':
+ $file_helper = $this->Application->recallObject('FileHelper');
+ /* @var $file_helper FileHelper */
- if ( $schedule ) {
- $schedule = unserialize($schedule);
+ $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);
- foreach ($schedule as $data) {
- if ( $data['action'] == 'delete' ) {
- unlink($data['file']);
- }
+ $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();
}
}
@@ -2999,7 +3016,7 @@
*/
public function getCustomExportColumns(kEvent $event)
{
- return Array();
+ return Array ();
}
/**
@@ -3152,18 +3169,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');
- $field_options = $this->_getUploadFieldDefinition($event, $field_name);
-
- $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
@@ -3175,7 +3187,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');
@@ -3184,13 +3197,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);
@@ -3200,23 +3213,23 @@
}
/**
- * Returns upload field definition
+ * Gets storage format for a given field
*
- * @param kEvent $event
* @param string $field_name
- * @return Array
+ * @param kEvent $event
+ * @return bool
* @access protected
*/
- protected function _getUploadFieldDefinition(kEvent $event, $field_name)
+ protected function _getStorageFormat($field_name, kEvent $event)
{
$config = $event->getUnitConfig();
- $ret = $config->getFieldByName($field_name);
+ $field_options = $config->getFieldByName($field_name);
- if ( !$ret ) {
- $ret = $config->getVirtualFieldByName($field_name);
+ if ( !$field_options ) {
+ $field_options = $config->getVirtualFieldByName($field_name);
}
- return $ret;
+ return isset($field_options['storage_format']) ? $field_options['storage_format'] : false;
}
/**
@@ -3290,21 +3303,31 @@
protected function OnDeleteFile(kEvent $event)
{
$event->status = kEvent::erSTOP;
- $filename = $this->_getUploadedFileInfo($event, 'full_path');
+ $filename = $this->_getSafeFilename();
- if ( $filename === false ) {
+ if ( !$filename ) {
return;
}
$object = $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
- $var_name = $object->getPendingActionVariableName();
- $schedule = $this->Application->RecallVar($var_name);
- $schedule = $schedule ? unserialize($schedule) : Array ();
- $schedule[] = Array ('action' => 'delete', 'file' => $filename);
+ $field_id = $this->Application->GetVar('field_id');
- $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);
}
/**
@@ -3317,21 +3340,37 @@
protected function OnViewFile(kEvent $event)
{
$event->status = kEvent::erSTOP;
+ $filename = $this->_getSafeFilename();
- if ( $this->Application->GetVar('thumb') ) {
- $object = $event->getObject(Array ('skip_autoload' => true));
- /* @var $object kDBItem */
+ if ( !$filename ) {
+ return;
+ }
- $field = $this->Application->GetVar('field');
- $url = $this->_getUploadedFileInfo($event, $object->GetFieldOption($field, 'thumb_format'));
+ $object = $event->getObject(Array ('skip_autoload' => true));
+ /* @var $object kDBItem */
+
+ $field = $this->Application->GetVar('field');
+ $options = $object->GetFieldOptions($field);
+
+ // set current uploaded file
+ if ( $this->Application->GetVar('tmp') ) {
+ $options['upload_dir'] = WRITEBALE_BASE . '/tmp/';
+ unset($options['include_path']);
+ $object->SetFieldOptions($field, $options);
+
+ $object->SetDBField($field, $this->Application->GetVar('id') . '_' . $filename);
}
else {
- $url = $this->_getUploadedFileInfo($event, 'full_url');
+ $object->SetDBField($field, $filename);
}
- if ( $url === false ) {
- return;
+ // get url to uploaded file
+ if ( $this->Application->GetVar('thumb') ) {
+ $url = $object->GetField($field, $options['thumb_format']);
}
+ else {
+ $url = $object->GetField($field, 'raw_url');
+ }
$file_helper = $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
@@ -3344,51 +3383,31 @@
header('Content-Length: ' . filesize($path));
$this->Application->setContentType(kUtil::mimeContentType($path), false);
- header('Content-Disposition: inline; filename="' . basename($path) . '"');
+ header('Content-Disposition: inline; filename="' . kUtil::removeTempExtension($filename) . '"');
readfile($path);
}
/**
- * Returns information about uploaded file
+ * Returns safe version of filename specified in url
*
- * @param kEvent $event
- * @param string $format
- * @return bool
+ * @return bool|string
* @access protected
*/
- protected function _getUploadedFileInfo(kEvent $event, $format)
+ protected function _getSafeFilename()
{
- $file = $this->Application->GetVar('file');
+ $filename = $this->Application->GetVar('file');
if ( !$this->Application->isAdmin ) {
- $file = htmlspecialchars_decode($file);
+ $filename = htmlspecialchars_decode($filename);
}
- if ( (strpos($file, '../') !== false) || (trim($file) !== $file) ) {
+ if ( (strpos($filename, '../') !== false) || (trim($filename) !== $filename) ) {
// when relative paths or special chars are found template names from url, then it's hacking attempt
return false;
}
- $object = $event->getObject(Array ('skip_autoload' => true));
- /* @var $object kDBItem */
-
- $field = $this->Application->GetVar('field');
- $options = $object->GetFieldOptions($field);
-
- // set current uploaded file
- if ( $this->Application->GetVar('tmp') ) {
- $options['upload_dir'] = WRITEBALE_BASE . '/tmp/';
- unset($options['include_path']);
- $object->SetFieldOptions($field, $options);
-
- $object->SetDBField($field, $this->Application->GetVar('id') . '_' . $file);
- }
- else {
- $object->SetDBField($field, $file);
- }
-
- return $object->GetField($field, $format);
+ return $filename;
}
/**
@@ -3434,6 +3453,7 @@
list ($id, $field_values) = each($items_info);
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
+ $event->setEventParam('form_data', $field_values);
$object->setID($id);
$response = Array ('status' => 'OK');
@@ -3444,13 +3464,14 @@
$error_field = $object->GetFieldOption($field, 'error_field', false, $field);
if ( !$object->Validate() && $object->GetErrorPseudo($error_field) ) {
- $response['status'] = $object->GetErrorMsg($error_field);
+ $response['status'] = $object->GetErrorMsg($error_field, false);
}
$ajax_form_helper = $this->Application->recallObject('AjaxFormHelper');
/* @var $ajax_form_helper AjaxFormHelper */
$response['other_errors'] = $ajax_form_helper->getErrorMessages($object);
+ $response['uploader_info'] = $ajax_form_helper->getUploaderInfo($object, array_keys($field_values));
$event->status = kEvent::erSTOP; // since event's OnBefore... events can change this event status
echo json_encode($response);
@@ -3499,7 +3520,7 @@
echo '';
foreach ($data as $item) {
- echo '- ' . htmlspecialchars($item, null, CHARSET) . '
';
+ echo '- ' . kUtil::escape($item, kUtil::ESCAPE_HTML) . '
';
}
echo '';