I've got some problems with a piece of code in my two classes 'File' and 'Folder'. I've created a page which shows me the content of my server space. Therefore I've wrote the class Folder which contains information about it self like 'name', 'path' and 'children'. The children property contains an Array of 'Files' or 'Folders' within this folder. So it's a kind of recursive class. To get the whole structure of a wanted directory I've wrote some recursive backtracking algorithms that are giving me an array of objects for all children in the same structure as my folder on the server. The second algorithm is taking that array and searches an special folder. If it finds this folder the method will return the root path to it and if the folder isn't a subfolder of this directory the algorithm will return false. I've tested all of that methods for the 'Folder' object and it works just fine but now I've detected an error by using my script more intensive.
/**
* find an subfolder within the given directory (Recursive)
*/
public function findFolder($name) {
// is this object the object you wanted
if ($this->name == $name) {
return $this->getPath();
}
// getting array
$this->bindChildren();
$result = $this->getChildren();
// backtracking part
foreach($result as $r) {
// skip all 'Files'
if(get_class($r) == 'File') {
continue;
} else {
if($search_res = $r->findFolder($name)) {
return $search_res;
}
}
}
// loop runned out
return false;
}
/**
* stores all children of this folder
*/
public function bindChildren() {
$this->resetContent();
$this->dirSearch();
}
/**
* resets children array
*/
private function resetContent() {
$this->children = array();
}
/**
* storing children of this folder
*/
private function dirSearch() {
$dh = opendir($this->path);
while($file = readdir($dh)) {
if($file !== "" && $file !== "." && $file !== "..") {
if(!is_dir($this->path.$file)) {
$this->children[] = new File($this->path.$file);
} else {
$this->children[] = new Folder($this->path.$file.'/');
}
}
}
}
In my website I first create a new folder object and then I'm starting to find a subfolder of 'doc' which is call 'test' for example. The folder 'test' is in '/var/www/media/username/doc/test4/test/' located
$folder = new Folder('/var/www/media/username/doc/');
$dir = $folder->findFolder('test');
If I print out $dir it returns a link as I wanted because the folder 'test' is a subfolder of 'docs' but the returned link is not correct. it should be '/var/www/media/username/doc/test4/test' but the result is '/var/www/media/username/doc/test' I've tried to debugg a bit and found out that the folders list which contains all children is keeping the objects with the right links but in the findFolder method in the first if condition the object $this doesn't have the correct path. I don't know why but the the
// backtracking part
foreach($result as $r) {
seems to change the object properties. I hope someone can help me and thanks in advance
Don't reinvent the wheel. PHP already has a class for that purpose named RecursiveDirectoryIterator.
http://php.net/manual/en/class.recursivedirectoryiterator.php
Related
I have source of data and it is like:
$sourceData = json_decode($sourceData);
OR
$sourceData = simplexml_load_string($sourceData);
but possibly it could be another type of source and the result is probably php object with path to attributes like this:
$sourceData->product->time[$x]->location->precipitation['value'];
and I would like to split the path like this:
$rootPath = $sourceData->product->time[$x];
$rest = ?
/* probably something like '{$location}->{$precipitation}['value']
but I want the rest in one variable like
$rest = 'location->precipitation['value'];
*/
so at the end I should load paths like or similar to:
$temperature = 'location->data->something->temperature['value'];'
$precipitation = 'location->xxx->yyy->precip['data'];'
and use like:
for($i)
{
$temp = $root[$i]->temperature;
$precip = $root[$i]->precipitation;
}
This can be done with dynamic paths (like "dot notation"), but I'd hold off with it and make sure I really need that. It might be slow and it's used in more generic situations - unknown variable paths that client will provide.
Cleaner way would be encapsulating each root subtree ($data->product->time) within object with methods that can reach deep inside and return what you want. For example:
class ProductProperties
{
private $data;
public function __construct($data)
{
$this->data = $data;
}
public function temperature()
{
return $this->data->location->something->temperature['value'];
}
//...
}
Then creating instance and calling it within loop (or separate loops):
foreach ($sourceData as $root) {
$properties = new ProductProperties($root);
$temp = $properties->temperature();
}
I'm scanning a folder and it's subfolders for files with PHP. I want to store the folders and files in a PHP array so I can create a treeview in another page. This is the format I get files paths in:
/home/project/index.php
/home/project/folder/myclass.php
/home/project/folder/myclass2.php
/home/project/folder/subfolder/anotherclass.php
I want to get these files in the following array:
[home][project] = array('index.php')
[home][project][folder] = array(myclass.php, myclass2.php)
[home][project][folder][subfolder] = array(anotherclass.php)
Note that the folder structure can change at any point. How can I achieve this?
The easiest way would be to use the built in (SPL) DirectoryIterator class and a simple recursive function.
An untested example:
public function directoryToArray($directoryPath)
{
$items = new DirectoryIterator($directoryPath);
$data = array();
foreach($items as $item) {
$name = $item->getFileName();
if ($item->isFile()) {
$data[] = $name;
}
else if ($item->isDir()) {
$data[$name] = directoryToArray($item->getPath());
}
}
return $data;
}
So I'm trying to write a function that does the following: I have about 20 or so XML files (someday I will have over a hundred) and in the header of each file is the name of a person who was a peer review editor <editor role="PeerReviewEditor">John Doe</editor>. I want to run through the directory where these files are stored and capture the name of the Peer-Review-Editor for that file. I want to end up with an variable $reviewEditorNames that contains all of the different names. (I will then use this to display a list of editors, etc.)
Here's what I've got so far. I'm worried about the last part. I feel like the attempt to turn $editorReviewName into $editorReviewNames is not going to combine the individuals for each file, but an array found within a given file (even if there is only one name in a given file, and thus it is an array of 1)
I'm grateful for your help.
function editorlist()
{
$filename = readDirectory('../editedtranscriptions');
foreach($filename as $file)
{
$xmldoc = simplexml_load_file("../editedtranscriptions/$file");
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
$reviewEditorName = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor']");
return $reviewEditorNames[] = $reviewEditorName;
}
}
I would put things more apart, that helps as well when you need to change your code later on.
Next to that, you need to check the return of the xpath, most likely you want to process only the first match (is there one editor per file?) and you want to return it as string.
If you put things into functions of it's own it's more easy to make a function to only do one thing and so it's easier to debug and improve things. E.g. you can first test if a editorFromFile function does what it should and then run it on multiple files:
/**
* get PeerReviewEditor from file
*
* #param string $file
* #return string
*/
function editorFromFile($file)
{
$xmldoc = simplexml_load_file($file);
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
$node = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor'][1]");
return (string) $node[0];
}
/**
* get editors from a path
*
* #param string $path
* #return array
*/
function editorlist($path)
{
$editors = array();
$files = glob(sprintf('%s/*.xml', $path), GLOB_NOSORT);
foreach($files as $file)
{
$editors[] = editorFromFile($file);
}
return $editors;
}
Just a little update:
function editorlist() {
$reviewEditorNames = array(); // init the array
$filename = readDirectory('../editedtranscriptions');
foreach($filename as $file) {
$xmldoc = simplexml_load_file("../editedtranscriptions/$file");
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
// add to the array
$result = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor']");
if (sizeof($result) > 0) {
$reviewEditorNames[] = (string)$result[0];
}
}
// return the array
return $reviewEditorNames;
}
I'm working on a script that gets file modified times, and takes an optional arg that if filled has an array with a list of files to check rather then every file. How could I go about just getting the data for those files in a script like this:
$filesObject = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
foreach ($filesObject as $key => $object)
{
$checkFile = filemtime($object->getPathname());
$num++;
$alertFiles[$num] = array('name' => $object->getPathname(),
'time' => $checkFile);
}
edit: this code is in a function where $filesArray is the array of file names that can be passed.
You can wrap your Iterator in a custom Filter Iterator (to foster reuse)
class FileFilter extends FilterIterator
{
protected $_files;
public function __construct($iterator, array $files)
{
$this->_files = $files;
parent::__construct($iterator);
}
public function accept()
{
return !in_array($this->current(), $this->_files);
}
}
If accept returns FALSE the current element is not considered in the iteration. Since you give very little information about your $filesArray contents, you might have to change the accept logic to make it work for your code.
How can I list all jpg files in a given directory and its subdirectories in PHP5 ?
I thought I could write a glob pattern for that but I can't figure it out.
thanx, b.
You can use a RecursiveDirectoryIterator with a filter:
class ImagesFilter extends FilterIterator
{
public function accept()
{
$file = $this->getInnerIterator()->current();
return preg_match('/\.jpe?g$/i', $file->getFilename());
}
}
$it = new RecursiveDirectoryIterator('/var/images');
$it = new ImagesFilter($it);
foreach ($it as $file)
{
// Use $file here...
}
$file is an SplFileInfo object.
without doing it for you. recursion is the answer here. a function that looks in a dir and gets a list of all files. filters out only th jpg's then calls its self if i finds any sub dirs
Wish I had time to do more & test, but this could be used as a starting point: it should (untested) return an array containing all the jpg/jpeg files in the specified directory.
function load_jpgs($dir){
$return = array();
if(is_dir($dir)){
if($handle = opendir($dir)){
while(readdir($handle)){
echo $file.'<hr>';
if(preg_match('/\.jpg$/',$file) || preg_match('/\.jpeg$/',$file)){
$return[] = $file;
}
}
closedir($handle);
return $return;
}
}
return false;
}