file exists () est trop lent en PHP. Quelqu'un peut-il Suggérer une solution plus rapide?

lors de l'affichage d'images sur notre site web, nous vérifions si le fichier existe avec un appel à file_exists() . On revient à une image factice si le fichier a disparu.

cependant, le profilage a montré que c'est la partie la plus lente de générer nos pages avec file_exists() prenant jusqu'à 1/2 ms par fichier. Nous testons seulement une quarantaine de fichiers, mais cela repousse toujours 20ms sur le temps de chargement de la page.

est-ce que quelqu'un peut suggérer un moyen de rendre cela plus rapide? Est-il un meilleur moyen de tester si le fichier est présent? Si je construis une cache, comment la synchroniser?

32
demandé sur Rik Heywood 2009-11-10 18:23:20

19 réponses

file_exists() devrait être une opération très peu coûteuse. Notez aussi que file_exists construit son propre cache pour aider à la performance.

voir: http://php.net/manual/en/function.file-exists.php

24
répondu RC. 2018-05-08 03:39:55

utilisez des chemins absolus! en fonction de votre include_path paramétrage PHP vérifie tout(!) ces DRS si vous vérifiez les chemins relatifs des fichiers! Vous pourriez désactiver include_path temporairement avant de vérifier l'existence.

realpath() fait la même chose mais je ne sais pas si c'est plus rapide.

mais l'accès aux fichiers e / s est toujours lent. Un accès disque dur est plus lent que le calcul quelque chose dans le processeur, normalement.

20
répondu powtac 2009-11-10 15:37:03

la manière la plus rapide de vérifier l'existence d'un fichier local est stream_resolve_include_path() :

if (false !== stream_resolve_include_path($s3url)) { 
  //do stuff 
}

résultats de la Performance stream_resolve_include_path() vs file_exists() :

Test name       Repeats         Result          Performance     
stream_resolve  10000           0.051710 sec    +0.00%
file_exists     10000           0.067452 sec    -30.44%

dans le test utilisé chemins absolus. La source d'essai est ici . Version PHP:

PHP 5.4.23-1~dotdeb.1 (cli) (construit en Décembre 13 2013 21:53:21)

Copyright (c) 1997-2013 Le Groupe PHP

Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies

15
répondu Alexander Yancharuk 2014-01-22 10:56:58

Nous fait retomber en une image factice si le fichier est manquant

si vous êtes simplement intéressé à revenir à cette image factice, vous pourriez envisager de laisser le client négocier avec le serveur au moyen d'une redirection (vers l'image factice) sur le fichier-not-found.

de cette façon, vous aurez juste une petite redirection au-dessus et un retard non-perceptible du côté du client. Au moins, vous vous débarrasserez du "cher"" (ce qui n'est pas, je sais) appel à file_exists .

juste une pensée.

10
répondu jensgram 2009-11-10 15:43:17

"151960920 des" points de référence avec PHP 5.6:

Fichier Existant:

0.0012969970 : stream_resolve_include_path + include  
0.0013520717 : file_exists + include  
0.0013728141 : @include  

Fichier Invalide:

0.0000281333 : file_exists + include  
0.0000319480 : stream_resolve_include_path + include  
0.0001471042 : @include  

Dossier Non Valide:

0.0000281333 : file_exists + include  
0.0000360012 : stream_resolve_include_path + include  
0.0001239776 : @include  

Code:

// microtime(true) is less accurate.
function microtime_as_num($microtime){
  $time = array_sum(explode(' ', $microtime));
  return $time;
}

function test_error_suppression_include ($file) {
  $x = 0;
  $x = @include($file);
  return $x;
}

function test_file_exists_include($file) {
  $x = 0;
  $x = file_exists($file);
  if ($x === true) {
    include $file;
  }
  return $x;
}

function test_stream_resolve_include_path_include($file) {
  $x = 0;
  $x = stream_resolve_include_path($file);
  if ($x !== false) {
    include $file;
  }
  return $x;
}

function run_test($file, $test_name) {
  echo $test_name . ":\n";
  echo str_repeat('=',strlen($test_name) + 1) . "\n";

  $results = array();
  $dec = 10000000000; // digit precision as a multiplier

  $i = 0;
  $j = 0;
  $time_start = 0;
  $time_end = 0;
  $x = -1;
  $time = 0;

  $time_start = microtime();
  $x= test_error_suppression_include($file);
  $time_end = microtime();
  $time = microtime_as_num($time_end) - microtime_as_num($time_start);

  $results[$time*$dec] = '@include';

  $i = 0;
  $j = 0;
  $time_start = 0;
  $time_end = 0;
  $x = -1;
  $time = 0;

  $time_start = microtime();
  $x= test_stream_resolve_include_path_include($file);
  $time_end = microtime();
  $time = microtime_as_num($time_end) - microtime_as_num($time_start);

  $results[$time * $dec] = 'stream_resolve_include_path + include';

  $i = 0;
  $j = 0;
  $time_start = 0;
  $time_end = 0;
  $x = -1;
  $time = 0;

  $time_start = microtime();
  $x= test_file_exists_include($file);
  $time_end = microtime();
  $time = microtime_as_num($time_end) - microtime_as_num($time_start);

  $results[$time * $dec ] = 'file_exists + include';

  ksort($results, SORT_NUMERIC);

  foreach($results as $seconds => $test) {
    echo number_format($seconds/$dec,10) . ' : ' . $test . "\n";
  }
  echo "\n\n";
}

