Script die bestanden van map(pen) laat zien
Door Carlo boy, 17 jaar geleden, 14.378x bekeken
Dit script laat al je bestanden zien in een map (ook submappen)
Dit script is makkelijk voor bijv. een gastenboek waar mensen avatars uit mappen kunnen kiezen.
Het script is voorzien van commentaar en is makkelijk in gebruik
Ik ben niet de eigenaar, lees de comentaars door en je komt er wel achter.
Gesponsorde koppelingen
PHP script bestanden
Er zijn 36 reacties op 'Script die bestanden van mappen laat zien'
Gesponsorde koppelingen
@pim bedankt voor je reactie, ik ga het meteen toepassen.
Er is wel een ding wat ik niet snap, hoe is de denk wijze als ik in getBestanden() een array moet maken.
Dan returnt getBestanden() een array die hij zo gemaakt is: maar hoe moet ik dan de tabel eromheen maken???
ik kan wel zo iets maken:
Maar dat is niet wat ik wil bereiken.
Hoe moet ik dat aanpakken??
Er is wel een ding wat ik niet snap, hoe is de denk wijze als ik in getBestanden() een array moet maken.
Dan returnt getBestanden() een array die hij zo gemaakt is: maar hoe moet ik dan de tabel eromheen maken???
ik kan wel zo iets maken:
Code (php)
Maar dat is niet wat ik wil bereiken.
Hoe moet ik dat aanpakken??
Nou als je een mapsturctuur hebt van
Dat je dan zo'n array teruggeeft
Ook kan je het niet met een array doen, maar met directories (en files) als objecten.
Dan doe je het zo:
EDIT: Zie verderop voor de code
Snap je het een beetje?
Als je nu de bovenstaande structuur zo in OOP wil hebben doe je het volgende:
Dat je dan zo'n array teruggeeft
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Array (
[mapA] => Array (
[0] => test.php
[1] => a.xml
)
[mapB] => Array (
[mapC] => Array (
[0] => file.ini
)
)
)
[mapA] => Array (
[0] => test.php
[1] => a.xml
)
[mapB] => Array (
[mapC] => Array (
[0] => file.ini
)
)
)
Ook kan je het niet met een array doen, maar met directories (en files) als objecten.
Dan doe je het zo:
EDIT: Zie verderop voor de code
Snap je het een beetje?
Als je nu de bovenstaande structuur zo in OOP wil hebben doe je het volgende:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/*
- mapA
- test.php
- a.xml
- map b
- map c
- file.ini
*/
$root = new Dir('Map');
$mapA = new Dir('mapA');
$mapA->addChild(new File('test.php'));
$mapA->addChild(new File('a.xml'));
$root->addChild($mapA);
$map_b = new Dir('map b');
$map_c = new Dir('map c');
$map_c->addChild(new File('file.ini'));
$map_b->addChild($map_c);
$root->addChild($map_b);
print_r($root->buildArray());
?>
/*
- mapA
- test.php
- a.xml
- map b
- map c
- file.ini
*/
$root = new Dir('Map');
$mapA = new Dir('mapA');
$mapA->addChild(new File('test.php'));
$mapA->addChild(new File('a.xml'));
$root->addChild($mapA);
$map_b = new Dir('map b');
$map_c = new Dir('map c');
$map_c->addChild(new File('file.ini'));
$map_b->addChild($map_c);
$root->addChild($map_b);
print_r($root->buildArray());
?>
Snap je dat je allemaal 'nodes' (in dit geval een dir of een file) aan elkaar rijgt?
Een directory kan nodes onder zich hebben, een file natuurlijk niet.
Een directory kan met addChild() een 'kind krijgen', dus een map of bestand onder zich.
Verder zijn er wat extra functies, zoals getPath(), waarmee een bestand of map steeds naar boven gaat en zo het pad (dus voor file.ini: Map/map b/map c/file.ini ) maakt. En getExtension() waarmee je van een bestand de extensie (bijv php of ini) kan krijgen.
Met getIterator() en de interface IteratorAggregate kan je een foreach doen op een map, waarmee je alle kinderen krijgt.
EDIT: Probeer dit te snappen, het is een mooie duidelijke uitwerking van OOP
Huh raar, verander de classnaam maar naar 'Dir', mss lukt t dan.
Ik wist niet dat er al een klasse met die naam bestond :S
Een directory kan nodes onder zich hebben, een file natuurlijk niet.
Een directory kan met addChild() een 'kind krijgen', dus een map of bestand onder zich.
Verder zijn er wat extra functies, zoals getPath(), waarmee een bestand of map steeds naar boven gaat en zo het pad (dus voor file.ini: Map/map b/map c/file.ini ) maakt. En getExtension() waarmee je van een bestand de extensie (bijv php of ini) kan krijgen.
Met getIterator() en de interface IteratorAggregate kan je een foreach doen op een map, waarmee je alle kinderen krijgt.
EDIT: Probeer dit te snappen, het is een mooie duidelijke uitwerking van OOP
Huh raar, verander de classnaam maar naar 'Dir', mss lukt t dan.
Ik wist niet dat er al een klasse met die naam bestond :S
Ik maak gebruik van php versie 5.3.1.
Ik krijg weer een error (
Catchable fatal error: Argument 1 passed to FileNode::setParentDir() must be an instance of Directory, instance of Dir given, called in C:\xampp\htdocs\OOP\test\example.php on line 57 and defined in C:\xampp\htdocs\OOP\test\example.php on line 29)
Maar kan je me deze regel even uitleggen?
en
Ik krijg weer een error (
Catchable fatal error: Argument 1 passed to FileNode::setParentDir() must be an instance of Directory, instance of Dir given, called in C:\xampp\htdocs\OOP\test\example.php on line 57 and defined in C:\xampp\htdocs\OOP\test\example.php on line 29)
Maar kan je me deze regel even uitleggen?
en
Zo moet het goed zijn.
Het nut van die abstracte klasse is dat een aantal dingen zijn die mappen en files delen, zo hebben ze alle een naam, een pad en kunnen een bovenliggende map hebben. Daarom zit die functionaliteit in een aparte klasse, die zowel mappen als files gebruiken.
Een map gebruikt dus die functionaliteit van een 'filenode' en ik heb hem ook die interface laten implementeren. Deze interface maakt het mogelijk alle objecten in een foreach te gebruiken, het wordt dan een 'iterator'.
Je kan dan de interface Iterator implementeren en een aantal functies, maar je kan, omdat het om een array (Dir::$childs) gaat, ook een nieuwe iterator maken (aggregate in het engels), zodat je niet 5, maar 1 nieuwe methode hoeft toe te voegen, getIterator(). De ArrayIterator die daar wordt gemaakt, is de iterator die in de foreach wordt gebruikt.
http://php.net/manual/en/class.iterator.php
http://www.php.net/manual/en/class.iteratoraggregate.php
Het nut van die abstracte klasse is dat een aantal dingen zijn die mappen en files delen, zo hebben ze alle een naam, een pad en kunnen een bovenliggende map hebben. Daarom zit die functionaliteit in een aparte klasse, die zowel mappen als files gebruiken.
Een map gebruikt dus die functionaliteit van een 'filenode' en ik heb hem ook die interface laten implementeren. Deze interface maakt het mogelijk alle objecten in een foreach te gebruiken, het wordt dan een 'iterator'.
Je kan dan de interface Iterator implementeren en een aantal functies, maar je kan, omdat het om een array (Dir::$childs) gaat, ook een nieuwe iterator maken (aggregate in het engels), zodat je niet 5, maar 1 nieuwe methode hoeft toe te voegen, getIterator(). De ArrayIterator die daar wordt gemaakt, is de iterator die in de foreach wordt gebruikt.
http://php.net/manual/en/class.iterator.php
http://www.php.net/manual/en/class.iteratoraggregate.php
En nog even een builder, die het aan de hand van een mappenstructuur opbouwd.
EDIT: Zie verderop voor de code
Niet getest, kan wat foutjes bevatten.
EDIT: Zie verderop voor de code
Niet getest, kan wat foutjes bevatten.
En als ik toch bezig ben, eentje die het mooi in een HTML lijstje weer kan geven.
EDIT: Over welke uitleg heb je het nu?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
class FileNodeRenderer
{
public function render(Dir $dir, $indent = 0)
{
$return = str_repeat('\t', $indent).$this->renderDirName($dir).PHP_EOL;
$return .= str_repeat('\t', $indent).'<ul>'.PHP_EOL;
foreach($dir->getChildren() as $child) {
if($child instanceof Dir) {
$return .= str_repeat('\t', $indent+1).'<li>.PHP_EOL;
$return .= $this->render($child, $indent+1);
$return .= str_repeat('\t', $indent+1).'</li>.PHP_EOL;
}
if($child instanceof File)
$return .= str_repeat('\t', $indent+1).$this->renderFileName($child).PHP_EOL;
}
$return .= str_repeat('\t', $indent).'<ul>'.PHP_EOL;
return $return;
}
// Als je de volgende functies extend, kan je er bijvoorbeeld links van maken
public function renderDirName(Dir $dir)
{
return '<strong>'.$dir->getName().'</strong>';
}
public function renderFileName(File $file)
{
return '<li>'.$file->getName().'</li>';
}
}
// Gebruik:
$builder = new FileNodeBuilder;
$dir = $builder->build('path');
$renderer = new FileNodeRenderer;
echo $renderer->render($dir);
?>
class FileNodeRenderer
{
public function render(Dir $dir, $indent = 0)
{
$return = str_repeat('\t', $indent).$this->renderDirName($dir).PHP_EOL;
$return .= str_repeat('\t', $indent).'<ul>'.PHP_EOL;
foreach($dir->getChildren() as $child) {
if($child instanceof Dir) {
$return .= str_repeat('\t', $indent+1).'<li>.PHP_EOL;
$return .= $this->render($child, $indent+1);
$return .= str_repeat('\t', $indent+1).'</li>.PHP_EOL;
}
if($child instanceof File)
$return .= str_repeat('\t', $indent+1).$this->renderFileName($child).PHP_EOL;
}
$return .= str_repeat('\t', $indent).'<ul>'.PHP_EOL;
return $return;
}
// Als je de volgende functies extend, kan je er bijvoorbeeld links van maken
public function renderDirName(Dir $dir)
{
return '<strong>'.$dir->getName().'</strong>';
}
public function renderFileName(File $file)
{
return '<li>'.$file->getName().'</li>';
}
}
// Gebruik:
$builder = new FileNodeBuilder;
$dir = $builder->build('path');
$renderer = new FileNodeRenderer;
echo $renderer->render($dir);
?>
EDIT: Over welke uitleg heb je het nu?
Onderstaande script verbeterd op de volgende punten:
-geen opendir maar scandir gebruikt
-optie om recursief uit te schakelen (alleen 1 dir uitlezen)
-oneindige loops eruit gehaald (filteren op ./ en ../ dus)
-bestanden worden oplopend of aflopend gesorteerd
-mapnamen worden goed weergegeven
Natuurlijk grootste deel van credits naar Pim voor de basis ;)
-geen opendir maar scandir gebruikt
-optie om recursief uit te schakelen (alleen 1 dir uitlezen)
-oneindige loops eruit gehaald (filteren op ./ en ../ dus)
-bestanden worden oplopend of aflopend gesorteerd
-mapnamen worden goed weergegeven
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<?PHP
// Abstracte klasse voor een file of een map
abstract class FileNode{
protected $name;
protected $parentDir = null;
public function __construct($name){
$this->name = $name;
}
public function getName(){
return $this->name;
}
public function getPath(){
$path = '';
// Als er een map boven zit, stop deze dan voor het pad
if(!is_null($this->parentDir))
$path .= $this->parentDir->getPath().'/';
$path .= $this->name;
}
public function setParentDir(Dir $dir){
$this->parentDir = $dir;
}
}
class File extends FileNode{
protected $ext;
public function __construct($name){
$this->ext = substr($name, strrpos($name, '.'));
parent::__construct($name);
}
public function getExtension(){
return $this->ext;
}
}
class Dir extends FileNode implements IteratorAggregate{
protected $dirchilds = array();
protected $filechilds = array();
protected $name;
public function __construct($name){
if(strrpos($name,'/')!==false){
$this->name=substr($name,strrpos($name,'/')+1);
}else{
$this->name=$name;
}
}
public function addChild(FileNode $node){
$node->setParentDir($this);
if($node instanceof Dir){
$this->dirchilds[] = $node;
}elseif($node instanceof File){
$this->filechilds[] = $node;
}else{
throw new Exception('Wrong instance given to Dir::addChild()');
}
}
public function getChilds(){
return $this->childs;
}
public function getIterator(){
return new ArrayIterator($this->childs);
}
public function getName(){
return $this->name;
}
public function buildArray($asc=1){
$array = array();
if(count($this->dirchilds)==0&&count($this->filechilds)==0){
return 'No files found';
}else{
if($asc==1){
sort($this->dirchilds);
sort($this->filechilds);
foreach($this->dirchilds as $child)
$array[$child->getName()] = $child->buildArray();
foreach($this->filechilds as $child)
$array[] = $child->getName();
}else{
rsort($this->dirchilds);
rsort($this->filechilds);
foreach($this->filechilds as $child)
$array[] = $child->getName();
foreach($this->dirchilds as $child)
$array[$child->getName()] = $child->buildArray();
}
return $array;
}
}
}
class FileNodeBuilder{
private $_dir;
public function build($path,$recursive=true){
if(!is_dir($path))
throw new Exception($path.' is no directory');
if(!is_readable($path))
throw new Exception($path.' is not readable');
$dir = new Dir($path);
foreach(scandir($path,1) as $file){
$newPath = $path.'/'.$file;
if(!($file==='.'||$file==='..')){
if(is_dir($newPath)&&$recursive)
$dir->addChild($this->build($newPath));
if(is_dir($newPath)&&(!$recursive))
$dir->addChild(new Dir($file));
if(is_file($newPath))
$dir->addChild(new File($file));
}
}
return $dir;
}
}
$builder = new FileNodeBuilder;
$data=$builder->build('./',true);
echo '<pre>'.PHP_EOL;
print_r($data->buildArray());
echo '</pre>';
?>
// Abstracte klasse voor een file of een map
abstract class FileNode{
protected $name;
protected $parentDir = null;
public function __construct($name){
$this->name = $name;
}
public function getName(){
return $this->name;
}
public function getPath(){
$path = '';
// Als er een map boven zit, stop deze dan voor het pad
if(!is_null($this->parentDir))
$path .= $this->parentDir->getPath().'/';
$path .= $this->name;
}
public function setParentDir(Dir $dir){
$this->parentDir = $dir;
}
}
class File extends FileNode{
protected $ext;
public function __construct($name){
$this->ext = substr($name, strrpos($name, '.'));
parent::__construct($name);
}
public function getExtension(){
return $this->ext;
}
}
class Dir extends FileNode implements IteratorAggregate{
protected $dirchilds = array();
protected $filechilds = array();
protected $name;
public function __construct($name){
if(strrpos($name,'/')!==false){
$this->name=substr($name,strrpos($name,'/')+1);
}else{
$this->name=$name;
}
}
public function addChild(FileNode $node){
$node->setParentDir($this);
if($node instanceof Dir){
$this->dirchilds[] = $node;
}elseif($node instanceof File){
$this->filechilds[] = $node;
}else{
throw new Exception('Wrong instance given to Dir::addChild()');
}
}
public function getChilds(){
return $this->childs;
}
public function getIterator(){
return new ArrayIterator($this->childs);
}
public function getName(){
return $this->name;
}
public function buildArray($asc=1){
$array = array();
if(count($this->dirchilds)==0&&count($this->filechilds)==0){
return 'No files found';
}else{
if($asc==1){
sort($this->dirchilds);
sort($this->filechilds);
foreach($this->dirchilds as $child)
$array[$child->getName()] = $child->buildArray();
foreach($this->filechilds as $child)
$array[] = $child->getName();
}else{
rsort($this->dirchilds);
rsort($this->filechilds);
foreach($this->filechilds as $child)
$array[] = $child->getName();
foreach($this->dirchilds as $child)
$array[$child->getName()] = $child->buildArray();
}
return $array;
}
}
}
class FileNodeBuilder{
private $_dir;
public function build($path,$recursive=true){
if(!is_dir($path))
throw new Exception($path.' is no directory');
if(!is_readable($path))
throw new Exception($path.' is not readable');
$dir = new Dir($path);
foreach(scandir($path,1) as $file){
$newPath = $path.'/'.$file;
if(!($file==='.'||$file==='..')){
if(is_dir($newPath)&&$recursive)
$dir->addChild($this->build($newPath));
if(is_dir($newPath)&&(!$recursive))
$dir->addChild(new Dir($file));
if(is_file($newPath))
$dir->addChild(new File($file));
}
}
return $dir;
}
}
$builder = new FileNodeBuilder;
$data=$builder->build('./',true);
echo '<pre>'.PHP_EOL;
print_r($data->buildArray());
echo '</pre>';
?>
Natuurlijk grootste deel van credits naar Pim voor de basis ;)
Nog een paar toevoegingen:
Denk aan mn naming convention... camelCase en properties zonder _ (ze zijn toch altijd protected)
FileNodeBuilder::$_dir is ongebruikt.
Verder kan je nog denken aan een opgegeven zoekdiepte of zelfs lazy load dirs.
En wat is er beter aan scandir dan?
En verder kan de volgorde beter met een constant.
En nog wat dingen naar mijn ogen mooier gemaakt.
En van childs children gemaakt ;)
Dus dan zo:
Ik stel het zeer op prijs dat je het script wou verbeteren, maar ik vind het wel vrij vervelend dat je alle conventies die ik gebruik (vooral Zend) omzet naar iets anders...
En nu uitleg:
Eerst was leeswerk:
Basic PHP OOP
http://phptuts.nl/view/45/
Over het composite pattern
http://devzone.zend.com/article/7
Dit gebruiken we bij het bestandensysteem.
Hoe het nu in elkaar zit hebben we een bouwer (Builder pattern) die het in elkaar zet. We krijgen dan een root map en die heeft dan weer submappen en -bestanden.
Zover duidelijk?
Nu de iterator
Een map kan meerdere kinderen hebben. De makkelijkste manier om langs al deze te gaan is gebruik te maken van een iterator. Dit is een object dat je in foreach kan stoppen. Om van een object een iterator te maken, laat je hem de 'Iterator' interface implementeren en de functies valid(), current(), key(), next() en rewind().
Dit is vaak een beetje veel gedoe en dus kan je niet het object zelf de iterator laten zijn, maar een iterator laten genereren. Dit gebeurt automatisch wanneer je een foreach gebruikt. Hiervoor implenteer je de interface 'IteratorAggregate' en de methode getIterator(). Omdat de te iteraten waarden in een array staan, maken we gebruik van de 'ArrayIterator', die de data uit een array haalt. Deze is standaard in PHP meegegeven in de SPL, een standaard uitbreiding op PHP.
Denk aan mn naming convention... camelCase en properties zonder _ (ze zijn toch altijd protected)
FileNodeBuilder::$_dir is ongebruikt.
Verder kan je nog denken aan een opgegeven zoekdiepte of zelfs lazy load dirs.
En wat is er beter aan scandir dan?
En verder kan de volgorde beter met een constant.
En nog wat dingen naar mijn ogen mooier gemaakt.
En van childs children gemaakt ;)
Dus dan zo:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<?PHP
// Abstracte klasse voor een file of een map
abstract class FileNode
{
protected $name;
protected $path;
public function __construct($name, $path)
{
$this->name = $name;
$this->path = $path;
}
public function getName()
{
return $this->name;
}
public function getPath()
{
return $this->path;
}
}
class File extends FileNode
{
protected $ext;
public function __construct($name, $path)
{
$this->ext = substr($name, strrpos($name, '.'));
parent::__construct($name, $path);
}
public function getExtension()
{
return $this->ext;
}
public function getContents()
{
if(!is_readable($this->path))
throw new Exception($this->path.' is not readable');
return file_get_contents($this->path);
}
}
class Dir extends FileNode implements IteratorAggregate
{
protected $dirChildren = array();
protected $fileChildren = array();
protected $name;
const ORDER_ASC = 1;
const ORDER_DESC = 2;
public function addChild(FileNode $node)
{
if($node instanceof Dir)
$this->dirChildren[] = $node;
if($node instanceof File)
$this->fileChildren[] = $node;
}
public function getChildren()
{
return array_merge($this->dirChildren, $this->fileChildren);
}
public function getFileChildren()
{
return $this->fileChildren;
}
public function getDirChildren()
{
return $this->dirChildren;
}
public function getIterator()
{
return new ArrayIterator($this->getChildren());
}
public function buildArray($order = self::ORDER_ASC)
{
$array = array();
if($order == self::ORDER_ASC) {
sort($this->dirChildren);
sort($this->fileChildren);
foreach($this->dirChildren as $child)
$array[$child->getName()] = $child->buildArray();
foreach($this->fileChildren as $child)
$array[] = $child->getName();
} else {
rsort($this->dirChildren);
rsort($this->fileChildren);
foreach($this->fileCchildren as $child)
$array[] = $child->getName();
foreach($this->dirChildren as $child)
$array[$child->getName()] = $child->buildArray();
}
return $array;
}
}
class FileNodeBuilder
{
public function build($path, $depth = null, $isRoot = true)
{
if($isRoot)
$path = realpath($path);
if(!is_dir($path))
throw new Exception($path.' is no directory');
if(!is_readable($path))
throw new Exception($path.' is not readable');
$dirName = substr($path, strrpos($path, DIRECTORY_SEPARATOR)+1);
$dir = new Dir($dirName, $path);
foreach(scandir($path) as $file) {
if($file == '.' || $file == '..')
continue;
$newPath = $path.DIRECTORY_SEPARATOR.$file;
if(is_dir($newPath))
if(is_null($depth))
$dir->addChild($this->build($newPath, null, false));
elseif($depth > 1)
$dir->addChild($this->build($newPath, $depth-1, false));
else
$dir->addChild(new Dir($file, $newPath));
if(is_file($newPath))
$dir->addChild(new File($file, $newPath));
}
return $dir;
}
}
$builder = new FileNodeBuilder;
$data = $builder->build('./');
echo '<pre>'.PHP_EOL;
print_r($data->buildArray());
echo '</pre>';
?>
// Abstracte klasse voor een file of een map
abstract class FileNode
{
protected $name;
protected $path;
public function __construct($name, $path)
{
$this->name = $name;
$this->path = $path;
}
public function getName()
{
return $this->name;
}
public function getPath()
{
return $this->path;
}
}
class File extends FileNode
{
protected $ext;
public function __construct($name, $path)
{
$this->ext = substr($name, strrpos($name, '.'));
parent::__construct($name, $path);
}
public function getExtension()
{
return $this->ext;
}
public function getContents()
{
if(!is_readable($this->path))
throw new Exception($this->path.' is not readable');
return file_get_contents($this->path);
}
}
class Dir extends FileNode implements IteratorAggregate
{
protected $dirChildren = array();
protected $fileChildren = array();
protected $name;
const ORDER_ASC = 1;
const ORDER_DESC = 2;
public function addChild(FileNode $node)
{
if($node instanceof Dir)
$this->dirChildren[] = $node;
if($node instanceof File)
$this->fileChildren[] = $node;
}
public function getChildren()
{
return array_merge($this->dirChildren, $this->fileChildren);
}
public function getFileChildren()
{
return $this->fileChildren;
}
public function getDirChildren()
{
return $this->dirChildren;
}
public function getIterator()
{
return new ArrayIterator($this->getChildren());
}
public function buildArray($order = self::ORDER_ASC)
{
$array = array();
if($order == self::ORDER_ASC) {
sort($this->dirChildren);
sort($this->fileChildren);
foreach($this->dirChildren as $child)
$array[$child->getName()] = $child->buildArray();
foreach($this->fileChildren as $child)
$array[] = $child->getName();
} else {
rsort($this->dirChildren);
rsort($this->fileChildren);
foreach($this->fileCchildren as $child)
$array[] = $child->getName();
foreach($this->dirChildren as $child)
$array[$child->getName()] = $child->buildArray();
}
return $array;
}
}
class FileNodeBuilder
{
public function build($path, $depth = null, $isRoot = true)
{
if($isRoot)
$path = realpath($path);
if(!is_dir($path))
throw new Exception($path.' is no directory');
if(!is_readable($path))
throw new Exception($path.' is not readable');
$dirName = substr($path, strrpos($path, DIRECTORY_SEPARATOR)+1);
$dir = new Dir($dirName, $path);
foreach(scandir($path) as $file) {
if($file == '.' || $file == '..')
continue;
$newPath = $path.DIRECTORY_SEPARATOR.$file;
if(is_dir($newPath))
if(is_null($depth))
$dir->addChild($this->build($newPath, null, false));
elseif($depth > 1)
$dir->addChild($this->build($newPath, $depth-1, false));
else
$dir->addChild(new Dir($file, $newPath));
if(is_file($newPath))
$dir->addChild(new File($file, $newPath));
}
return $dir;
}
}
$builder = new FileNodeBuilder;
$data = $builder->build('./');
echo '<pre>'.PHP_EOL;
print_r($data->buildArray());
echo '</pre>';
?>
Ik stel het zeer op prijs dat je het script wou verbeteren, maar ik vind het wel vrij vervelend dat je alle conventies die ik gebruik (vooral Zend) omzet naar iets anders...
En nu uitleg:
Eerst was leeswerk:
Basic PHP OOP
http://phptuts.nl/view/45/
Over het composite pattern
http://devzone.zend.com/article/7
Dit gebruiken we bij het bestandensysteem.
Hoe het nu in elkaar zit hebben we een bouwer (Builder pattern) die het in elkaar zet. We krijgen dan een root map en die heeft dan weer submappen en -bestanden.
Zover duidelijk?
Nu de iterator
Een map kan meerdere kinderen hebben. De makkelijkste manier om langs al deze te gaan is gebruik te maken van een iterator. Dit is een object dat je in foreach kan stoppen. Om van een object een iterator te maken, laat je hem de 'Iterator' interface implementeren en de functies valid(), current(), key(), next() en rewind().
Dit is vaak een beetje veel gedoe en dus kan je niet het object zelf de iterator laten zijn, maar een iterator laten genereren. Dit gebeurt automatisch wanneer je een foreach gebruikt. Hiervoor implenteer je de interface 'IteratorAggregate' en de methode getIterator(). Omdat de te iteraten waarden in een array staan, maken we gebruik van de 'ArrayIterator', die de data uit een array haalt. Deze is standaard in PHP meegegeven in de SPL, een standaard uitbreiding op PHP.
@Pim:
Ben zelf ook nog niet zolang bezig met OOP, dus van Zend weet ik nog niet zoveel. Het voordeel van scandir vind ik dat je geen stream terugkrijgt, waar je verder toch niet veel mee doet (je haalt toch alle bestanden op). En de resource blijf openstaan zolang hij bezig is een child aan te maken/te zoeken, dit betekend dat de rootdir-resource heel lang openstaat, terwijl die array gewoon in een variable wordt opgeslagen.
Iemand zou een testje kunnen maken door alle dirs door te gaan met zowel scandir als opendir en readdir, en kijken welke het snelte is.
Wat bedoel je met Zend Conventies?
Ben zelf ook nog niet zolang bezig met OOP, dus van Zend weet ik nog niet zoveel. Het voordeel van scandir vind ik dat je geen stream terugkrijgt, waar je verder toch niet veel mee doet (je haalt toch alle bestanden op). En de resource blijf openstaan zolang hij bezig is een child aan te maken/te zoeken, dit betekend dat de rootdir-resource heel lang openstaat, terwijl die array gewoon in een variable wordt opgeslagen.
Iemand zou een testje kunnen maken door alle dirs door te gaan met zowel scandir als opendir en readdir, en kijken welke het snelte is.
Wat bedoel je met Zend Conventies?
http://framework.zend.com/manual/en/coding-standard.html
Dit beschrijft de stijl waarin het Zend Framework moet worden geschreven. Het wordt door veel mensen, inclusief mijzelf, als 'net' gezien en wordt dus ook buiten het Zend Framework in andere code gebruikt.
Dit beschrijft de stijl waarin het Zend Framework moet worden geschreven. Het wordt door veel mensen, inclusief mijzelf, als 'net' gezien en wordt dus ook buiten het Zend Framework in andere code gebruikt.
Wow, Pim hoelang script jij al in OOP. Ik snap er echt helemaal niks van. Ik zie het licht van OOP nog niet, maar dat komt wel (zolang er geen Frans in voor komt).
Over dat Zend Framework, is dat een uitbreiding van PHP? Heb er wel eens wat van gehoort van niet echt in verdiept.
Bedankt voor alle :D
Over dat Zend Framework, is dat een uitbreiding van PHP? Heb er wel eens wat van gehoort van niet echt in verdiept.
Bedankt voor alle :D
Je moet Zend Framework als een raamwerk van je applicatie zien.
Begin anders eens met dit: http://zendframework.com/manual/en/learning.quickstart.intro.html
Verder ben ik niet echt fan van alle componenten ( Zend_Form, Zend_Navigation, etc ) zend framework, maar daar kom je vanzelf nog wel achter. Je leert hierdoor ook het MVC pattern heel goed kennen.
Let op: Bij die quick start wordt er geadviseerd een virtual host file aan te maken. Dat is nergens voor nodig. Niet doen dus, Verder is Zend_Tool ook raar dus het hele gedoe met die environment variabelen toevoegen moet je ook maar overslaan.
Owja, wat me nog even te binnen schiet: Vergeet niet de libary te downloaden en die aan je include_path te koppelen..
Succes!
Begin anders eens met dit: http://zendframework.com/manual/en/learning.quickstart.intro.html
Verder ben ik niet echt fan van alle componenten ( Zend_Form, Zend_Navigation, etc ) zend framework, maar daar kom je vanzelf nog wel achter. Je leert hierdoor ook het MVC pattern heel goed kennen.
Let op: Bij die quick start wordt er geadviseerd een virtual host file aan te maken. Dat is nergens voor nodig. Niet doen dus, Verder is Zend_Tool ook raar dus het hele gedoe met die environment variabelen toevoegen moet je ook maar overslaan.
Owja, wat me nog even te binnen schiet: Vergeet niet de libary te downloaden en die aan je include_path te koppelen..
Succes!
Niet doen! ;). Leer eerst de basisbeginselen van OOP, lees dan dit door en ga dan pas een framework gebruiken. Andersom schept het alleen maar verwarring.
Wat is er mis met Zend_Form dan?
En environment vars (dat is toch test/dev/prod?) zijn echt handig, bijv. om een aparte test-db te hebben of om debugging tools makkelijk aan of uit te zetten.
Wat is er mis met Zend_Form dan?
En environment vars (dat is toch test/dev/prod?) zijn echt handig, bijv. om een aparte test-db te hebben of om debugging tools makkelijk aan of uit te zetten.
@Pim
Ik was dus in de veronderstelling dat hij de beginselen al wist. Maar dat hij Zend Framework niet begreep.
Van alles, maar nu even geen tijd om daar uitgebreid op te reageren, dat zal ik vanavond of morgen wel even doen..
Jaa zeker, ze zijn supper handig maar ik vind Zend_Tool overbodig.
bijvoorbeeld een action schrijven gebeurd zo: ( Uit me hoofd ) zf create action [controllernaam] [actienaam]
Dat is toch vaag? Ik bedoel,
Is toch gewoon goed? En schrijft toch ook veel lekkerder? Het is toch PHP en geen shell?
Quote:
Niet doen! ;). Leer eerst de basisbeginselen van OOP, lees dan dit
Ik was dus in de veronderstelling dat hij de beginselen al wist. Maar dat hij Zend Framework niet begreep.
Quote:
Wat is er mis met Zend_Form dan?
Van alles, maar nu even geen tijd om daar uitgebreid op te reageren, dat zal ik vanavond of morgen wel even doen..
Quote:
En environment vars (dat is toch test/dev/prod?) zijn echt handig, bijv. om een aparte test-db te hebben of om debugging tools makkelijk aan of uit te zetten.
Jaa zeker, ze zijn supper handig maar ik vind Zend_Tool overbodig.
bijvoorbeeld een action schrijven gebeurd zo: ( Uit me hoofd ) zf create action [controllernaam] [actienaam]
Dat is toch vaag? Ik bedoel,
Is toch gewoon goed? En schrijft toch ook veel lekkerder? Het is toch PHP en geen shell?
Ik ken al een beetje OOP dus de beginselen snap ik wel. Alleen het moeilijke deel van OOP zoals classes inelkaar voegen etc. snap ik nog niet zo.
@Niels Kieviet, ik snap nog echt niet wat zend inhoud, raamkozijn, daarin zit een raam... Dus zend zijn dus functie die je in je php script kan gebruiken (dat maak ik eruit)
Maar ik ga maar eerst me verdiepen in OOP en snap wat alles inhoud en dan ga ik naar de raamkozijn kijken. :)
What the hell is shell?? Een benzinepomp?
@Niels Kieviet, ik snap nog echt niet wat zend inhoud, raamkozijn, daarin zit een raam... Dus zend zijn dus functie die je in je php script kan gebruiken (dat maak ik eruit)
Maar ik ga maar eerst me verdiepen in OOP en snap wat alles inhoud en dan ga ik naar de raamkozijn kijken. :)
What the hell is shell?? Een benzinepomp?
Niels, vrijwel alle frameworks gebruiken shell commands (dat is de command line tool, dus [windows]+r en dan 'cmd'), bijvoorbeeld om met doctrine je DB schema te verversen. De Zend_Tool implementatie is idd echt slecht. Ook zat er laatst een enorme bug in waardoor je op windows zelf de lib moet gaan zitten aan te passen om überhaupt een command in te kunnen voeren.
@Carlo
Lees maar dat artikel door wat ik je stuurde over MVC. Dan begrijp je dat het handig is een bepaalde basis te gebruiken, zodat je niet bij elke applicatie opnieuw moet gaan werken aan routing, dispatching, views e.d. (die termen staan in het artikel verklaard)
@Carlo
Lees maar dat artikel door wat ik je stuurde over MVC. Dan begrijp je dat het handig is een bepaalde basis te gebruiken, zodat je niet bij elke applicatie opnieuw moet gaan werken aan routing, dispatching, views e.d. (die termen staan in het artikel verklaard)
Quote:
Niels, vrijwel alle frameworks gebruiken shell commands
Weet ik. Maar ik zie het nut er niet van in. Kijk DB schema verwezen is wat anders maar om een action of een controller te generen vind ik overbodig. Die bug ben ik tegengekomen:(
Of lees gewoon bij de introductie van zend framework over MVC. Als ik me niet vergis wordt het aan de hand van plaatjes netjes uitgelegd.
Verder over Zend_Form even heel kort: Je moet veel te veel typen om een form te genereren zodat je het best gewoon een form in phtml kan zetten.
Om te reageren heb je een account nodig en je moet ingelogd zijn.
PHP hulp
0 seconden vanaf nu