9

Amazon S3 API を使用してファイルをアップロードしていますが、アップロードするたびにファイルの名前を変更しています。

たとえば、次のようになります。

犬.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;
        }   

したがって、次のように name パラメータに 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 (スクリプト全体の他のファイルはありません)。

私は何を間違っていますか?これは本当にイライラします。

4

12 に答える 12

8

変数 $filename (したがって "${filename}") は、コードの 1053 行目 (pastebin からの未加工の貼り付けに基づく行番号付け) の範囲ではありません。

したがって、何をしても、存在しない変数の拡張子を見つけることはできません。


そして、私はついにあなたが何をしているのかを理解しました。これはPHP の拡張機能だと思います: アップロード前にファイルの名前を変更する

簡単な答え: 思い通りにはできません。理由 - URL の作成時に「$filename」は解析されませんが、変数は Amazon S3 に渡され、そこで処理されます。

ソリューション

したがって、私が考えることができる唯一のオプションは、「successRedirect」パラメーターを使用して別の URL を指すようにすることです。その URL は、Amazon からクエリ パラメータとして「バケット」と「キー」を受け取ります ( http://doc.s3.amazonaws.com/proposals/post.html#Dealing_with_Success )。Amazon S3 上のファイルの名前を変更 (コピー + 削除) し、ユーザーを別の成功画面にリダイレクトする PHP スクリプトを指定します。

そう、

コードの 34 行目、

  1. これから作成する新しい php スクリプト ファイルに完全修飾 URL を追加します。
  2. PHP スクリプトはバケットとキーを取得します。
  3. 「キー」から新しいファイル名を作成します
  4. 関数「public static function copyObject($srcBucket, $srcUri, $bucket, $uri)」を使用して、アップロードされたファイルを新しい名前にコピーします
  5. 次に、オリジナルを削除します (deleteObject($bucket, $uri) を使用)
  6. 次に、ユーザーを送信先にリダイレクトします

それはまさにあなたが望むことをします。


「これが唯一の方法ですか。リクエストごとに Amazon が請求するコストについてはどうですか?」というコメントに対して。

削除依頼は無料です。同じバケット (または同じリージョン内) で移動する場合、データ転送コストはかかりません。したがって、このソリューション (中間サーバーへの転送、名前の変更、アップロードを行わない唯一の方法) では、アップロードのコストが 1000 回のアップロードあたり 1c から 1000 回のアップロードあたり 2c に倍増します。それを見つけて応答するのに 10 分かかりました @ $200/hour = $33 = 1,666,666 アップロード! 計算すると、コストは少し薄くなります:)

他のソリューションと比較してください: Web サーバーに投稿し、ファイルの名前を変更してから、Web サーバーからアップロードします。すべての帯域幅をクライアントから自分自身に直接移動します - 2 回。また、これによりリスクが発生し、故障の可能性が高くなります。


「動作しません。ファイルをアップロードすると、古いファイルが削除されます」への対応

ファイルをアップロードしてから1、2秒以内に名前を変更するので、これは問題ではないと思います。ただし、各ファイルがアップロードされることを保証したい場合は、とにかくランダムなファイル名を作成するだけでなく、さらに多くのことを行う必要があります。

  1. 「最終」バケットを用意する
  2. アップロードごとに、一時的なバケットを作成します (コストが心配な場合は、バケット 1000 個あたり 1c です)。
  3. 一時バケットにアップロード
  4. ランダムな名前を作成し、最終バケットに存在しないかどうかを確認します (1000 回の確認ごとに 1c)
  5. ファイルを最終バケットにコピーします (新しい名前で)
  6. アップロードしたファイルとバケットを削除します。
  7. ファイルのアップロードが完了していないバケットを定期的にクリーンアップします。
于 2012-05-19T03:02:45.547 に答える
4
$fileSplit = explode('.',$filename);
$extension = '.'.$fileSplit[count($fileSplit) - 1];

