PHP: получить расширение файла, не работающее с загрузкой на S3

Я использую API Amazon S3 для загрузки файлов, и каждый раз, когда я загружаю, я меняю имя файла.

Так, например:

Dog.png> 3Sf5f.png

Теперь я получил случайную часть, которая работает как таковая:

function rand_string( $length ) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $size = strlen( $chars ); for( $i = 0; $i < $length; $i++ ) { $str .= $chars[ rand( 0, $size - 1 ) ]; } return $str; } 

Поэтому я устанавливаю random_string в параметр имени как таковой:

 $params->key = rand_string(5); 

Теперь моя проблема в том, что это не будет показывать расширение. Таким образом, файл будет загружаться как 3Sf5f вместо 3Sf5f.png .

Переменная $ filename дает мне полное имя файла с его расширением.

Если я использую $params->key = rand_string(5).'${filename}'; Я получил:

 3Sf5fDog.png 

Поэтому я попытался получить расширение $ filename и применить его. Я пробовал более 30 методов без каких-либо положительных результатов.

Например, я попробовал $ path_info (), я попробовал substr (strrchr ($ file_name, '.'), 1); еще много. Все они дают мне либо 3Sf5fDog.png либо просто 3Sf5f .

Пример того, что я пробовал:

 // As @jcinacio pointed out. Change this to: // // $file_name = "${filename}"; // $file_name = '${filename}' // Is is wrong, since '..' does not evaluate $params->key = rand_string(5).$file_name; = 3Sf5fDog.png 

,

 $file_name = substr(strrchr('${filename}', '.'), 1); $params->key = rand_string(5).$file_name; = 3Sf5f 

,

 $filename = "example.png" // If I declare my own the filename it works. $file_name = substr(strrchr('${filename}', '.'), 1); $params->key = rand_string(5).$file_name; = 3Sf5f.png 

Весь файл класса: http://pastebin.com/QAwJphmW (других файлов для всего скрипта нет).

Что я делаю неправильно? Это действительно расстраивает.

Solutions Collecting From Web of "PHP: получить расширение файла, не работающее с загрузкой на S3"

Переменная $ filename (и, таким образом, "$ {filename}") НЕ НАХОДИТСЯ в строке 1053 вашего кода (нумерация строк на основе исходной пасты из pastebin).

Таким образом, независимо от того, что вы делаете, вы никогда не найдете расширение переменной, которой не существует.


И я, наконец, решил, что вы делаете. Я предполагаю, что это расширение PHP: переименуйте файл перед загрузкой

Простой ответ: вы не можете сделать это, как вы предполагаете. Почему-то «$ filename» не анализируется в момент создания этого URL-адреса, но переменная передается на Amazon S3 и обрабатывается там.

Решение

