How to improve the speed of a for loop in PHP?

Tags: , , ,



I have a CSV file with different lines:

;0;1;0;4;5;M;468468;A1101;0090
0;1;0;4;5;M;468468;A1108;0090

And in a folder of photos that must have the naming format “A1101_0090-1.JPG” for the first view for example.

I wrote a code that allows you to have two things:

  • the names of the images present in both the csv file and the photos folder, and the number of views
  • The names of images that are in the photos folder but not in the csv file or that are incorrectly renamed.

My script works but when I put a big photo folder with more than 5000 photos for example, the processing is very long… how could I improve my code ?

<?php
echo '<pre>';
$dataImage = [];
$dataImageTmp = [];
$path = $_POST['path'];

$photos = scandir($path);
$photos = array_map('strtoupper', $photos);

if (($handle = fopen("../RC_PRODUCT_HUB.csv", "r")) !== FALSE) {
    $firstLine = true;
    while (($data = fgetcsv($handle, 9000000, ";")) !== FALSE){
        if (!$firstLine){
            if ($data[0] != null) {
                $countImage = count(glob($path . $data[6] . '_' . $data[7] . '*.*'));
                for ($i = 0; $i <= $countImage; ++$i) {
                    if ((file_exists($fileName = $path.$data[6].'_'.$data[7].'-'.$i.'.JPG'))){
                        if (!in_array($fileName, $dataImage)){
                            $dataImage[$data[6] . '_' . $data[7]]['file'][$i] = $fileName;
                            $fileName = str_replace($path, '', $fileName);
                            if (!in_array($fileName, $dataImageTmp)){
                                $dataImageTmp[] = $fileName;
                            }
                        }
                        $dataImage[$data[6] . '_' . $data[7]]['TOTAL'] = $countImage;
                    }
                }
            }
        }
        $firstLine = false;
    } 

    //FIRST PART
    echo count($dataImage)." refs founds.<br>";
    print_r($dataImage).'<br>';

    //SECOND PART

    $dataImageTmp = array_map('strtoupper', $dataImageTmp); 
    $resultat = array_diff($photos, $dataImageTmp);
    $element = '.';
    unset($resultat[array_search($element, $resultat)]);
    $element2 = '..';
    unset($resultat[array_search($element2, $resultat)]);

    echo count($resultat)." photos found.<br>";

    foreach ($resultat as $result) {
        echo ($result) . '<br>';
    }
}
?>

Answer

Don’t call glob(). Just use a loop that processes each file that matches the pattern in numeric order. You can stop the loop when the file doesn’t exist.

I assume there are no gaps in your numeric sequence of filenames.

if (($handle = fopen("../RC_PRODUCT_HUB.csv", "r")) !== FALSE) {
    fgets($handle); // skip header line
    while (($data = fgetcsv($handle, 9000000, ";")) !== FALSE){
        if ($data[0] != null) {
            for ($i = 1; file_exists($fileName = $path.$data[6].'_'.$data[7].'-'.$i.'.JPG'); ++$i) {
                if (!in_array($fileName, $dataImage)){
                    $dataImage[$data[6] . '_' . $data[7]]['file'][$i] = $fileName;
                    $fileName = str_replace($path, '', $fileName);
                    if (!in_array($fileName, $dataImageTmp)){
                        $dataImageTmp[] = $fileName;
                    }
                }
                if (isset($dataImage[$data[6] . '_' . $data[7]]['TOTAL'])) {
                    $dataImage[$data[6] . '_' . $data[7]]['TOTAL']++;
                } else {
                    $dataImage[$data[6] . '_' . $data[7]]['TOTAL'] = 1;
                }
            }
        }
    }
} 


Source: stackoverflow