【问题标题】:PHP get actual maximum upload sizePHP获取实际的最大上传大小
【发布时间】:2012-10-16 02:27:36
【问题描述】:

使用时

ini_get("upload_max_filesize");

它实际上为您提供了 php.ini 文件中指定的字符串。

不宜将此值用作最大上传大小的参考,因为

  • 可以使用所谓的shorthandbytes,比如1M等等,需要大量额外的解析
  • 当upload_max_filesize例如0.25M时,实际上是零,再次使得解析值变得更加困难
  • 此外,如果该值包含任何空格,则 php 将其解释为零,而在使用 ini_get 时显示不带空格的值

那么,除了ini_get 报告的那个值之外,还有什么方法可以获取 PHP 实际使用的值,或者确定它的最佳方法是什么?

【问题讨论】:

标签: php


【解决方案1】:

这里是完整的解决方案。它处理所有陷阱,如速记字节表示法,还考虑 post_max_size:

/**
* This function returns the maximum files size that can be uploaded 
* in PHP
* @returns int File size in bytes
**/
function getMaximumFileUploadSize()  
{  
    return min(convertPHPSizeToBytes(ini_get('post_max_size')), convertPHPSizeToBytes(ini_get('upload_max_filesize')));  
}  

/**
* This function transforms the php.ini notation for numbers (like '2M') to an integer (2*1024*1024 in this case)
* 
* @param string $sSize
* @return integer The value in bytes
*/
function convertPHPSizeToBytes($sSize)
{
    //
    $sSuffix = strtoupper(substr($sSize, -1));
    if (!in_array($sSuffix,array('P','T','G','M','K'))){
        return (int)$sSize;  
    } 
    $iValue = substr($sSize, 0, -1);
    switch ($sSuffix) {
        case 'P':
            $iValue *= 1024;
            // Fallthrough intended
        case 'T':
            $iValue *= 1024;
            // Fallthrough intended
        case 'G':
            $iValue *= 1024;
            // Fallthrough intended
        case 'M':
            $iValue *= 1024;
            // Fallthrough intended
        case 'K':
            $iValue *= 1024;
            break;
    }
    return (int)$iValue;
}      

【讨论】:

  • 我不知道这实际上是如何工作的(特别是 switch 语句),直到我最终意识到 switch 语句中只有一个“break”语句,以及“case”的顺序线条很重要。它工作得很好,但我害怕一些初级程序员以后会回去尝试修改这段代码。也许“更标准化”的版本会是更好的长期解决方案?
  • 好吧,这并不能真正解决我在问题中提到的问题,因为它只是使用 ini_get() ;-) 我们已经有很多这样的答案了。
  • @GavinG 我现在已经根据 PSR-2 的要求添加了适当的 cmets,因此失败是显而易见的。
  • 链接已失效...
【解决方案2】:

Drupal 相当优雅地实现了这一点:

// Returns a file size limit in bytes based on the PHP upload_max_filesize
// and post_max_size
function file_upload_max_size() {
  static $max_size = -1;

  if ($max_size < 0) {
    // Start with post_max_size.
    $post_max_size = parse_size(ini_get('post_max_size'));
    if ($post_max_size > 0) {
      $max_size = $post_max_size;
    }

    // If upload_max_size is less, then reduce. Except if upload_max_size is
    // zero, which indicates no limit.
    $upload_max = parse_size(ini_get('upload_max_filesize'));
    if ($upload_max > 0 && $upload_max < $max_size) {
      $max_size = $upload_max;
    }
  }
  return $max_size;
}

function parse_size($size) {
  $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
  $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
  if ($unit) {
    // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
    return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
  }
  else {
    return round($size);
  }
}

上述功能在 Drupal 中的任何地方都可用,或者您可以根据 GPL 许可版本 2 或更高版本的条款将其复制并在您自己的项目中使用。

至于问题的第 2 部分和第 3 部分,您需要直接解析 php.ini 文件。这些本质上是配置错误,PHP 正在诉诸回退行为。看来您实际上可以在 PHP 中获取已加载的 php.ini 文件的位置,尽管尝试从中读取可能无法在启用 basedir 或安全模式的情况下工作:

