user2101411
user2101411

Reputation: 1202

Repeating image count for both directories

I'm using the glob function in PHP to browse directories and trying to also match up only the image files. This is working but when I try to count the images in each directory, it repeats the count of the first directory for the others. For example, directory 1 has 6 images and directory 2 has 4 images but when I try to display the count for each directory, it shows 6 images for directory 2 and so forth.

Here is the code I have in place:

public function viewphotoalbumsAction()
{
    $identity = $this->identity();
    $dirname = array();
    $files = array();

    foreach (glob(getcwd() . '/public/images/profile/' . $identity . '/albums/*', GLOB_ONLYDIR) as $dir) {
        $dirname[] = basename($dir);

        foreach (glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE) as $images) {
            $files[] = $images;
        }
    }
    //var_dump($files); exit;

    $data = array(
        'albums' => array_values($dirname),
        'files'  => $files,
    );

    return new ViewModel(array('album' => $data['albums'], 'files' => $data['files']));
}

The results of var_dump()

 array(9) { [0]=> string(96) "C:\xampp\htdocs/public/images/profile/fooboy/albums/bone mom's album_2017-07-03/massive snow.jpg"
[1]=> string(91) "C:\xampp\htdocs/public/images/profile/fooboy/albums/bone mom's album_2017-07-03/mom-jon.jpg" 
[2]=> string(90) "C:\xampp\htdocs/public/images/profile/fooboy/albums/bone mom's album_2017-07-03/sunset.jpg" 
[3]=> string(85) "C:\xampp\htdocs/public/images/profile/fooboy/albums/random photos_2017-07-02/cref.jpg" 
[4]=> string(88) "C:\xampp\htdocs/public/images/profile/fooboy/albums/random photos_2017-07-02/diploma.jpg" 
[5]=> string(86) "C:\xampp\htdocs/public/images/profile/fooboy/albums/random photos_2017-07-02/eeyor.jpg" 
[6]=> string(93) "C:\xampp\htdocs/public/images/profile/fooboy/albums/random photos_2017-07-02/frother-jaws.jpg" 
[7]=> string(88) "C:\xampp\htdocs/public/images/profile/fooboy/albums/random photos_2017-07-02/frother.jpg" 
[8]=> string(93) "C:\xampp\htdocs/public/images/profile/fooboy/albums/random photos_2017-07-02/goat_singing.jpg" }

It is getting all the images from each directory as expected but what I really need to do is separate the images so I can have a accurate count for each directory and not just have it show the whole count (9)

The view code:

<div class="w3-col m7">
    <div class="w3-row-padding">
        <div class="w3-col m12">
            <div class="w3-card-2 w3-round w3-white">
                <div class="w3-container w3-padding" id="view-photo-albums">
                    <p class="w3-center">Current Albums</p>
                    <br>
                    <?php
foreach ($this->album as $albums):
    ?>
                    <p>
                        <?php echo $albums; ?> - Number of images: <?php echo $this->files; ?>
                    </p>
                    <?php endforeach; ?>
                </div>
            </div>
        </div>
    </div>
</div>

Any help would be appreciated.

Update:
I cannot use array_values for $data['files'] as I did for $data['albums'] as it is giving a warning of array to string conversion.

Upvotes: 7

Views: 217

Answers (5)

axiac
axiac

Reputation: 72256

There is a problem in this fragment of code:

foreach (glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE) as $images) {
     $files[] = $images;
}

The variable $dir was used to iterate the array returned by the first invocation of glob():

foreach (glob(...) as $dir) {
    ...
}

Its value after the first foreach loop ends is the last value that was assigned to it into the foreach loop.

In the end, $data['albums'] contains all the directory names and $data['files'] contains the names of the files inside the last directory listed in $data['albums'].

I cannot use array_values for $data['files'] as I did for $data['albums'] as it is giving a warning of array to string conversion.

array_values() doesn't produce anything new for the $dirname and $files. If they are created (!) these two variables contain values indexed by sequential numbers starting with 0; this is exactly what array_values() returns.

The intention of the code you posted is not very clear for me. I assume you want to display the list of albums and how many images contain each album.

This is how I would do it:

public function viewphotoalbumsAction()
{
    $identity = $this->identity();

    // Always initialize the arrays before putting values into them.
    // Without this, if the first glob() returns an empty array, the outer
    // foreach loop never runs and both $dirname and $files end up being undefined
    // and this produces trouble in the code that uses these variables later.
    $dirname = array();
    // This will be a two dimensional array. It is indexed by directory
    // names and contains the lists of files for each directory.
    $files   = array();

    // The outer loop enumerates the albums
    foreach (glob(getcwd() . '/public/images/profile/' . $identity . '/albums/*', GLOB_ONLYDIR) as $dir) {
        // The directory name is the album name
        $albumName = basename($dir);

        // Put the album name in $dirname[]
        // This is not really needed as we also have the album name
        // as key in $files but can be useful if you want to keep more
        // information about each album
        $dirname[] = $albumName;

        // Initialize the list of images of this album
        $files[$albumName] = array();

        // The inner loop enumerates the images of this directory
        foreach (glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE) as $images) {
            $files[] = $images;
        }
    }

    // Prepare the data for display
    $data = array(
        'albums' => $dirname,
        'files'  => $files,
    );

    return new ViewModel($data);
}

The view (ignored the HTML wrapper, it is ok as it is):

<?php foreach ($this->files as $albumName => $listFiles): ?>
    <p>
        <?php echo $albumName; ?> - Number of images: <?php echo count($listFiles); ?>
    </p>
<?php endforeach; ?>

As a remark, the inner foreach loop is not even needed because all it does is to copy one by one the values from the array returned by glob() into a new array.

It is faster and easier to read and understand to just store the value returned by glob() into $files[$albumName]. Since the values stored in $dirname are never used, this variable can be omitted completely and the function becomes shorter (comments omitted):

public function viewphotoalbumsAction()
{
    $identity = $this->identity();
    $files    = array();

    foreach (glob(getcwd().'/public/images/profile/'.$identity.'/albums/*', GLOB_ONLYDIR) as $dir) {
        $albumName = basename($dir);
        $files[$albumName] = glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE);
    }

    return new ViewModel(array('files' => $files));
}

Upvotes: 5

davejal
davejal

Reputation: 6133

In your public function de last dir will be the directory used in your second statement, which results in only the files counted in this folder.

change this:

foreach (glob(getcwd() . '/public/images/profile/' . $identity . '/albums/*', GLOB_ONLYDIR) as $dir) {
        $dirname[] = basename($dir);
    }


    foreach (glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE) as $images) {
         $files[] = $images;
    }

into

foreach (glob(getcwd() . '/images/albums/*', GLOB_ONLYDIR) as $dir) 
{
     $dirname[] = basename($dir);

         foreach (glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE) as $images) 
         {
          $files[] = $images;
         }
}

Upvotes: 2

Osama
Osama

Reputation: 3040

May be you need to end the first foreach statement after the end of the second one not before it so each $dir has its own $images

 public function viewphotoalbumsAction()
    {
        $identity = $this->identity();

        foreach (glob(getcwd() . '/public/images/profile/' . $identity . '/albums/*', GLOB_ONLYDIR) as $dir) {
            $dirname[] = basename($dir);



        foreach (glob($dir . '/*.{jpg,png,gif}', GLOB_BRACE) as $images) {
             $files[] = $images;
        }
    }

        $data = array(
            'albums' => array_values($dirname),
            'files'  => $files,
        );

        return new ViewModel(array('album' => $data['albums'], 'files' => count($data['files'])));
    }

Upvotes: 2

jsmean
jsmean

Reputation: 239

I think you need to explicitly declare variable type array i.e.

public function viewphotoalbumsAction()
{
    $identity = $this->identity();
    $dirname = array();
    $files = array();
   // continue ...
}

let me know if works. thanks.

Upvotes: 2

Minar_Mnr
Minar_Mnr

Reputation: 1405

I think you need to use foreach for files array also :

//its a demo 
foreach(array_combine($a,$b) as $key=>$value) {
    echo $key."<br/>".$value;
}//its a demo

Try this:

<div class="w3-col m7">
<div class="w3-row-padding">
    <div class="w3-col m12">
        <div class="w3-card-2 w3-round w3-white">
            <div class="w3-container w3-padding" id="view-photo-albums">
                <p class="w3-center">Current Albums</p>
                <br>
                    <?php

 foreach(array_combine($this->album,$this->files) as $albums=>$files) :
    ?>
                    <p>
                        <?php echo $albums; ?> - Number of images: <?php echo files; ?>
                    </p>
                    <?php endforeach; ?>
                </div>
        </div>
    </div>
</div>

Upvotes: 2

Related Questions