この expand() は、ファイル名を区切り文字としてピリオドを使用して配列に分割し、配列の最後の部分を取得して (ファイル名が foo.bar.jpg の場合)、その前にピリオドを置きます。これにより、目的の拡張子が rand_string(5) に追加されます。

$params->key = rand_string(5).$extension;
于 2012-05-13T19:43:42.190 に答える
2

画像をアップロードする場合は、これを試してください

$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;
于 2012-05-20T14:51:34.823 に答える
2

ファイル名からファイル拡張子を抽出するには、以下のような単純なものが機能すると思います。

function getFileExtension($fileName)
{
    $ext = '';
    if(strpos($fileName, ".") !== false)
    {
        $ext = end(explode(".", $fileName));
    }
    return $ext;
}
于 2012-05-21T07:58:17.240 に答える
1

サーバー側で拡張機能を取得するのに問題があったときに使用した別の試みがあります。私がやったことは、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']を直接使用できます。それがお役に立てば幸いです。これを実装するのに問題がある場合はお知らせください

于 2012-05-21T19:37:47.570 に答える
1

ファイル全体の名前を変更するのではなく、最初に元の拡張子が何であるかを確認する必要があります。したがって、拡張子を保持し、ファイル名の名前を変更します。

$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);  
于 2012-05-20T14:46:21.747 に答える
1

次の場合:

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

「Dog.png」のようなものを取得しますか? そうでない場合は、ファイル名を取得する方法に問題があります。「Dog.png」のようなものを取得した場合、ファイル拡張子を取得するために使用するものは次のとおりです。

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

次に、これを行うことができるはずです:

$params->key = rand_string(5).'.'.$extension;
于 2012-05-17T19:39:54.327 に答える
1

私は自分のウェブサイトでこれを使用しています(そして何年もうまく機能します):

$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

于 2012-05-22T06:35:40.337 に答える
1

実際に起こっていることは、現在ファイル名を完全に生成するのではなく、実際にはインターフェイスを介して非常に小さな「プログラム」を渡しているため、後でファイル名を生成できます(変数 $filename が存在し、スコープ内にある場合) )。インターフェイスの反対側は、最終的に、渡された「プログラム」を実行し、変更されたファイル名を生成します。(もちろん、後で実行するために「プログラム」を別のものに渡すことは、デバッグを本当に簡単にする傾向はありません:-)

(もちろん、「これを機能させる」か「別の方法で行う」かはあなた次第です。「別の方法」では通常、アップロードインターフェイスを呼び出す前に、ファイルの名前を変更したり、ファイルをコピーしたりする必要があり、説明されています他の回答では。)

「それを機能させる」ことにした場合は、ファイル名パラメーター全体がプログラムの一部ではなく、プログラムである必要があります。このやや珍しい機能では、通常、文字列全体を重引用符で囲みます。(文字列内の既存の一重引用符についても、引用符で囲まれた文字列がすぐに終了しないようにする必要があります。1 つの方法は、それぞれをバックスラッシュで引用することです。よりきれいに見え、通常は機能する別の方法は、次のとおりです。それらを二重引用符に置き換えてください。) つまり、以下のコードはうまくいくと思います (テストするための適切な環境がないため、確信が持てません)。

$file_extension = 'substr(strrchr(${filename}, "."), 1)';

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

(機能するようになったら、命名スキームを再検討することをお勧めします。名前をもう少し長くする必要があるかもしれません。または、識別可能な情報 {今日の日付やファイルの元の名前など} を含める必要があるかもしれません。 $file_base.rand_string(7).$file_extension のようなものにヒットします。

于 2012-05-22T21:53:27.747 に答える
0

これはどう?

$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
于 2012-05-19T20:40:10.177 に答える
0

ファイルの名前を変更して拡張子を計算する簡単なソリューション:

$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();
于 2012-05-13T19:45:30.300 に答える
0

テストされていませんが、動作するのに十分シンプルです:

$ext = pathinfo($filename, PATHINFO_EXTENSION);

拡張部分を返します(「。」なし)

于 2012-05-13T19:47:44.970 に答える