Application->ConfigValue($object->Prefix.'_MaxImageCount'); // file count equals to image count (temporary measure) $sql = 'SELECT * FROM '.TABLE_PREFIX.'CatalogFiles WHERE ResourceId = '.$object->GetDBField('ResourceId').' ORDER BY FileId ASC LIMIT 0, '.(int)$max_file_count; $item_files = $this->Conn->Query($sql); $file_counter = 1; foreach ($item_files as $item_file) { $file_path = $item_file['FilePath']; $object->SetDBField('File'.$file_counter, $file_path); $object->SetOriginalField('File'.$file_counter, $file_path); $object->SetFieldOption('File'.$file_counter, 'original_field', $item_file['FileName']); $file_counter++; } } /** * Saves newly uploaded images to external image table * * @param kCatDBItem $object * @return void * @access public */ public function SaveItemFiles(&$object) { $table_name = $this->Application->getUnitConfig('#file')->getTableName(); $max_file_count = $object->getUnitConfig()->getFileCount(); // $max_file_count = $this->Application->ConfigValue($object->Prefix . '_MaxImageCount'); $this->CheckFolder(FULL_PATH . ITEM_FILES_PATH); $i = 0; while ($i < $max_file_count) { $field = 'File'.($i + 1); $field_options = $object->GetFieldOptions($field); $file_path = $object->GetDBField($field); if ($file_path) { if (isset($field_options['original_field'])) { $key_clause = 'FileName = '.$this->Conn->qstr($field_options['original_field']).' AND ResourceId = '.$object->GetDBField('ResourceId'); if ($object->GetDBField('Delete'.$field)) { // if item was cloned, then new filename is in db (not in $image_src) $sql = 'SELECT FilePath FROM '.$table_name.' WHERE '.$key_clause; $file_path = $this->Conn->GetOne($sql); if (@unlink(FULL_PATH.ITEM_FILES_PATH.$file_path)) { $sql = 'DELETE FROM '.$table_name.' WHERE '.$key_clause; $this->Conn->Query($sql); } } else { // image record found -> update $fields_hash = Array ( 'FilePath' => $file_path, ); $this->Conn->doUpdate($fields_hash, $table_name, $key_clause); } } else { // record not found -> create $fields_hash = Array ( 'ResourceId' => $object->GetDBField('ResourceId'), 'FileName' => $field, 'Status' => STATUS_ACTIVE, 'FilePath' => $file_path, ); $this->Conn->doInsert($fields_hash, $table_name); $field_options['original_field'] = $field; $object->SetFieldOptions($field, $field_options); } } $i++; } } /** * Preserves cloned item images/files to be rewritten with original item images/files * * @param Array $field_values * @return void * @access public */ public function PreserveItemFiles(&$field_values) { foreach ($field_values as $field_name => $field_value) { if ( !is_array($field_value) ) { continue; } if ( isset($field_value['upload']) && ($field_value['error'] == UPLOAD_ERR_NO_FILE) ) { // this is upload field, but nothing was uploaded this time unset($field_values[$field_name]); } } } /** * Determines what image/file fields should be created (from post or just dummy fields for 1st upload) * * @param string $prefix * @param bool $is_image * @return void * @access public */ public function createItemFiles($prefix, $is_image = false) { $items_info = $this->Application->GetVar($prefix); if ($items_info) { list (, $fields_values) = each($items_info); $this->createUploadFields($prefix, $fields_values, $is_image); } else { $this->createUploadFields($prefix, Array(), $is_image); } } /** * Dynamically creates virtual fields for item for each image/file field in submit * * @param string $prefix * @param Array $fields_values * @param bool $is_image * @return void * @access public */ public function createUploadFields($prefix, $fields_values, $is_image = false) { $field_options = Array ('type' => 'string', 'max_len' => 240, 'default' => '',); if ( $is_image ) { $field_options['formatter'] = 'kPictureFormatter'; $field_options['include_path'] = 1; $field_options['allowed_types'] = Array ('image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/gif', 'image/bmp'); $field_prefix = 'Image'; } else { $field_options['formatter'] = 'kUploadFormatter'; $field_options['upload_dir'] = ITEM_FILES_PATH; $field_options['allowed_types'] = Array ('application/pdf', 'application/msexcel', 'application/msword', 'application/mspowerpoint'); $field_prefix = 'File'; } $image_count = 0; $config = $this->Application->getUnitConfig($prefix); foreach ($fields_values as $field_name => $field_value) { if ( preg_match('/^(' . $field_prefix . '[\d]+|Primary' . $field_prefix . ')$/', $field_name) ) { $config->addFields($field_options, $field_name); $config->addVirtualFields($field_options, $field_name); $this->_createCustomFields($prefix, $field_name, $config, $is_image); $image_count++; } } if ( !$image_count ) { // no images found in POST -> create default image fields $image_count = $this->Application->ConfigValue($prefix . '_MaxImageCount'); if ( $is_image ) { $created_count = 1; $image_names = Array ('Primary' . $field_prefix => ''); while ( $created_count < $image_count ) { $image_names[$field_prefix . $created_count] = ''; $created_count++; } } else { $created_count = 0; $image_names = Array (); while ( $created_count < $image_count ) { $image_names[$field_prefix . ($created_count + 1)] = ''; $created_count++; } } if ( $created_count ) { $this->createUploadFields($prefix, $image_names, $is_image); } return; } $config->setSetting($field_prefix . 'Count', $image_count); } /** * Adds ability to create more virtual fields associated with main image/file * * @param string $prefix * @param string $field_name * @param kUnitConfig $config * @param bool $is_image * @return void * @access protected */ protected function _createCustomFields($prefix, $field_name, kUnitConfig $config, $is_image = false) { $config->addVirtualFields(Array ('type' => 'int', 'default' => 0), 'Delete' . $field_name); if ( $is_image ) { $config->addVirtualFields(Array ('type' => 'string', 'default' => ''), $field_name . 'Alt'); } } /** * Downloads file to user * * @param string $filename * @return void * @access public */ public function DownloadFile($filename) { $this->Application->setContentType(kUtil::mimeContentType($filename), false); header('Content-Disposition: attachment; filename="' . basename($filename) . '"'); header('Content-Length: ' . filesize($filename)); readfile($filename); flush(); } /** * Creates folder with given $path * * @param string $path * @return bool * @access public */ public function CheckFolder($path) { $result = true; if (!file_exists($path) || !is_dir($path)) { $parent_path = preg_replace('#(/|\\\)[^/\\\]+(/|\\\)?$#', '', rtrim($path , '/\\')); $result = $this->CheckFolder($parent_path); if ($result) { $result = mkdir($path); if ($result) { chmod($path, 0777); // don't commit any files from created folder if (file_exists(FULL_PATH . '/CVS')) { $cvsignore = fopen($path . '/.cvsignore', 'w'); fwrite($cvsignore, '*.*'); fclose($cvsignore); chmod($path . '/.cvsignore', 0777); } } else { trigger_error('Cannot create directory "' . $path . '"', E_USER_WARNING); return false; } } } return $result; } /** * Copies all files and directories from $source to $destination directory. Create destination directory, when missing. * * @param string $source * @param string $destination * @return bool * @access public */ public function copyFolderRecursive($source, $destination) { if ( substr($source, -1) == DIRECTORY_SEPARATOR ) { $source = substr($source, 0, -1); $destination .= DIRECTORY_SEPARATOR . basename($source); } $iterator = new DirectoryIterator($source); /* @var $file_info DirectoryIterator */ $result = $this->CheckFolder($destination); foreach ($iterator as $file_info) { if ( $file_info->isDot() ) { continue; } $file = $file_info->getFilename(); if ( $file_info->isDir() ) { $result = $this->copyFolderRecursive($file_info->getPathname(), $destination . DIRECTORY_SEPARATOR . $file); } else { $result = copy($file_info->getPathname(), $destination . DIRECTORY_SEPARATOR . $file); } if (!$result) { trigger_error('Cannot create file/directory "' . $destination . DIRECTORY_SEPARATOR . $file . '"', E_USER_WARNING); break; } } return $result; } /** * Copies all files from $source to $destination directory. Create destination directory, when missing. * * @param string $source * @param string $destination * @return bool * @access public */ public function copyFolder($source, $destination) { if ( substr($source, -1) == DIRECTORY_SEPARATOR ) { $source = substr($source, 0, -1); $destination .= DIRECTORY_SEPARATOR . basename($source); } $iterator = new DirectoryIterator($source); /* @var $file_info DirectoryIterator */ $result = $this->CheckFolder($destination); foreach ($iterator as $file_info) { if ( $file_info->isDot() || !$file_info->isFile() ) { continue; } $file = $file_info->getFilename(); $result = copy($file_info->getPathname(), $destination . DIRECTORY_SEPARATOR . $file); if ( !$result ) { trigger_error('Cannot create file "' . $destination . DIRECTORY_SEPARATOR . $file . '"', E_USER_WARNING); break; } } return $result; } /** * Transforms given path to file into it's url, where each each component is encoded (excluding domain and protocol) * * @param string $path Path to file. * @param string|null $domain Alternative domain to use in url. * * @return string * @access public */ public function pathToUrl($path, $domain = null) { $path = str_replace(DIRECTORY_SEPARATOR, '/', preg_replace('/^' . preg_quote(FULL_PATH, '/') . '(.*)/', '\\1', $path, 1)); // TODO: why? $path = implode('/', array_map('rawurlencode', explode('/', $path))); return rtrim($this->Application->BaseURL($domain), '/') . $path; } /** * Transforms given url to path to it * * @param string $url Url. * @param string|null $domain Alternative domain to use in url. * * @return string */ public function urlToPath($url, $domain = null) { $base_url = rtrim($this->Application->BaseURL($domain), '/'); // escape replacement patterns, like "\" $full_path = preg_replace('/(\\\[\d]+)/', '\\\\\1', FULL_PATH); $path = preg_replace('/^' . preg_quote($base_url, '/') . '(.*)/', $full_path . '\\1', $url, 1); return str_replace('/', DIRECTORY_SEPARATOR, kUtil::unescape($path, kUtil::ESCAPE_URL)); } /** * Ensures, that new file will not overwrite any of previously created files with same name * * @param string $path * @param string $name * @param Array $forbidden_names * @return string */ public function ensureUniqueFilename($path, $name, $forbidden_names = Array ()) { $parts = pathinfo($name); $ext = '.' . $parts['extension']; $filename = $parts['filename']; $path = rtrim($path, '/'); $original_checked = false; $new_name = $filename . $ext; if ( $parts['dirname'] != '.' ) { $path .= '/' . ltrim($parts['dirname'], '/'); } // make sure target folder always exists, especially for cases, // when storage engine folder is supplied as a part of $name $this->CheckFolder($path); while (file_exists($path . '/' . $new_name) || in_array($path . '/' . $new_name, $forbidden_names)) { if ( preg_match('/(.*)_([0-9]*)(' . preg_quote($ext, '/') . ')/', $new_name, $regs) ) { $new_name = $regs[1] . '_' . ((int)$regs[2] + 1) . $regs[3]; } elseif ( $original_checked ) { $new_name = $filename . '_1' . $ext; } $original_checked = true; } if ( $parts['dirname'] != '.' ) { $new_name = $parts['dirname'] . '/' . $new_name; } return $new_name; } }