Reading files from multiple directions - php

I am trying to make a script that reads .sql files from multiple directories in a certain folder, and then to execute them into the database.
How would I make my code below able to read multiple folders. [These folders will be added/removed in future so I need it to just automatic find any folder without any partciular names.
So for example I have a folder called "mysqls" and inside that folder I have other folders such as 'text1', 'test2'. Test1 and test2 have different .sql files in that I want to be excuted.
<?php
$dirf = 'mysqls';
$dir = scandir($dirf);
unset($dir['0']);
unset($dir['1']);
foreach($dir as $file) {
$sql = file_get_contents($dirf . '/'. $file);
$qr = $dbh->exec($sql);
}
?>

$directory = new RecursiveDirectoryIterator('mysqls');
// Filter out "dot" folders
$filter = new DirnameFilter($directory, '/^(?!\.)/');
// Filter sql files
$filter = new FilenameFilter($filter, '/(?:sql)$/i');
foreach(new RecursiveIteratorIterator($filter) as $file) {
$sql = file_get_contents($file);
$qr = $dbh->exec($sql);
}
abstract class FilesystemRegexFilter extends RecursiveRegexIterator {
protected $regex;
public function __construct(RecursiveIterator $it, $regex) {
$this->regex = $regex;
parent::__construct($it, $regex);
}
}
class FilenameFilter extends FilesystemRegexFilter {
// Filter files against the regex
public function accept() {
return ( ! $this->isFile() || preg_match($this->regex, $this->getFilename()));
}
}
class DirnameFilter extends FilesystemRegexFilter {
// Filter directories against the regex
public function accept() {
return ( ! $this->isDir() || preg_match($this->regex, $this->getFilename()));
}
}

Perhaps something like this using RecursiveIteratorIterator()
<?php
function scan_for_sql_files($path){
$itdir = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::SELF_FIRST,
\RecursiveIteratorIterator::CATCH_GET_CHILD);
$files = array();
foreach ($itdir as $path=>$dir){
if ($dir->isFile()){
$ext = substr(strtolower($path), -3);
if($ext == 'sql'){
$files[] = array('path' => $path);
}
}
}
return $files;
}
//get files
$files = scan_for_sql_files('mysqls');
//Do sql
foreach($files as $file){
$sql = file_get_contents($file['path']);
$qr = $dbh->exec($sql);
}
?>

$iterator = new RecursiveDirectoryIterator('mysqls');
foreach($iterator as $fileinfo){
if('sql' == $fileinfo->getExtension()){
$sql = file_get_contents($fileinfo->getPathname());
$qr = $dbh->exec($sql);
}
}

Related

How to get the number of files in the folder recursive in php

I have folder structure like below in my web application.
How can I get the number of files in each folder recursively using php.
I'm working with Codeignaiter.
I haven't any idea for how to do this task.
I can't use scandir function because there are no physical
directory in path.Only files and folders save in database.
This is my database
Please any help needed.
Thank you.
Try this function by passing the path as a parameter in it:
function getFileCount($path) {
$size = 0;
$ignore = array('.','..','cgi-bin','.DS_Store');
$files = scandir($path);
foreach($files as $t) {
if(in_array($t, $ignore)) continue;
if (is_dir(rtrim($path, '/') . '/' . $t)) {
$size += getFileCount(rtrim($path, '/') . '/' . $t);
} else {
$size++;
}
}
return $size;
}
If you would like to get, say, all the *.php files in your project folder, recursively, you could use the following: Source
<?php
$Directory = new RecursiveDirectoryIterator('path/to/project/');
$Iterator = new RecursiveIteratorIterator($Directory);
$Regex = new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);
?>
$Regex will contain a single index array for each PHP file.
You can extend RecursiveArrayIterator to get kind of RecursiveDirectoryIterator but for your virtual filesystem:
class RecursiveVirtualDirectoryIterator extends RecursiveArrayIterator
{
private $files;
public function __construct($parentId, $array = [], $flags = 0)
{
$this->files = $array;
parent::__construct(
$this->getFilesByParentId($parentId),
$flags
);
}
private $children;
public function hasChildren()
{
$file = $this->current();
if ($file['is_file']) {
return false;
}
$this->children = $this->getFilesByParentId($file['id']);
return !empty($this->children);
}
private function getFilesByParentId($id)
{
return array_filter($this->files, function ($file) use ($id) {
return $file['parent_id'] === $id;
});
}
public function getChildren()
{
$file = $this->current();
return new static(
$file['id'],
$this->children,
$this->getFlags()
);
}
}
Then you can iterate over your array returned from databases using RecursiveIteratorIterator and count files for, say, topmost folders:
$iterator = new RecursiveIteratorIterator(
new RecursiveVirtualDirectoryIterator(0, $files),
RecursiveIteratorIterator::SELF_FIRST
);
$currentDirectoryName = null;
$filesCount = [];
foreach ($iterator as $file) {
if ($iterator->getDepth() === 0 && !$file['is_file']) {
$currentDirectoryName = $file['name'];
$filesCount[$currentDirectoryName] = 0;
continue;
}
$filesCount[$currentDirectoryName] += 1;
}
Here is working demo.
While Standard PHP Library (SPL) is poorly documented, it contains many useful things that save you from reinventing the wheel over and over again.