run_test($argv[1],$argv[2]);

exécution en ligne de commande:

php test.php '/path/to/existing_but_empty_file.php' 'Existing File'  
php test.php '/path/to/non_existing_file.php' 'Invalid File'  
php test.php '/path/invalid/non_existing_file.php' 'Invalid Folder'  
4
répondu Jonathan Falkner 2016-08-25 16:47:46

file_exists() est automatiquement mis en cache par PHP. Je ne pense pas que vous trouverez une fonction plus rapide en PHP pour vérifier l'existence d'un fichier.

voir ce fil .

3
répondu mculp 2017-05-23 11:55:19

crée une routine de hachage pour découper les fichiers en plusieurs sous-répertoires.

nom du fichier.jpg -> 012345 -> /01/23/45.jpg

aussi, vous pouvez utiliser mod_rewrite pour retourner votre image de remplacement pour les requêtes à votre répertoire d'image que 404.

3
répondu racerror 2018-05-08 03:41:42

Je ne sais pas exactement ce que vous voulez faire, mais vous pourriez juste laisser le client s'en charger .

2
répondu ViperArrow 2017-05-23 11:33:19

si vous ne faites que vérifier l'existence de files , utilisez is_file() . file_exists() vérifie pour un fichier ou un répertoire existant, donc peut-être is_file() pourrait être un peu plus rapide.

2
répondu Alex 2018-05-08 03:41:56

Sont-ils tous dans le même répertoire? Si c'est le cas, il peut vaut la peine d'obtenir la liste des fichiers et de les stocker dans un hachage et de comparer avec cela plutôt que toutes les recherches de file_exists.

1
répondu easement 2009-11-10 15:34:27

Si vous voulez vérifier l'existence d'un fichier image, un beaucoup plus rapide façon est d'utiliser des getimagesize !

plus rapide localement et à distance!

if(!@GetImageSize($image_path_or_url)) // False means no imagefile
 {
 // Do something
 }
1
répondu Fabrice Oppitz 2015-02-11 10:27:04

je trouve 1/2 ms par appel très, très abordable. Je ne pense pas qu'il existe des alternatives plus rapides, car les fonctions de fichiers sont très proches des couches inférieures qui gèrent les opérations de fichiers.

vous pouvez cependant écrire un wrapper à file_exists() qui cache les résultats dans une memcache ou une installation similaire. Cela devrait réduire le temps à presque rien dans l'utilisation quotidienne.

0
répondu Pekka 웃 2009-11-10 15:39:36

vous pouvez faire un cronjob pour créer périodiquement une liste d'images et les stocker dans DB/file/BDB/...

toutes les demi-heures devrait être parfait, mais assurez-vous de créer une interface pour réinitialiser le cache en cas d'Ajout/Suppression de fichier.

et puis, il est aussi facile de trouver . -mmin -30 -print0 sur la coque et ajouter de nouveaux fichiers.

0
répondu anttir 2011-04-19 08:08:17

lorsque vous enregistrez un fichier dans un dossier, si le téléchargement a été réussi, vous pouvez stocker le chemin vers une Table DB.

alors vous aurez juste à faire une requête à la base de données afin de trouver le chemin du fichier demandé.

0
répondu Galois 2012-01-26 11:04:05

je suis venu à cette page à la recherche d'une solution, et il semble que fopen peut faire l'affaire. Si vous utilisez ce code, vous pouvez désactiver la journalisation des erreurs pour les fichiers qui ne sont pas trouvés.

<?php
for ($n=1;$n<100;$n++){
clearstatcache();
$h=@fopen("files.php","r");
if ($h){
echo "F";
fclose($h);
}else{
echo "N";
}
}
?>
0
répondu 2014-09-21 20:23:38

question ancienne, je vais ajouter une réponse ici. Pour php 5.3.8, is_file() (pour un fichier existant) est d'un ordre de grandeur plus rapide. Pour un fichier non-existant, les temps sont presque identiques. Pour PHP 5.1 avec eaccelerator, ils sont un peu plus proches.

PHP 5.3.8 w & w/o APC

time ratio (1000 iterations)
Array
(
    [3."is_file('exists')"] => 1.00x    (0.002305269241333)
    [5."is_link('exists')"] => 1.21x    (0.0027914047241211)
    [7."stream_resolve_inclu"(exists)] => 2.79x (0.0064241886138916)
    [1."file_exists('exists')"] => 13.35x   (0.030781030654907)
    [8."stream_resolve_inclu"(nonexists)] => 14.19x (0.032708406448364)
    [4."is_file('nonexists)"] => 14.23x (0.032796382904053)
    [6."is_link('nonexists)"] => 14.33x (0.033039808273315)
    [2."file_exists('nonexists)"] => 14.77x (0.034039735794067)
)

