PHP получает фактический максимальный размер загрузки

При использовании

ini_get("upload_max_filesize");

он фактически дает вам строку, указанную в файле php.ini.

Неправильно использовать это значение в качестве ссылки для максимального размера загрузки, потому что

  • можно использовать так называемый shorthandbytes, например 1M и т.д., в котором требуется много дополнительного синтаксического анализа
  • когда upload_max_filesize, например, 0.25M, на самом деле это ZERO, что делает синтаксический анализ значения намного сложнее снова
  • также, если значение содержит любые пробелы, такие как оно интерпретируется как ZERO по php, тогда как при использовании ini_get оно отображается без пробелов,

Итак, есть ли способ получить значение, фактически используемое PHP, помимо сообщения, сообщенного ini_get, или что это лучший способ его определить?

Ответ 1

У 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.ini на PHP, хотя попытка чтения с него может не работать с включенным или безопасным режимом:

$max_size = -1;
$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;
    }
  }
  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;

Ответ 2

Вот полное решение. Он берет на себя все ловушки, такие как сокращенное обозначение байта, а также считает post_max_size:

/**
* 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;
}      
function getMaximumFileUploadSize()  
{  
    return min(convertPHPSizeToBytes(ini_get('post_max_size')), convertPHPSizeToBytes(ini_get('upload_max_filesize')));  
}  

Это безошибочная версия этого источника: http://www.smokycogs.com/blog/finding-the-maximum-file-upload-size-in-php/.

Ответ 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);
}

Ответ 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'));

Первоначально из этот полезный комментарий php.net.

ВСЕ ЕЩЕ ОТКРЫТЬ ДЛЯ ПРИНЯТИЯ ЛУЧШИХ ОТВЕТОВ

Ответ 5

Я так не думаю, по крайней мере, не так, как вы это определили. Существует множество других факторов, которые учитывают максимальный размер загрузки файлов, в первую очередь скорость соединения пользователя, а также время ожидания для веб-сервера, а также процессы (процессы) PHP.

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

Ответ 6

Ну, вы всегда можете использовать этот синтаксис, который даст вам правильные номера из файла PHP ini:

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

Март