94 votes

Comment gérer élégamment les fichiers qui dépassent la `post_max_size` de PHP ?

Je travaille sur un formulaire PHP qui joint un fichier à un e-mail, et j'essaie de gérer de manière élégante les cas où le fichier téléchargé est trop volumineux.

J'ai appris qu'il existe deux paramètres dans php.ini qui affectent la taille maximale d'un téléchargement de fichier : upload_max_filesize et post_max_size.

Si la taille d'un fichier dépasse upload_max_filesize, PHP retourne la taille du fichier comme étant 0. C'est bien ; je peux vérifier cela.

Mais s'il dépasse post_max_size, mon script échoue silencieusement et revient au formulaire vierge.

Y a-t-il un moyen de capturer cette erreur ?

1 votes

Avez-vous accès au php.ini? post_max_size doit être réglé plus grand que upload_max_filesize. Vous devriez également utiliser sur le formulaire comme indiqué ca2.php.net/manual/en/features.file-upload.post-method.php

0 votes

@Matt McCormick - l'entrée MAX_FILE_SIZE fonctionne très bien - si la taille du fichier dépasse cela, la taille du fichier s'affiche maintenant comme 0, ce qui est un cas que j'ai déjà pris en charge. Même si cela peut être contourné par un utilisateur malveillant, cela répond à mes besoins ici, car je cherche simplement à échouer de manière élégante pour les utilisateurs réguliers.

1voto

BogisW Points 76

J'avais le même problème et j'ai combiné certaines des solutions déjà publiées sur cette page (par @Doblas, @Lance Cleveland et @AbdullahAJM).

De plus, ma solution tente d'envoyer une erreur 413 Payload Too Large (au lieu de 200 OK), ce qui est bien sûr uniquement possible si php.ini n'est pas configuré pour afficher les avertissements.

// Vérifier les Avertissements de php attrapent l'Avertissement: Inconnu: La longueur du contenu POST de bytes dépasse la limite de bytes dans Inconnu à la ligne 0
// L'envoi de 413 ne fonctionne que si les Avertissements sont désactivés dans php.ini!!!

// récupérer les limites de taille...
$postMaxSize = trim(ini_get('post_max_size')); 
if (strlen($postMaxSize)>0) {
   $postMaxSizeValue = substr($postMaxSize, 0, -1);
   $postMaxSizeUnit = strtolower(substr($postMaxSize, -1));
   $postMaxSize = 0; // rendre son utilisation sûre
   if (false !== filter_var($postMaxSizeValue, FILTER_VALIDATE_INT, array('options' => array( 'min_range' => 0)))) {
      switch ($postMaxSizeUnit) {
         case 'g': $postMaxSizeValue*=1024; // ... puis continuer
         case 'm': $postMaxSizeValue*=1024; // ... puis continuer
         case 'k': $postMaxSizeValue*=1024; break;
         default: if ($postMaxSizeUnit>='0' && $postMaxSizeUnit<='9') {
                     $postMaxSizeValue = (int) $postMaxSizeValue.$postMaxSizeUnit;
                  } else {
                     $postMaxSizeValue = 0;
                  }
      }
      $postMaxSize = $postMaxSizeValue;
   }
} else {
   $postMaxSize = 0;
}

if (empty($_FILES) && empty($_POST) &&
    isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' &&
    isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > $postMaxSize) {
    // s'il s'agit d'une requête POST et que la variable $_POST est vide (un symptôme d'une "erreur de taille maximale des posts")

    if (headers_sent()) {
       // afficher l'erreur et les solutions...
       echo "\nVeuillez noter qu'une erreur 413 Payload Too Large devrait être envoyée, mais l'avertissement ne peut pas être attrapé, c'est pourquoi le client reçoit un 200 OK. ".
            "Veuillez désactiver les avertissements dans php.ini pour obtenir le comportement correct."; 
    } else {
       http_response_code(413);
    }

    // attraper l'erreur de surcharge de fichier : afficher l'erreur et les solutions...
    echo "\nVeuillez noter que les fichiers plus grands que ".$postMaxSize." entraîneront cette erreur!".
         "Veuillez noter qu'il ne s'agit pas d'une limitation dans le script, mais d'une limitation du serveur d'hébergement.";
    exit(1);
}

0voto

antoni Points 1889

Mes 2 cents. Même idée, beaucoup plus léger que d'autres réponses. Il suffit d'appeler checkPostSize();. S'il est dépassé, il plantera avec le code HTTP correct, et enregistrera l'erreur.

function checkPostSize() {
  preg_match('~(\d+)([KMG])*~', ini_get('post_max_size'), $matches);
  list(, $number, $unit) = $matches;
  $postMaxSize = $number * ($unit ? pow(1024, ['K' => 1, 'M' => 2, 'G' => 3][$unit]) : 1);

  if ((int)$_SERVER['CONTENT_LENGTH'] > $postMaxSize) {
    error_log('post_max_size de ' . ($postMaxSize / pow(1024, 2)) . 'M dépassé : ' . ~~($_SERVER['CONTENT_LENGTH'] / pow(1024, 2)) . 'M reçus.');
    http_response_code(413);
    exit;
  }
}

À noter également que lorsque votre charge utile est suffisamment importante, Chrome peut exclure la réponse de l'inspecteur et vous ne pouvez rien voir (ce n'est pas parce que votre PHP est cassé). Il est donc judicieux de journaliser les erreurs à cette fin.

Inspecteur de Chrome

Et je ne pense pas que vérifier que la méthode est POST et que $_FILES & $_POST sont vides suffisent pour déduire qu'il s'agit d'un dépassement de la taille maximale d'une requête POST, comme le suggère une autre réponse.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X