PHP 5.1 w /eaccelerator

time ratio (1000x)
Array
(
    [3."is_file('exists')"] => 1.00x    (0.000458002090454)
    [5."is_link('exists')"] => 1.22x    (0.000559568405151)
    [6."is_link('nonexists')"] => 3.27x (0.00149989128113)
    [4."is_file('nonexists')"] => 3.36x (0.00153875350952)
    [2."file_exists('nonexists')"] => 3.92x (0.00179600715637)
    [1."file_exists('exists"] => 4.22x  (0.00193166732788)
)

il y a quelques mises en garde.

1) tous les fichiers "" sont des fichiers, is_file() teste régulier les fichiers, pas les liens symboliques. Donc sur un système * nix, vous ne pouvez pas vous en tirer avec is_file () à moins que vous ne soyez sûr que vous ne traitiez que des fichiers réguliers. Pour les téléchargements, etc, cela peut être une hypothèse raisonnable, ou si le serveur est basé sur Windows, qui n'a pas réellement de liens symboliques. Sinon, vous devrez tester is_file($file) || is_link($file) .

2) La Performance se dégrade définitivement pour toutes les méthodes si le fichier est manquant et devient à peu près égale.

3) la plus grosse mise en garde. Toutes les méthodes mettent en cache les statistiques de fichier pour accélérer la recherche, donc si le fichier change régulièrement ou rapidement, supprimé, réapparaît, supprime, alors clearstatcache(); doit être exécuté pour s'assurer que l'information d'existence de fichier correcte est dans le cache. J'ai donc testé les. J'ai laissé de côté tous les noms de fichiers et autres. L'important est que presque tous les temps convergent, sauf stream_resolve_include, qui est 4x aussi vite. Encore une fois, ce serveur a eaccelerator sur lui, donc YMMV.

time ratio (1000x)
Array
(
    [7."stream_resolve_inclu...;clearstatcache();"] => 1.00x    (0.0066831111907959)
    [1."file_exists(...........;clearstatcache();"] => 4.39x    (0.029333114624023)
    [3."is_file(................;clearstatcache();] => 4.55x    (0.030423402786255)
    [5."is_link(................;clearstatcache();] => 4.61x    (0.030798196792603)
    [4."is_file(................;clearstatcache();] => 4.89x    (0.032709360122681)
    [8."stream_resolve_inclu...;clearstatcache();"] => 4.90x    (0.032740354537964)
    [2."file_exists(...........;clearstatcache();"] => 4.92x    (0.032855272293091)
    [6."is_link(...............;clearstatcache();"] => 5.11x    (0.034154653549194)
)

fondamentalement, l'idée est, si vous êtes sûr à 100% que c'est un fichier, pas un lien symbolique ou un répertoire, et selon toute probabilité, il existera, puis utiliser is_file() . Vous verrez un atout certain. Si le fichier peut être un fichier ou un lien symbolique à tout moment, alors le fichier is_file() 14x + is_link() 14x ( is_file() || is_link() ) qui a échoué sera 2 fois plus lent dans l'ensemble. Si l'existence du fichier change beaucoup, alors utilisation stream_resolve_include_path().

Donc, cela dépend de votre scénario d'utilisation.

0
répondu Beracah 2016-08-21 05:49:02

je pense que la meilleure façon est de garder l'url de l'image dans la base de données et ensuite la mettre dans une variable de session en particulier quand vous avez l'authentification. De cette façon, vous n'avez pas à vérifier chaque fois qu'une page se recharge

0
répondu daRula 2017-05-09 02:40:53

et glob() ? Mais je ne suis pas sûr si c'est rapide.

http://www.php.net/manual/en/function.glob.php

0
répondu juno 2018-05-08 03:42:15

Je ne suis même pas sûr si ce sera plus rapide, mais il semble que vous voudriez encore benchmark soooo:

construisez une cache d'un large éventail de tous les chemins d'image.

$array = array('/path/to/file.jpg' => true, '/path/to/file2.gif' => true);

mettre à Jour le cache horaire ou quotidien en fonction de vos exigences. Vous feriez cela en utilisant cron pour exécuter un script PHP qui ira récursivement à travers le répertoire de fichiers pour générer le tableau de chemins.

quand vous voulez vérifier si un fichier existe, chargez votre tableau caché et faites simplement isset () vérifiez pour une recherche d'index de tableau rapide:

if (isset($myCachedArray[$imgpath])) {
    // handle display
}

il y aura toujours des frais généraux à partir du chargement du cache, mais on espère qu'il sera assez petit pour rester en mémoire. Si vous avez plusieurs images que vous enregistrez sur une page, vous remarquerez probablement plus de gains importants comme vous pouvez charger le cache sur le chargement de page.

-1
répondu Corey Ballou 2009-11-10 15:51:27