Таким образом, единственный вариант, о котором я могу думать, – использовать параметр «successRedirect», чтобы указать на другой URL-адрес. Этот URL-адрес получит «ведро» и «ключ» в качестве параметров запроса от Amazon ( http://doc.s3.amazonaws.com/proposals/post.html#Dealing_with_Success ). Укажите это на PHP-скрипт, который переименовывает файл на Amazon S3 (copy + delete), а затем перенаправляет пользователя на другой экран успеха.

Так,

в вашем коде, строка 34,

  1. добавьте полный URL-адрес в новый файл сценария php, который вы собираетесь писать.
  2. скрипт php wil получит ведро и ключ, переданный ему
  3. Создайте новое имя файла из "ключа"
  4. используйте функцию «public static function copyObject ($ srcBucket, $ srcUri, $ bucket, $ uri)», чтобы скопировать загруженный файл в новое имя
  5. затем удалите оригинал (используя deleteObject ($ bucket, $ uri))
  6. затем перенаправить пользователя туда, куда вы хотите отправить их

Это будет делать именно то, что вы хотите.


В ответ на ваши комментарии «Это единственный способ – как насчет затрат, как плата за Amazon за запрос?»

Запросы на удаление бесплатны. Никаких затрат на передачу данных при перемещении на одном ковше (или даже в том же регионе). Таким образом, это решение (это единственный способ без переноса на промежуточный сервер, переименование и загрузка), он удваивает стоимость загрузки от 1c на 1000 загрузок до 2c на 1000 загрузок. Мне понадобилось 10 минут @ $ 200 / час, чтобы узнать это и ответить = $ 33 = 1,666,666 загрузок! Затраты немного бледнеют, когда вы делаете математику 🙂

Сравните с другим решением: сделайте сообщение на веб-сервере, переименуйте файл, а затем загрузите с веб-сервера: вы перемещаете всю полосу пропускания из клиники прямо к себе – дважды. И это также вводит риск и увеличивает возможные точки отказа.


В ответ на «Не работает. Я загружаю файл, а старый удаляется»

Я бы сказал, что это не проблема, поскольку вы загружаете файл, а затем переименовываете его в течение секунды или двух. Но если вы хотите от gurantee, каждый файл будет загружен, вам нужно сделать намного больше, чем создавать произвольное имя файла:

  1. иметь свое «окончательное» ведро
  2. для каждой загрузки создайте временное ведро (это 1c на 1000 ведер, если вы беспокоитесь о расходах)
  3. загружать во временное ведро
  4. создать случайное имя, проверить, не существует ли в конечном ковше (1c на 1000 проверок)
  5. скопировать файл в конечное ведро (с новым именем)
  6. удалять загруженный файл, а также ведро.
  7. периодически очищать ведра, где загрузка файлов не была завершена.
 $fileSplit = explode('.',$filename); $extension = '.'.$fileSplit[count($fileSplit) - 1]; 

Этот explode () делит имя файла на массив с периодами как разделители, а затем захватывает последний кусок массива (если имя файла – foo.bar.jpg) и ставит перед ним период. Это должно дать вам желаемое расширение, чтобы добавить его в rand_string (5).

 $params->key = rand_string(5).$extension; 

Я думаю, что что-то простое, как показано ниже, должно работать, чтобы извлечь расширение файла из имени файла:

 function getFileExtension($fileName) { $ext = ''; if(strpos($fileName, ".") !== false) { $ext = end(explode(".", $fileName)); } return $ext; } 

если вы загружаете изображения, попробуйте это

 $dim = getimagesize($file); $type = $dim[2]; if( $type == IMAGETYPE_JPEG ) $ext=".jpg"; if( $type == IMAGETYPE_GIF ) $ext=".gif"; if( $type == IMAGETYPE_PNG ) $ext=".png"; $params->key = rand_string(5).$ext; 

Что происходит, если вы:

 $filename = "${filename}"; echo $filename; die(); 

Вы получаете что-то вроде «Dog.png»? Если вы этого не сделали, есть что-то не так, как вы получаете имя файла. Если вы получаете что-то вроде «Dog.png», вот что я использую для получения расширения файла.

 $pieces = explode('.',trim($filename)); $extension = end($pieces); 

Тогда вы сможете это сделать:

 $params->key = rand_string(5).'.'.$extension; 

Вам нужно сначала узнать, что такое первоначальное расширение, а не переименовать весь файл. Поэтому сохраните расширение и переименуйте имя файла.

Предполагая, что у вас есть имя изображения в $ image_name:

 $image_name = "image.png"; $random_string = "random"; list($filename,$fileext) = explode(".",$image_name); $new_name = $random_string.'.'.$fileext; rename($image_name,$new_name); 

Хорошо, вот еще одна попытка, которую я использовал, когда мне не удалось получить расширение на стороне сервера. что я сделал, я использовал javascript для извлечения расширения файла и отправки его по почте.

 <script type="text/javascript" > function fileinfo() { var file = document.form.file.value; document.getElementById("ext").value = file.split('.').pop(); document.myform.submit(); } </script> <form name="myform" enctype="multipart/form-data" onsubmit="fileinfo();"> <input type="file" name="file"> <input type="hidden" name="ext"> //rest of the form </form> 

в следующем файле php вы можете напрямую использовать $ _POST ['ext'] в качестве расширения. надеюсь, что это помогло. сообщите мне, если у вас есть проблемы с реализацией этого

я использую это на своих сайтах (и прекрасно работает в течение многих лет):

 $file = 'yourOriginalfile.png'; //get the file extension $fileExt = substr(strrchr($file, '.'), 1); //create a random name and add the original extension $fileUniqueName = md5(uniqid(mktime())) . '.' . $fileExt; rename($file,$fileUniqueName); 

ваша функция генерирует слишком короткие имена файлов (5 символов), таким образом создает более длинные имена файлов, избегая столкновения имен файлов.

Пример вывода: aff5a25e84311485d4eedea7e5f24a4f.png

Похоже, что на самом деле происходит то, что происходит на самом деле, а не полностью выдает имя файла прямо сейчас, вы фактически передаете очень маленькую «программу» через интерфейс, чтобы впоследствии можно было создать имя файла (когда имя переменной $ filename существует и находится в области видимости ). Другая сторона интерфейса в конечном итоге выполняет эту «программу», в которую вы проходите, что создает измененное имя файла. (Конечно, передача «программы» на что-то еще, чтобы выполнить позже, не стремится сделать отладочную реальность легкой 🙂

(Конечно, вам решать, хотите ли вы «сделать эту работу» или «сделать это по-другому». «Различные способы» обычно включают переименование или копирование файла, прежде чем вы даже попытаетесь вызвать интерфейс загрузки и описаны в других ответах.)

Если вы решите, что хотите «заставить его работать», тогда весь параметр имени файла должен быть программой, а не просто частью ее. Эта несколько необычная функциональность обычно включает в себя включение всей строки в одинарные кавычки. (Вам также нужно что-то сделать с существующими метками одиночной кавычки внутри строки, чтобы они не прервали цитированную строку слишком рано. Один из способов – процитировать каждую из них с обратной косой чертой. Другой способ, который может выглядеть более чистым и обычно работает, – это замените их двойными кавычками.) Другими словами, я считаю, что приведенный ниже код будет работать для вас (у меня нет подходящей среды для его проверки, поэтому я не уверен).

 $file_extension = 'substr(strrchr(${filename}, "."), 1)'; $params->key = rand_string(5).$file_extension; 

(Как только вы его заработаете, вам может потребоваться пересмотреть схему именования. Возможно, имя должно быть немного длиннее. Или, возможно, оно должно включать некоторую идентифицируемую информацию (например, сегодняшнюю дату или исходное имя файла). нажмите на что-то вроде $ file_base.rand_string (7). $ file_extension.

Непроверенный, но достаточно простой для работы:

 $ext = pathinfo($filename, PATHINFO_EXTENSION); 

вернет часть расширения (без «.»)

Простое решение для переименования файла и вычисления расширения :

 $fileName = 'myRandomFile.jpg'; // separate the '.'-separated parts of the file name $parts = explode( '.', $fileName ); // Solution will not work, if no extension is present assert( 1 < count( $parts ) ); // keep the extension and drop the last part $extension = $parts[ count( $parts ) - 1 ]; unset( $parts[ count( $parts ) - 1 ] ); // finally, form the new file name $newFileName = md5( 'someSeedHere' + implode( '.', $parts )) . '.' . $extension; echo $extension // outputs jpg . ' - ' . $newFileName // outputs cfcd208495d565ef66e7dff9f98764da.jpg ; 

Обратите внимание, что md5 () всегда имеет длину 32 байта и не уникален относительно вычисленного значения . Для многих практических примеров это достаточно уникально .

добавление

Кроме того, вы можете использовать это решение для отслеживания изменений переменных :

 abstract class CSTReportDelegate { abstract public function emitVariableChange( $variableName, $oldValue, $newValue ); abstract public function emitVariableSetNew( $variableName, $newValue ); } class CSTSimpleReportDelegate extends CSTReportDelegate { public function emitVariableChange( $variableName, $oldValue, $newValue ) { echo '<br />[global/change] '. $variableName . ' : ' . print_r( $oldValue, true ) . ' &rarr; ' . print_r( $newValue, true ); } public function emitVariableSetNew( $variableName, $newValue ) { echo '<br />[global/init] '. $variableName . ' &rarr; ' . print_r( $newValue, TRUE ); } } class CSysTracer { static protected $reportDelegate; static private $globalState = array(); static private $traceableGlobals = array(); static private $globalTraceEnabled = FALSE; const DEFAULT_TICK_AMOUNT = 1; static public function setReportDelegate( CSTReportDelegate $aDelegate ) { self::$reportDelegate = $aDelegate; } static public function start( $tickAmount = self::DEFAULT_TICK_AMOUNT ) { register_tick_function ( array( 'CSysTracer', 'handleTick' ) ); } static public function stop() { unregister_tick_function( array( 'CSysTracer', 'handleTick' ) ); } static public function evalAndTrace( $someStatement ) { declare( ticks = 1 ); { self::start(); eval( $someStatement ); self::stop(); } } static public function addTraceableGlobal( $varName ) { if ( is_array( $varName )) { foreach( $varName as $singleName ) { self::addTraceableGlobal( $singleName ); } return; } self::$traceableGlobals[ $varName ] = $varName; } static public function removeTraceableGlobal( $varName ) { unset( self::$traceableGlobals[ $varName ] ); } /** * Main function called at each tick. Calls those functions, which * really perform the checks. * */ static public function handleTick( ) { if ( TRUE === self::$globalTraceEnabled ) { self::traceGlobalVariable(); } } static public function enableGlobalsTrace() { self::$globalTraceEnabled = TRUE; } static public function disableGlobalsTrace() { self::$globalTraceEnabled = FALSE; } static public function traceGlobalVariable( ) { foreach( self::$traceableGlobals as $aVarname ) { if ( ! isset( $GLOBALS[ $aVarname ] )) { continue; } if ( ! isset( self::$globalState[ $aVarname ] ) ) { self::$reportDelegate->emitVariableSetNew( $aVarname, $GLOBALS[ $aVarname ] ); self::$globalState[ $aVarname ] = $GLOBALS[ $aVarname ]; continue; } if ( self::$globalState[ $aVarname ] !== $GLOBALS[ $aVarname ]) { self::$reportDelegate->emitVariableChange( $aVarname, self::$globalState[ $aVarname ], $GLOBALS[ $aVarname ] ); } self::$globalState[ $aVarname ] = $GLOBALS[ $aVarname ]; } } } 

Пример использования:

 ini_set("display_errors", TRUE); error_reporting(E_ALL); require_once( dirname( __FILE__ ) . '/CStatementTracer.inc.php' ); /* Ticks make it easy to have a function called for every line of PHP * code. We can use this to track the state of a variable throughout * the execution of a script. */ CSysTracer::addTraceableGlobal( array( 'foo', 'bar' )); CSysTracer::setReportDelegate( new CSTSimpleReportDelegate() ); CSysTracer::enableGlobalsTrace(); CSysTracer::start(); declare( ticks = 1 ); // // At this point, tracing is enabled. // Add your code or call your functions/methods here // CSysTracer::stop(); 

Как насчет этого?

 $temp = rand_string(5).'${filename}'; //should be 3Sf5fDog.png $ext = pathinfo($temp, PATHINFO_EXTENSION); //should be .png $temp2 = rand_string(5) . $ext; //should be 4D47a.png