$max_size = -1;
$post_overhead = 1024; // POST data contains more than just the file upload; see comment from @jlh
$files = array_merge(array(php_ini_loaded_file()), explode(",\n", php_ini_scanned_files()));
foreach (array_filter($files) as $file) {
  $ini = parse_ini_file($file);
  $regex = '/^([0-9]+)([bkmgtpezy])$/i';
  if (!empty($ini['post_max_size']) && preg_match($regex, $ini['post_max_size'], $match)) {
    $post_max_size = round($match[1] * pow(1024, stripos('bkmgtpezy', strtolower($match[2])));
    if ($post_max_size > 0) {
      $max_size = $post_max_size - $post_overhead;
    }
  }
  if (!empty($ini['upload_max_filesize']) && preg_match($regex, $ini['upload_max_filesize'], $match)) {
    $upload_max_filesize = round($match[1] * pow(1024, stripos('bkmgtpezy', strtolower($match[2])));
    if ($upload_max_filesize > 0 && ($max_size <= 0 || $max_size > $upload_max_filesize) {
      $max_size = $upload_max_filesize;
    }
  }
}

echo $max_size;

【讨论】:

  • pow 行非常优雅,但这仅解决了问题中列出的 3 个问题之一。
  • 好吧,另外两个问题实际上是配置错误,而不是需要考虑的有效情况。但是为了检查配置错误,这只能通过在 PHP 尝试解析无效条目之前直接读取 php.ini 文件来完成。而且由于 php.ini 可以在任何地方,这不是检查活动配置的稳定或跨平台方式。 $ini = parse_ini_file('/etc/php.ini'); $ini['upload_max_filesize']呢?
  • 澄清一下,自从我之前发表评论以来,我已经用一些代码更新了帖子,以找到活动的php.ini 文件并直接解析它。
  • 这对我来说似乎是目前最好的选择。如果 php.ini 不可读,则回退到 ini_get()。非常好。
  • 如果这个限制真的被强制执行了,我假设是这样,它是由允许 php 运行的 Apache 或 CGI 控制器处理的吗? 他们如何处理它? DRY 说我们应该找到将其转换为字节的内部机制,而不是让我们自己的代码臃肿(假设我们还没有运行 Drupal)。
【解决方案3】:

这是我用的:

function asBytes($ini_v) {
   $ini_v = trim($ini_v);
   $s = [ 'g'=> 1<<30, 'm' => 1<<20, 'k' => 1<<10 ];
   return intval($ini_v) * ($s[strtolower(substr($ini_v,-1))] ?: 1);
}

【讨论】:

  • 2020年我们可以使用kbs 1 1 1 1 1 ][strtolower(substr(trim($v),-1))] ?: 1) ;回声(kbs('1g')); ?>
【解决方案4】:

看起来不可能。

因此,我将继续使用此代码:

function convertBytes( $value ) {
    if ( is_numeric( $value ) ) {
        return $value;
    } else {
        $value_length = strlen($value);
        $qty = substr( $value, 0, $value_length - 1 );
        $unit = strtolower( substr( $value, $value_length - 1 ) );
        switch ( $unit ) {
            case 'k':
                $qty *= 1024;
                break;
            case 'm':
                $qty *= 1048576;
                break;
            case 'g':
                $qty *= 1073741824;
                break;
        }
        return $qty;
    }
}
$maxFileSize = convertBytes(ini_get('upload_max_filesize'));

最初来自this有帮助的php.net评论。

仍然愿意接受更好的答案

【讨论】:

    【解决方案5】:

    你总是可以使用这个语法,它会从 PHP ini 文件中为你提供正确的数字:

    $maxUpload      = (int)(ini_get('upload_max_filesize'));
    $maxPost        = (int)(ini_get('post_max_size'));
    

    市场

    【讨论】:

    • 你读过开头的帖子吗? echo ini_get('post_max_size'); -&gt; 8Mecho (int)(ini_get('post_max_size'));-&gt; 8
    【解决方案6】:

    我不这么认为,至少不是按照您定义的方式。对于最大文件上传大小,还有很多其他因素需要考虑,最显着的是用户的连接速度以及 Web 服务器的超时设置以及 PHP 进程。

    对您来说更有用的指标可能是确定对于给定输入您希望接收的文件类型的合理最大文件大小。决定什么对您的用例来说是合理的,并为此制定政策。

    【讨论】:

    • 当然,这就是我正在做的。但我仍然绝对需要知道 php.ini 中允许的大小是否低于我推荐的最大大小。
    猜你喜欢
    • 2010-10-18
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 2011-12-19
    相关资源
    最近更新 更多