tags:

views:

65

answers:

4

hi every one. In my application there is a folder name videos. i want to raed all file only of this folder I have done almostly it does not show any folder in folder videos except .DS_Store currently i have applied if condition to hide this but i want a perfect solution can any one help:- my code is :----

<?php
      $dir = "../videos/";
 $dh = opendir($dir);
       ?>
       <select size="4" name="vidfile">
       <?php
      while (($file = readdir($dh)) !== false) {
     if (is_file($dir.'/'.$file) && $file != "." && $file != ".."){ 
     if($file!=".DS_Store"){?>
<option><?php echo $file ; ?></option>
    <?php } }

}?>
</select><?php 


      closedir($dh);?> 
+2  A: 
<?php
$dir = '../videos/';
if($dh = opendir($dir)){
   echo '<select size="4" name="vidfile">';
   while(($file=readdir($dh)) !== FALSE){
      $file = $dir . '/' . $file;
      if(!is_file($file) || substr($file, 0, 1) == '.'){
         continue;
      }
      printf('<option>%s</option>', htmlentities($file));
   }
   echo '</select>';
   closedir($dh);
}
?>

First, if opendir fails, don't continue with junk. It ignores non-files (directories) and files starting with a dot (including ., .., .htaccess, etc.)

Lekensteyn
+1  A: 

Here's a variation that works with glob() instead, has an array of excluded files, and collects all the option elements and then outputs them as one. Also, glob() allows filtering for certain file extensions through its brace syntax as shown in the out-commented line.

$dir = "../videos";
$mask = "*";
// $mask = "*.{wmv,mpeg,mpg}";  // get only files of these types

$files = glob($dir."/".$mask);
$excluded_files = array(".DS_store");
$html = null;    

if (count($files) > 0)
foreach ($files as $file)
 {
  $filename = basename($file);
  if (in_array($filename, $excluded_files)) continue;
  $html.="<option>".htmlentities($filename)."</option>";
 }

 echo $html;
Pekka
A: 

Just if ($file[0] == ".") continue; instead of these 2 if's is probably what you're looking for.
Though I'd make it slightly different, in 2 parts.
getting data part:

<?php
  $dir = "../videos/";
  $dh = opendir($dir);
  $filesarr = array();
  while (($file = readdir($dh)) !== false) {
    if ($file[0] != ".") $filesarr[] = $file;
  }
  closedir($dh);
?>

and display data part:

<select size="4" name="vidfile">
<?php foreach ($filesarr as $file): ?>
<option><?php echo $file ?></option>
<?php endforeach ?>
</select>

it seems way more clean to me

Col. Shrapnel
+2  A: 

The quick and easy solution

You could make your life easier and use a DirectoryIterator to go over the directory.

echo '<select name="vids" size="4">';
foreach( new DirectoryIterator('/path/to/videos') as $file) {
    if( $file->isFile() === TRUE && $file->getBasename() !== '.DS_Store') {
        printf("<option>%s</option>\n", htmlentities($file->getBasename()));
    }
}
echo '</select>';

Improvement: Decoupling Directory Filtering from SelectBox building

If you want to decouple the filtering logic from the foreach loop, you can subclass a FilterIterator to capsule that logic into it's accept() method. The DirectoryIterator has to be wrapped into the FilterIterator then. The main point is reusability of course:

class MyFilter extends FilterIterator
{
    public function accept()
    {
        return $this->current()->isFile() === TRUE &&
               $this->current()->getBasename() !== '.DS_Store';
    }
}

$iterator = new MyFilter(new DirectoryIterator('/path/to/videos'));

When you use foreach on a filtered iterator, it will trigger accept() automatically. If accept() returns FALSE, the current element will be filtered out in the iteration.

You create the SelectBox like this then:

echo '<select name="vids" size="4">';
foreach( $iterator as $file) {
    printf("<option>%s</option>\n", htmlentities($file->getBasename()));
}
echo '</select>';

Alternative to subclassing FilterIterator

If you are too lazy to write a separate FilterIterator or think it's just not worth it for a specific case or already have validators somewhere and dont want to duplicate their code, but still want to decouple Filtering and SelectBox creation, you can also use this custom FilterChainIterator and add callbacks to it:

$iterator = new FilterChainIterator(new DirectoryIterator('/path/to/videos'));
$iterator->addCallback(function($file) {
    return $file->isFile() === TRUE &&
           $file->getBasename() !== '.DS_Store';}); 

The SelectBox creation would be the same as shown above.


Improvement: Making SelectBox creation reusable

In addition, if you want to make the SelectBox creation reusable, why not create a Helper for it. Below is a very simple one that uses DOM to create the actual HTML. You pass in any Iterator and it will create the HTML for you when you call it's render() method or use it in a string context:

class SelectBox
{
    protected $iterator;
    public function __construct(Iterator $iterator)
    {
        $this->iterator = $iterator;
    }
    public function render()
    {
        $dom = new DOMDocument;
        $dom->formatOutput = TRUE;
        $dom->loadXml('<select name="vids"/>');
        $dom->documentElement->appendChild(new DOMElement('option', 'Pick One'));
        foreach($this->iterator as $option) {
            $dom->documentElement->appendChild(
                new DOMElement('option', $option));
        }
        return $dom->saveXml($dom->documentElement);
    }
    public function __toString()
    {
        return $this->render();
    }
}

And then printing a SelectBox from an Iterator is as simple as

echo new SelectBox(new MyFilter(new DirectoryIterator('/path/to/videos')));

That's pretty flexible then, given that there is Iterators for everything. For instance

echo new SelectBox(new ArrayIterator(array('foo', 'bar', 'baz')));

would give a neatly formatted

<select>
  <option>Pick One</option>
  <option>foo</option>
  <option>bar</option>
  <option>baz</option>
</select>
Gordon