我正在使用 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;
}
所以我将random_string设置为 name 参数如下:
$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(整个脚本没有其他文件(。
我做错了什么?这真的很令人沮丧。
变量 $filename(因此"${文件名}"(不在代码第 1053 行的作用域中(行号基于 pastebin 的原始粘贴(。
因此,无论您做什么,都永远不会找到不存在的变量的扩展。
我终于弄清楚你在做什么。我认为这是PHP的扩展:上传前重命名文件
简单的答案:你不能按照你的设想去做。原因 - 创建 URL 时不会解析"$filename",但变量会传递到 Amazon S3 并在那里进行处理。
解决方案
因此,我能想到的唯一选择是使用"successRedirect"参数指向另一个URL。该 URL 将从 Amazon 接收"存储桶"和"密钥"作为查询参数 (http://doc.s3.amazonaws.com/proposals/post.html#Dealing_with_Success(。将其指向 PHP 脚本,该脚本在 Amazon S3 上重命名文件(复制 + 删除(,然后将用户重定向到另一个成功屏幕。
所以
在您的代码第 34 行中,
- 将完全限定的 URL 添加到要访问的新 PHP 脚本文件中写。
- PHP 脚本将获取传递给它的存储桶和密钥
- 从"密钥"创建新文件名
- 使用函数"公共静态函数"copyObject($srcBucket, $srcUri, $bucket, $uri(" 来复制上传的文件到新名称
- 然后删除原始文件(使用 deleteObject($bucket, $uri((
- 然后将用户重定向到您要将他们发送到的位置
这将完全按照您的要求。
回应您的评论"这是唯一的方法 - 亚马逊按请求收取的费用如何?
删除请求是免费的。在同一存储桶(甚至在同一区域中(移动时,不会产生数据传输成本。因此,此解决方案(这是无需您转移到中间服务器,重命名和上传的唯一方法(它将上传成本从每 1000 次上传 1c 增加到每 1000 次上传 2c。我花了 10 分钟 @ $200/小时才发现并回复 = $33 = 1,666,666 上传!当你做数学时,成本有点苍白:)
与其他解决方案进行比较:向网络服务器发帖,重命名文件,然后从网络服务器上传:您将所有带宽从 clinet 直接移动到自己身上 - 两次。这也带来了风险并增加了可能的故障点。
回应"不起作用。我上传一个文件,然后旧的文件被删除">
我断言这不是问题,因为您上传文件然后在一两秒内重命名它。但是,如果你想保证每个文件都被上传,那么你需要做的不仅仅是创建一个随机文件名:
- 拥有您的"最终"存储桶
- 对于每次上传,创建一个临时存储桶(如果您担心成本,则为每 1000 个存储桶 1c(
- 上传到临时存储桶
- 创建随机名称,检查最终存储桶中是否存在(每 1000 次检查 1c(
- 将文件复制到最终存储桶(使用新名称(
- 删除上传的文件以及存储桶。
- 定期清理文件上传未完成的存储桶。
$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();
你会得到像"狗.png"这样的东西吗?如果您不这样做,则获取文件名的方式有问题。如果你确实得到像"狗.png"这样的东西,这是我用来获取文件扩展名的。
$pieces = explode('.',trim($filename));
$extension = end($pieces);
然后你应该能够做到这一点:
$params->key = rand_string(5).'.'.$extension;
您需要首先找出原始扩展名是什么,而不是重命名整个文件。所以保留扩展名并重命名 de 文件名。
假设您在 $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<</p>
看起来实际发生的事情不是现在完全生成文件名,而是实际上通过接口传递一个非常小的"程序",以便它可以稍后生成文件名(当变量$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 ) . ' → ' . print_r( $newValue, true );
}
public function emitVariableSetNew( $variableName, $newValue ) {
echo '<br />[global/init] '. $variableName . ' → ' . 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