Recursive function scanning a folder and storing it in an array

I am trying to make a recursive function to go through all of the folder path that I have given it in the parameters.
What I am trying to do is to store the folder tree into an array for example I have Folder1 and this folder contains 4 text files and another folder and I want the structure to be a multidimensional array like the following
Array 1 = Folder one
Array 1 = text.text.....So on so forth
I have the following function that I build but its not working as I want it too. I know that I need to check whether it is in the root directory or not but when it becomes recursive it becoems harder
function displayAllFolders($root)
{
$foldersArray = array();
$listFolderFile = scandir($root);
foreach($listFolderFile as $row)
{
if($row == "." || $row == "..")
{
continue;
}
elseif(is_dir("$root/$row") == true)
{
$foldersArray["$root/$row"] = "$row";
$folder = "$root/$row";
#$foldersArray[] = displayAllFolders("$root/$row");
}
else
{
$foldersArray[]= array("$root/$row") ;
}
}
var_dump($foldersArray);
}
Using RecursiveDirectoryIterator with RecursiveIteratorIterator this becomes rather easy, e.g.:
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
// root dir
'.',
// ignore dots
RecursiveDirectoryIterator::SKIP_DOTS
),
// include directories
RecursiveIteratorIterator::SELF_FIRST
// default is:
// RecursiveIteratorIterator::LEAVES_ONLY
//
// which would only list files
);
foreach ($it as $entry) {
/* #var $entry \SplFileInfo */
echo $entry->getPathname(), "\n";
}
Your approach isn't recursive at all.
It would be recursive if you called the same function again in case of a directory. You only make one sweep.
Have a look here:
http://php.net/manual/en/function.scandir.php
A few solutions are posted. I would advise you to start with the usercomment by mmda dot nl.
(function is named dirToArray, exactly what you are tryting to do.)
In case it will be removed, I pasted it here:
function dirToArray($dir) {
$result = array();
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value,array(".",".."))) {
if (is_dir($dir . DIRECTORY_SEPARATOR . $value)) {
$result[$value] = dirToArray($dir . DIRECTORY_SEPARATOR . $value);
}
else {
$result[] = $value;
}
}
}
return $result;
}
Why not using PHP itself? Just have a look at the RecursiveDirectoryIterator of the standard php library (SPL).
$folders = [];
$iterator = new RecursiveDirectoryIterator(new RecursiveDirectoryIterator($directory));
iterator_apply($iterator, 'scanFolders', array($iterator, $folders));
function scanFolders($iterator, $folders) {
while ($iterator->valid()) {
if ($iterator->hasChildren()) {
scanFolders($iterator->getChildren(), $folders);
} else {
$folders[] = $iterator->current();
}
$iterator->next();
}
}

Simplified Recursive PHP

