Index: branches/5.3.x/core/units/helpers/upload_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/upload_helper.php (revision 16390) +++ branches/5.3.x/core/units/helpers/upload_helper.php (revision 16391) @@ -1,332 +1,332 @@ <?php /** * @version $Id$ * @package In-Portal * @copyright Copyright (C) 1997 - 2012 Intechnic. All rights reserved. * @license GNU/GPL * In-Portal is Open Source software. * This means that this software may have been modified pursuant * the GNU General Public License, and as distributed it includes * or is derivative of works licensed under the GNU General Public License * or other free or open source software licenses. * See http://www.in-portal.org/license for copyright notices and details. */ class kUploadHelper extends kHelper { /** * Creates kUploadHelper instance. */ public function __construct() { parent::__construct(); // 5 minutes execution time @set_time_limit(5 * 60); } /** * Handles the upload. * * @param kEvent $event Event. * * @return string * @throws kUploaderException When upload could not be handled properly. */ public function handle(kEvent $event) { $this->disableBrowserCache(); // Uncomment this one to fake upload time // sleep(5); if ( !$this->Application->HttpQuery->Post ) { // Variables {field, id, flashsid} are always submitted through POST! // When file size is larger, then "upload_max_filesize" (in php.ini), // then these variables also are not submitted. throw new kUploaderException('File size exceeds allowed limit.', 413); } if ( !$this->checkPermissions($event) ) { // 403 Forbidden throw new kUploaderException('You don\'t have permissions to upload.', 403); } $value = $this->Application->GetVar('file'); if ( !$value || ($value['error'] != UPLOAD_ERR_OK) ) { // 413 Request Entity Too Large (file uploads disabled OR uploaded file was // too large for web server to accept, see "upload_max_filesize" in php.ini) throw new kUploaderException('File size exceeds allowed limit.', 413); } - $value = $this->Application->HttpQuery->unescapeRequestVariable($value); + $value = $this->Application->unescapeRequestVariable($value); $tmp_path = WRITEABLE . '/tmp/'; $filename = $this->getUploadedFilename() . '.tmp'; $id = $this->Application->GetVar('id'); if ( $id ) { $filename = $id . '_' . $filename; } if ( !is_writable($tmp_path) ) { // 500 Internal Server Error // check both temp and live upload directory throw new kUploaderException('Write permissions not set on the server, please contact server administrator.', 500); } /** @var FileHelper $file_helper */ $file_helper = $this->Application->recallObject('FileHelper'); $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'); /* @var $image_helper ImageHelper */ $this->moveUploadedFile($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 . $filename); } else { $this->moveUploadedFile($tmp_path . $filename); } $this->deleteTempFiles($tmp_path); if ( file_exists($tmp_path . 'resized/') ) { $this->deleteTempFiles($tmp_path . 'resized/'); } return preg_replace('/^' . preg_quote($id, '/') . '_/', '', $filename); } /** * Sends headers to ensure, that response is never cached. * * @return void */ protected function disableBrowserCache() { header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: post-check=0, pre-check=0', false); header('Pragma: no-cache'); } /** * Checks, that flash uploader is allowed to perform upload * * @param kEvent $event * @return bool */ protected function checkPermissions(kEvent $event) { // Flash uploader does NOT send correct cookies, so we need to make our own check $cookie_name = 'adm_' . $this->Application->ConfigValue('SessionCookieName'); $this->Application->HttpQuery->Cookie['cookies_on'] = 1; $this->Application->HttpQuery->Cookie[$cookie_name] = $this->Application->GetVar('flashsid'); // this prevents session from auto-expiring when KeepSessionOnBrowserClose & FireFox is used $this->Application->HttpQuery->Cookie[$cookie_name . '_live'] = $this->Application->GetVar('flashsid'); $admin_session = $this->Application->recallObject('Session.admin'); /* @var $admin_session Session */ if ( $admin_session->RecallVar('user_id') == USER_ROOT ) { return true; } // copy some data from given session to current session $backup_user_id = $this->Application->RecallVar('user_id'); $this->Application->StoreVar('user_id', $admin_session->RecallVar('user_id')); $backup_user_groups = $this->Application->RecallVar('UserGroups'); $this->Application->StoreVar('UserGroups', $admin_session->RecallVar('UserGroups')); // check permissions using event, that have "add|edit" rule $check_event = new kEvent($event->getPrefixSpecial() . ':OnProcessSelected'); $check_event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true)); /** @var kEventHandler $event_handler */ $event_handler = $this->Application->recallObject($event->Prefix . '_EventHandler'); $allowed_to_upload = $event_handler->CheckPermission($check_event); // restore changed data, so nothing gets saved to database $this->Application->StoreVar('user_id', $backup_user_id); $this->Application->StoreVar('UserGroups', $backup_user_groups); return $allowed_to_upload; } /** * Returns uploaded filename. * * @return string */ protected function getUploadedFilename() { if ( isset($_REQUEST['name']) ) { $file_name = $_REQUEST['name']; } elseif ( !empty($_FILES) ) { $file_name = $_FILES['file']['name']; } else { $file_name = uniqid('file_'); } return $file_name; } /** * Gets storage format for a given field. * * @param string $field_name * @param kEvent $event * @return bool */ protected function getStorageFormat($field_name, kEvent $event) { $config = $event->getUnitConfig(); $field_options = $config->getFieldByName($field_name); if ( !$field_options ) { $field_options = $config->getVirtualFieldByName($field_name); } return isset($field_options['storage_format']) ? $field_options['storage_format'] : false; } /** * Moves uploaded file to given location. * * @param string $file_path File path. * * @return void * @throws kUploaderException When upload could not be handled properly. */ protected function moveUploadedFile($file_path) { // Chunking might be enabled $chunk = (int)$this->Application->GetVar('chunk', 0); $chunks = (int)$this->Application->GetVar('chunks', 0); // Open temp file if ( !$out = @fopen("{$file_path}.part", $chunks ? 'ab' : 'wb') ) { throw new kUploaderException('Failed to open output stream.', 102); } if ( !empty($_FILES) ) { if ( $_FILES['file']['error'] || !is_uploaded_file($_FILES['file']['tmp_name']) ) { throw new kUploaderException('Failed to move uploaded file.', 103); } // Read binary input stream and append it to temp file if ( !$in = @fopen($_FILES['file']['tmp_name'], 'rb') ) { throw new kUploaderException('Failed to open input stream.', 101); } } else { if ( !$in = @fopen('php://input', 'rb') ) { throw new kUploaderException('Failed to open input stream.', 101); } } while ( $buff = fread($in, 4096) ) { fwrite($out, $buff); } @fclose($out); @fclose($in); // Check if file has been uploaded if ( !$chunks || $chunk == $chunks - 1 ) { // Strip the temp .part suffix off rename("{$file_path}.part", $file_path); } } /** * Delete temporary files, that won't be used for sure * * @param string $path * @return void */ protected function deleteTempFiles($path) { $files = glob($path . '*.*'); $max_file_date = strtotime('-1 day'); foreach ($files as $file) { if (filemtime($file) < $max_file_date) { unlink($file); } } } /** * Prepares object for operations with file on given field. * * @param kEvent $event Event. * @param string $field Field. * * @return kDBItem */ public function prepareUploadedFile(kEvent $event, $field) { $object = $event->getObject(Array ('skip_autoload' => true)); /* @var $object kDBItem */ $filename = $this->getSafeFilename(); if ( !$filename ) { $object->SetDBField($field, ''); return $object; } // set current uploaded file if ( $this->Application->GetVar('tmp') ) { $options = $object->GetFieldOptions($field); $options['upload_dir'] = WRITEBALE_BASE . '/tmp/'; unset($options['include_path']); $object->SetFieldOptions($field, $options); $filename = $this->Application->GetVar('id') . '_' . $filename; } $object->SetDBField($field, $filename); return $object; } /** * Returns safe version of filename specified in url * * @return bool|string * @access protected */ protected function getSafeFilename() { $filename = $this->Application->GetVar('file'); $filename = $this->Application->unescapeRequestVariable($filename); 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; } return $filename; } } class kUploaderException extends Exception { } Index: branches/5.3.x/core/units/helpers/country_states_helper.php =================================================================== --- branches/5.3.x/core/units/helpers/country_states_helper.php (revision 16390) +++ branches/5.3.x/core/units/helpers/country_states_helper.php (revision 16391) @@ -1,245 +1,245 @@ <?php /** * @version $Id$ * @package In-Portal * @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved. * @license GNU/GPL * In-Portal is Open Source software. * This means that this software may have been modified pursuant * the GNU General Public License, and as distributed it includes * or is derivative of works licensed under the GNU General Public License * or other free or open source software licenses. * See http://www.in-portal.org/license for copyright notices and details. */ defined('FULL_PATH') or die('restricted access!'); class kCountryStatesHelper extends kHelper { /** * ID of current language. * * @var integer */ protected $currentLanguage; /** * ID of primary language. * * @var integer */ protected $primaryLanguage; /** * Populates language ids that are used. */ public function __construct() { parent::__construct(); // Don't use GetVar('m_lang') since it's always equals to default language on editing form in admin. $this->currentLanguage = $this->Application->Phrases->LanguageId; $this->primaryLanguage = $this->Application->GetDefaultLanguageId(); } /** * Returns countries, that have states * * @return Array */ function getCountriesWithStates() { static $cache = null; if ( !isset($cache) ) { $table_name = $this->Application->getUnitConfig('country-state')->getTableName(); $sql = 'SELECT DISTINCT cname.IsoCode, cid.StateCountryId FROM ' . $table_name . ' cid JOIN ' . $table_name . ' cname ON cname.CountryStateId = cid.StateCountryId WHERE cid.StateCountryId IS NOT NULL'; $cache = $this->Conn->GetCol($sql, 'StateCountryId'); } return $cache; } /** * Checks, that country with given 3symbol ISO code has states * * @param string $country_code * @return bool */ function CountryHasStates($country_code) { return $country_code ? in_array($country_code, $this->getCountriesWithStates()) : false; } /** * Prepares states dropdown based on country selected * * @param kEvent $event * @param string $state_field * @param string $country_field */ function PopulateStates($event, $state_field, $country_field) { $object = $event->getObject(); /* @var $object kDBItem */ $country_iso = $object->GetDBField($country_field); if ( !$country_iso ) { - return; - } + return; + } $field_options = $object->GetFieldOptions($state_field); $field_options['options'] = $this->getStates($country_iso); $object->SetFieldOptions($state_field, $field_options, $object->isVirtualField($state_field)); } /** * Returns list of given country states * * @param string $country_iso * @return Array */ public function getStates($country_iso) { $country_id = $this->getCountryStateId($country_iso, DESTINATION_TYPE_COUNTRY); if ( !$country_id ) { return Array (); } $cache_key = 'country_states[%CountryStateSerial%]'; $cache_key .= ':PL=' . $this->primaryLanguage . ':CL=' . $this->currentLanguage . ':ISO=' . $country_iso; $states = $this->Application->getCache($cache_key); if ( $states === false ) { $sql = 'SELECT IF(l' . $this->currentLanguage . '_Name = "", l' . $this->primaryLanguage . '_Name, l' . $this->currentLanguage . '_Name) AS Name, IsoCode FROM ' . $this->Application->getUnitConfig('country-state')->getTableName() . ' WHERE (Type = ' . DESTINATION_TYPE_STATE . ') AND (StateCountryId = ' . $country_id . ') ORDER BY Name ASC'; $states = $this->Conn->GetCol($sql, 'IsoCode'); $this->Application->setCache($cache_key, $states); } return $states; } /** * Returns valid state ISO code for state name and country code passed * * @param string $state_name * @param string $country_iso * @return string */ function getStateIso($state_name, $country_iso) { if ( !$this->CountryHasStates($country_iso) ) { return $state_name; } $table_name = $this->Application->getUnitConfig('country-state')->getTableName(); $country_id = $this->getCountryStateId($country_iso, DESTINATION_TYPE_COUNTRY); $sql = 'SELECT IsoCode FROM ' . $table_name . ' WHERE (Type = ' . DESTINATION_TYPE_STATE . ') AND (StateCountryId = %1$s) AND ( (IsoCode = %2$s) OR (UPPER(l%3$s_Name) = %2$s) OR (UPPER(l%4$s_Name) = %2$s) )'; $state_name = trim(mb_strtoupper($state_name)); $sql = sprintf($sql, $country_id, $this->Conn->qstr($state_name), $this->currentLanguage, $this->primaryLanguage); return $this->Conn->GetOne($sql); } /** * Checks, that entered state matches entered country * * @param kEvent $event * @param string $state_field * @param string $country_field * @param bool $auto_required * @return void */ function CheckStateField($event, $state_field, $country_field, $auto_required = true) { $object = $event->getObject(); /* @var $object kDBItem */ $country_iso = $object->GetDBField($country_field); if ( $auto_required ) { $object->setRequired($state_field, $this->CountryHasStates($country_iso)); } $state = $object->GetDBField($state_field); if ( $country_iso && $state ) { $state_iso = $this->getStateIso($state, $country_iso); if ( $state_iso !== false ) { // replace state name with it's ISO code $object->SetDBField($state_field, $state_iso); } else { // state not found by name -> report error $object->SetError($state_field, 'invalid_state', 'la_invalid_state'); } } } /** * Returns country/state id based on given iso code and it's type * * @param string $iso_code * @param int $type * @return int */ function getCountryStateId($iso_code, $type) { $config = $this->Application->getUnitConfig('country-state'); $cache_key = 'country_state_id[%CountryStateSerial%]:ISO=' . $iso_code . ';Type=' . $type; $id = $this->Application->getCache($cache_key); if ( $id === false ) { $sql = 'SELECT ' . $config->getIDField() . ' FROM ' . $config->getTableName() . ' WHERE (Type = ' . $type . ') AND (IsoCode = ' . $this->Conn->qstr($iso_code) . ')'; $id = (int)$this->Conn->GetOne($sql); $this->Application->setCache($cache_key, $id); } return $id; } /** * Returns 3 symbols ISO code from 2 symbols ISO code or otherwise, when $from_short parameter is used * * @param string $iso_code * @param bool $from_short * @return string */ function getCountryIso($iso_code, $from_short = false) { if ($from_short) { $sql = 'SELECT IsoCode FROM ' . TABLE_PREFIX . 'CountryStates WHERE ShortIsoCode = ' . $this->Conn->qstr($iso_code) . ' AND `Type` = ' . DESTINATION_TYPE_COUNTRY; } else { $sql = 'SELECT ShortIsoCode FROM ' . TABLE_PREFIX . 'CountryStates WHERE IsoCode = ' . $this->Conn->qstr($iso_code) . ' AND `Type` = ' . DESTINATION_TYPE_COUNTRY; } return $this->Conn->GetOne($sql); } }