I've been working on a method of including files recursively with the __autoload() function in php. This way, You could throw your class anywhere in the "classes" folder, and have them organized by sub directory, But the __autoload function would still be able to find them. This is what I've gotten so far, And was wondering if anyone might be able to help me simplify it so that it isn't so lengthy. It is completely functional currently, And works like a charm. I'm just trying to make it shorter.
<?php
function readRecursive($path){
if(!is_dir($path)){
return false;
}
$dir = glob($path ."/*");
$retArr = array();
foreach($dir as $f){
if(is_dir($f)){
$m = readRecursive($f);
foreach($m as $n){
$retArr[] = $n;
}
}else{
$retArr[] = $f;
}
}
return $retArr;
}
function endsWith($haystack, $needle){
return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
/* Set up AutoLoading for object classes */
function __autoload($class_name){
$classes = readRecursive("classes");
foreach($classes as $class){
if(endsWith(strtolower($class), strtolower($class_name.".class.php"))){
include_once ($class);
}
}
}
?>
Here's my attempt at this autoload for you.
I've slightly modified Emil Condrea's Answer.
To start, I'll show you the file structure of my classes:
As you can see above, the classes are set into seperate files and such to show.
Now taking Emil's answer and slightly changing it:
(Provided the file name is something like "Class.php" as seen above in the file structure)
function getClasses($path) {
$files = array();
$dir_iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
foreach ($dir_iterator as $item) {
$pathname = $item->getPathName();
$filename = $item->getFileName();
if ($item->isDir()) {
getClasses($item);
} else {
$files[$filename] = $pathname;
}
}
return $files;
}
Will warrant a return array of files like the following [FILE_NAME] => [PATH_NAME]:
Array
(
[Error.php] => /home2/DERP/public_html/something.com/watch/model/Site/Error.php
[Form.php] => /home2/DERP/public_html/something.com/watch/model/Site/Form.php
[Site.php] => /home2/DERP/public_html/something.com/watch/model/Site/Site.php
[Db.php] => /home2/DERP/public_html/something.com/watch/model/Database/Db.php
[Db_pdo.php] => /home2/DERP/public_html/something.com/watch/model/Database/Db_pdo.php
[Session.php] => /home2/DERP/public_html/something.com/watch/model/Security/Session.php
[Auth.php] => /home2/DERP/public_html/something.com/watch/model/Security/Auth.php
[Input.php] => /home2/DERP/public_html/something.com/watch/model/Security/Input.php
[Postcode.php] => /home2/DERP/public_html/something.com/watch/model/Postcode.php
[Rep.php] => /home2/DERP/public_html/something.com/watch/model/User/Rep.php
[User.php] => /home2/DERP/public_html/something.com/watch/model/User/User.php
[Notifications.php] => /home2/DERP/public_html/something.com/watch/model/User/Notifications.php
[Log.php] => /home2/DERP/public_html/something.com/watch/model/Log/Log.php
[Hook.php] => /home2/DERP/public_html/something.com/watch/model/Hook.php
)
Now that would've been called by something like the following:
getClasses(realpath(dirname(__FILE__)) . '/model')
Allowing us to run an __autoload() like the following:
$model_classes = getClasses(realpath(dirname(__FILE__)) . '/model');
function __autoload($class_name) {
global $model_classes;
$filename = ucfirst($class_name) . '.php';
$model = $filename;
if (!isset($model_classes[$model])) {
// dead
return false;
} else {
// include first file (model)
include($model_classes[$model]);
}
}
Now
Obviously you shouldn't use global but to me it seemed a far better alternative to running the getClasses() function every single time within the __autoload() function.
If someone else has anything to add, feel free! I just tried my own little method on this and it works without fault!
Note: I was using file_exists() before and the above method is, in my opinion; a lot faster.
UPDATE
I had a brain wave just the other night and thought;
"Why not scan the application root and fetch all the php files then run a function to check if said file actually contains a class to make this as universal as possible.."
So I did a little research and found this nifty little function from php: token_get_all()
Now after a little digging through SO I found this answer: Determine class in file...
and after some modification, the getClasses() function now looks like this:
function getClasses($path) {
$files = array();
$dir_iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
foreach ($dir_iterator as $item) {
$pathname = $item->getPathName();
$filename = $item->getFileName();
if ($item->isDir()) {
get_classes($item);
} else {
if (substr($filename, -4) === '.php') {
if (get_php_classes(file_get_contents($pathname))) {
$files[$filename] = $pathname;
}
}
}
}
return $files;
}
With the addition of this new function from the above question:
function get_php_classes($php_code) {
$tokens = token_get_all($php_code);
$class_token = false;
foreach ($tokens as $token) {
if (is_array($token)) {
if ($token[0] == T_CLASS) {
$class_token = true;
} else if ($class_token && $token[0] == T_STRING) {
$classes[] = $token[1];
// $class_token = false;
}
}
}
return $class_token;
}
Now that allows you to simply run a $classes = getClasses(ROOTPATH) and itterate through them.
DOWNFALL: each of the classes will have to have unique class names and/or file names. Unless somebody could lend their hand at a modification to allow.
You can use
RecursiveDirectoryIterator to iterate through the directory recursively. This might simplify your function.
function getRecursive($path){
$files = array();
$dir_iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),RecursiveIteratorIterator::SELF_FIRST);
foreach ($dir_iterator as $item) {
$subPath = $dir_iterator->getSubPathName();
if($item->isDir())
$files[$subPath] = array();
else
$files[$subPath][] = $subPath;
}
return $files;
}

Generating playlist for jplayer in php

i am actually working on this mentioned title. player show the list, its generating perfectly. but i am no where to make it actually play that file. i must be wrong some where.
i need advise fox. (ahh if i can attach the files.)
my class
class DecodDir
{
function getFiles($directory)
{
$all_files = array();
$handler = opendir($directory);
while($files=readdir($handler))
{
if($files!="." && $files!="..")
{
$all_files[]= $files;
}
}
closedir($handler);
return $all_files;
}
}
################# file where i am using this class *###############
<?php
include("decoddir.php");
$obj = new DecodDir();
$results = $obj->getFiles("mp3");
$total = count($results);
$string = "";
for($i=0; $i<$total; $i++){
$string .="
{
name:'$results[$i]',
mp3:'mp3/$results[$i]',
ogg:'$results[$i]'
},
";
}
?>
// its at the top of that html file (ofcorse with the php ext)
and below, this is where it is generating the playlist
var audioPlaylist = new Playlist("2", [
<?php echo $string; ?>
],
http://www.jplayer.org/latest/demo-02/ (the link from where i get jplayer) you can see the audio player with playlist.
(actually i don't know hot format the code in here stackoverflow)
thanks
Rafay
I have taken the liberty of re-factoring the code a bit for you. I don't know exactly what you are trying to do, but it will help to have the beginnings of a better class on your side.
<?php
class DecodDir
{
private
$directory,
$files;
public function __construct( $directory = null )
{
if ( ! is_null($directory) )
{
$this->setDirectory( $directory );
}
}
public function setDirectory( $directory )
{
$this->directory = $directory;
$this->files = null;
// TODO put some validation in here;
return $this;
}
public function getDirectory()
{
if ( is_null($this->directory) )
{
$this->directory = './';
}
return $this->directory;
}
private function getFiles()
{
if ( is_null($this->files) )
{
$this->files = array();
$handler = opendir( $this->getDirectory() );
while($files=readdir($handler))
{
if($files!="." && $files!="..")
{
$this->files[]= $files;
}
}
closedir($handler);
}
return $this->files;
}
public function getJson()
{
$list = array();
foreach ( $this->getFiles() as $filename )
{
$item = new stdClass();
$item->name = $filename;
$item->mp3 = "mp3/{$filename}";
$item->ogg = $filename;
$list[] = $item;
}
$json = json_encode( $list );
return $json;
}
public function countFiles()
{
return sizeof( $this->getFiles() );
}
}
$obj = new DecodDir( 'mp3' );
echo $obj->getJson();
I wrote the code at the following site to do what you are trying to do, I think:
http://jplaylister.yaheard.us/
Sadly, it doesn't currently collapse a song stored in multiple formats (mysong1.mp3, mysong1.ogg) into one playlist item, but otherwise it is pretty feature-complete and has lots of customizable options.
Hope this helps!

Get all modules, controllers and actions from a Zend Framework application

I want to create a Zend Controller for ACL management so my problem is: How can I get all Module names, Control names and Action names in a Zend application to build a ACL Control?
I use Zend_Navigation and if the resource don't exist in your ACL Zend_Navigation is thrown a exception. And I want to use a database to deny and allow access. So I must build the database first. And if I must do that by hand it's a pain to do that.
This may be an old question but this is how I am doing this...
// $front = Zend_Controller_Front::getInstance(); // use this line instead on a model class
$front = $this->getFrontController(); // this in controller
$acl = array();
foreach ($front->getControllerDirectory() as $module => $path) {
foreach (scandir($path) as $file) {
if (strstr($file, "Controller.php") !== false) {
include_once $path . DIRECTORY_SEPARATOR . $file;
$class = substr($file,0,strpos($file,".php"));
if (is_subclass_of($class, 'Zend_Controller_Action')) {
$controller = strtolower(substr($file, 0, strpos($file, "Controller")));
$methods = array();
foreach (get_class_methods($class) as $method) {
if (strstr($method,"Action") != false) {
array_push($methods,substr($method,0,strpos($method,"Action")));
}
}
}
$acl[$module][$controller] = $methods;
}
}
}
I have created a function that can get all the actions, controllers and modules from a zend application. Here it is:
$module_dir = substr(str_replace("\\","/",$this->getFrontController()->getModuleDirectory()),0,strrpos(str_replace("\\","/",$this->getFrontController()->getModuleDirectory()),'/'));
$temp = array_diff( scandir( $module_dir), Array( ".", "..", ".svn"));
$modules = array();
$controller_directorys = array();
foreach ($temp as $module) {
if (is_dir($module_dir . "/" . $module)) {
array_push($modules,$module);
array_push($controller_directorys, str_replace("\\","/",$this->getFrontController()->getControllerDirectory($module)));
}
}
foreach ($controller_directorys as $dir) {
foreach (scandir($dir) as $dirstructure) {
if (is_file($dir . "/" . $dirstructure)) {
if (strstr($dirstructure,"Controller.php") != false) {
include_once($dir . "/" . $dirstructure);
}
}
}
}
$default_module = $this->getFrontController()->getDefaultModule();
$db_structure = array();
foreach(get_declared_classes() as $c){
if(is_subclass_of($c, 'Zend_Controller_Action')){
$functions = array();
foreach (get_class_methods($c) as $f) {
if (strstr($f,"Action") != false) {
array_push($functions,substr($f,0,strpos($f,"Action")));
}
}
$c = strtolower(substr($c,0,strpos($c,"Controller")));
if (strstr($c,"_") != false) {
$db_structure[substr($c,0,strpos($c,"_"))][substr($c,strpos($c,"_") + 1)] = $functions;
}else{
$db_structure[$default_module][$c] = $functions;
}
}
}
}
I actually found the best way to have an easily available reflection reference was to recursively tokenise the correct directories and then build an xml document as a result. Caching the xml document for speed and using xpath for retrieving the data.
The plugin builds the reflection xml and caches it for later. I've taken this code out of its original implementation, so its more to give you a feel rather than copy and paste.
Of course, a database works just as well here. But if you're trying to limit your queries per page, a cached xml doc works pretty well.
class My_Reflection_Plugin extends My_Controller_Plugin_Abstract
{
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
$cache = $this -> getCacheManager() -> getCache('general');
if (!$xml = $cache->load("Reflection"))
{
$paths = array(
PATH_APPLICATION . "/Core",
PATH_SITE . "/Project"
);
foreach ($paths as $path)
{
$this -> inspectDir($path);
}
$cache -> save($this->getReflectionXML(), "Reflection");
}
else
{
$this -> getReflectionXML($xml);
}
}
private function inspectDir($path)
{
$rdi = new RecursiveDirectoryIterator($path);
$rii = new RecursiveIteratorIterator($rdi);
$filtered = new My_Reflection_Filter($rii);
iterator_apply($filtered, array($this, 'process'), array($filtered));
}
private function process($it = false)
{
$this -> getReflectionXML() -> addItem($it -> current());
return true;
}
}
Tokenisation happens inside the filter:
class My_Reflection_Filter extends FilterIterator
{
public function accept()
{
$file = $this->getInnerIterator()->current();
// If we somehow have something other than an SplFileInfo object, just
// return false
if (!$file instanceof SplFileInfo) {
return false;
}
// If we have a directory, it's not a file, so return false
if (!$file->isFile()) {
return false;
}
// If not a PHP file, skip
if ($file->getBasename('.php') == $file->getBasename()) {
return false;
}
// Resource forks are no good either.
if (substr($file->getBaseName(), 0, 2) == '._')
{
return false;
}
$contents = file_get_contents($file->getRealPath());
$tokens = token_get_all($contents);
$file->className = NULL;
$file->classExtends = NULL;
$file->classImplements = array();
$last = null;
while (count($tokens) > 0)
{
$token = array_shift($tokens);
if (!is_array($token))
{
continue;
}
list($id, $content, $line) = $token;
switch ($id)
{
case T_ABSTRACT:
case T_CLASS:
case T_INTERFACE:
$last = 'object';
break;
case T_EXTENDS:
$last = "extends";
break;
case T_IMPLEMENTS:
$last = "implements";
break;
case T_STRING:
switch ($last)
{
case "object":
$file -> className = $content;
break;
case "extends":
$file -> classExtends = $content;
break;
case "implements":
$file -> classImplements[] = $content;
break;
}
break;
case T_WHITESPACE:
// Do nothing, whitespace should be ignored but it shouldnt reset $last.
break;
default:
// If its not directly following a keyword specified by $last, reset last to nothing.
$last = null;
break;
}
}
return true;
}
}
Once you have your reflection xml populated with whatever information you need out of the class, your acl plugin can come after it and query that information with xpath.
I don't think there is a solution for this in Zend. You will have to do it yourself...
One way to do it, is to list all classes, and check if the classes extend (for example) the Zend_Controller_Action class...
check the php functions get_declared_classes and is_subclass_of
foreach(get_declared_classes() as $c){
if(is_subclass_of($c, 'Zend_Controller_Action')){
...
}
}

Categories