"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "smb.php" see the
Fossies "Dox" file reference documentation.
1 <?php
2 ###################################################################
3 # smb.php
4 # This class implements a SMB stream wrapper based on 'smbclient'
5 #
6 # Date: lun oct 22 10:35:35 CEST 2007
7 #
8 # Homepage: http://www.phpclasses.org/smb4php
9 #
10 # Copyright (c) 2007 Victor M. Varela <vmvarela@gmail.com>
11 #
12 # This program is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; either version 2
15 # of the License, or (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 ###################################################################
23
24 define ('SMB4PHP_VERSION', '0.8');
25
26 ###################################################################
27 # CONFIGURATION SECTION - Change for your needs
28 ###################################################################
29
30 define ('SMB4PHP_SMBCLIENT', 'smbclient');
31 define ('SMB4PHP_SMBOPTIONS', 'TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE SO_RCVBUF=8192 SO_SNDBUF=8192');
32 define ('SMB4PHP_AUTHMODE', 'arg'); # set to 'env' to use USER enviroment variable
33
34 ###################################################################
35 # SMB - commands that does not need an instance
36 ###################################################################
37
38 $GLOBALS['__smb_cache'] = array ('stat' => array (), 'dir' => array ());
39
40 class smb {
41
42 function parse_url ($url) {
43 $pu = parse_url (trim($url));
44 foreach (array ('domain', 'user', 'pass', 'host', 'port', 'path') as $i)
45 if (! isset($pu[$i])) $pu[$i] = '';
46 if (count ($userdomain = split (';', urldecode ($pu['user']))) > 1)
47 @list ($pu['domain'], $pu['user']) = $userdomain;
48 $path = preg_replace (array ('/^\//', '/\/$/'), '', urldecode ($pu['path']));
49 list ($pu['share'], $pu['path']) = (preg_match ('/^([^\/]+)\/(.*)/', $path, $regs))
50 ? array ($regs[1], preg_replace ('/\//', '\\', $regs[2]))
51 : array ($path, '');
52 $pu['type'] = $pu['path'] ? 'path' : ($pu['share'] ? 'share' : ($pu['host'] ? 'host' : '**error**'));
53 if (! ($pu['port'] = intval(@$pu['port']))) $pu['port'] = 139;
54 return $pu;
55 }
56
57
58 function look ($purl) {
59 return smb::client ('-L ' . escapeshellarg ($purl['host']), $purl);
60 }
61
62
63 function execute ($command, $purl) {
64 return smb::client ('-d 0 '
65 . escapeshellarg ('//' . $purl['host'] . '/' . $purl['share'])
66 . ' -c ' . escapeshellarg ($command), $purl
67 );
68 }
69
70 function client ($params, $purl) {
71
72 static $regexp = array (
73 '^added interface ip=(.*) bcast=(.*) nmask=(.*)$' => 'skip',
74 'Anonymous login successful' => 'skip',
75 '^Domain=\[(.*)\] OS=\[(.*)\] Server=\[(.*)\]$' => 'skip',
76 '^\tSharename[ ]+Type[ ]+Comment$' => 'shares',
77 '^\t---------[ ]+----[ ]+-------$' => 'skip',
78 '^\tServer [ ]+Comment$' => 'servers',
79 '^\t---------[ ]+-------$' => 'skip',
80 '^\tWorkgroup[ ]+Master$' => 'workg',
81 '^\t(.*)[ ]+(Disk|IPC)[ ]+IPC.*$' => 'skip',
82 '^\tIPC\\\$(.*)[ ]+IPC' => 'skip',
83 '^\t(.*)[ ]+(Disk)[ ]+(.*)$' => 'share',
84 '^\t(.*)[ ]+(Printer)[ ]+(.*)$' => 'skip',
85 '([0-9]+) blocks of size ([0-9]+)\. ([0-9]+) blocks available' => 'skip',
86 'Got a positive name query response from ' => 'skip',
87 '^(session setup failed): (.*)$' => 'error',
88 '^(.*): ERRSRV - ERRbadpw' => 'error',
89 '^Error returning browse list: (.*)$' => 'error',
90 '^tree connect failed: (.*)$' => 'error',
91 '^(Connection to .* failed)$' => 'error',
92 '^NT_STATUS_(.*) ' => 'error',
93 '^NT_STATUS_(.*)\$' => 'error',
94 'ERRDOS - ERRbadpath \((.*).\)' => 'error',
95 'cd (.*): (.*)$' => 'error',
96 '^cd (.*): NT_STATUS_(.*)' => 'error',
97 '^\t(.*)$' => 'srvorwg',
98 '^([0-9]+)[ ]+([0-9]+)[ ]+(.*)$' => 'skip',
99 '^Job ([0-9]+) cancelled' => 'skip',
100 '^[ ]+(.*)[ ]+([0-9]+)[ ]+(Mon|Tue|Wed|Thu|Fri|Sat|Sun)[ ](Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+([0-9]+)[ ]+([0-9]{2}:[0-9]{2}:[0-9]{2})[ ]([0-9]{4})$' => 'files',
101 '^message start: ERRSRV - (ERRmsgoff)' => 'error'
102 );
103
104 if (SMB4PHP_AUTHMODE == 'env') {
105 putenv("USER={$purl['user']}%{$purl['pass']}");
106 $auth = '';
107 } else {
108 $auth = ($purl['user'] <> '' ? (' -U ' . escapeshellarg ($purl['user'] . '%' . $purl['pass'])) : '');
109 }
110 if ($purl['domain'] <> '') {
111 $auth .= ' -W ' . escapeshellarg ($purl['domain']);
112 }
113 $port = ($purl['port'] <> 139 ? ' -p ' . escapeshellarg ($purl['port']) : '');
114 $options = '-O ' . escapeshellarg(SMB4PHP_SMBOPTIONS);
115 $output = popen (SMB4PHP_SMBCLIENT." -N {$auth} {$options} {$port} {$options} {$params} 2>/dev/null", 'r');
116 $info = array ();
117 while ($line = fgets ($output, 4096)) {
118 list ($tag, $regs, $i) = array ('skip', array (), array ());
119 reset ($regexp);
120 foreach ($regexp as $r => $t) if (preg_match ('/'.$r.'/', $line, $regs)) {
121 $tag = $t;
122 break;
123 }
124 switch ($tag) {
125 case 'skip': continue;
126 case 'shares': $mode = 'shares'; break;
127 case 'servers': $mode = 'servers'; break;
128 case 'workg': $mode = 'workgroups'; break;
129 case 'share':
130 list($name, $type) = array (
131 trim(substr($line, 1, 15)),
132 trim(strtolower(substr($line, 17, 10)))
133 );
134 $i = ($type <> 'disk' && preg_match('/^(.*) Disk/', $line, $regs))
135 ? array(trim($regs[1]), 'disk')
136 : array($name, 'disk');
137 break;
138 case 'srvorwg':
139 list ($name, $master) = array (
140 strtolower(trim(substr($line,1,21))),
141 strtolower(trim(substr($line, 22)))
142 );
143 $i = ($mode == 'servers') ? array ($name, "server") : array ($name, "workgroup", $master);
144 break;
145 case 'files':
146 list ($attr, $name) = preg_match ("/^(.*)[ ]+([D|A|H|S|R]+)$/", trim ($regs[1]), $regs2)
147 ? array (trim ($regs2[2]), trim ($regs2[1]))
148 : array ('', trim ($regs[1]));
149 list ($his, $im) = array (
150 split(':', $regs[6]), 1 + strpos("JanFebMarAprMayJunJulAugSepOctNovDec", $regs[4]) / 3);
151 $i = ($name <> '.' && $name <> '..')
152 ? array (
153 $name,
154 (strpos($attr,'D') === FALSE) ? 'file' : 'folder',
155 'attr' => $attr,
156 'size' => intval($regs[2]),
157 'time' => mktime ($his[0], $his[1], $his[2], $im, $regs[5], $regs[7])
158 )
159 : array();
160 break;
161 case 'error': trigger_error($regs[1], E_USER_ERROR);
162 }
163 if ($i) switch ($i[1]) {
164 case 'file':
165 case 'folder': $info['info'][$i[0]] = $i;
166 case 'disk':
167 case 'server':
168 case 'workgroup': $info[$i[1]][] = $i[0];
169 }
170 }
171 pclose($output);
172 return $info;
173 }
174
175
176 # stats
177
178 function url_stat ($url, $flags = STREAM_URL_STAT_LINK) {
179 if ($s = smb::getstatcache($url)) { return $s; }
180 list ($stat, $pu) = array (array (), smb::parse_url ($url));
181 switch ($pu['type']) {
182 case 'host':
183 if ($o = smb::look ($pu))
184 $stat = stat ("/tmp");
185 else
186 trigger_error ("url_stat(): list failed for host '{$host}'", E_USER_WARNING);
187 break;
188 case 'share':
189 if ($o = smb::look ($pu)) {
190 $found = FALSE;
191 $lshare = strtolower ($pu['share']); # fix by Eric Leung
192 foreach ($o['disk'] as $s) if ($lshare == strtolower($s)) {
193 $found = TRUE;
194 $stat = stat ("/tmp");
195 break;
196 }
197 if (! $found)
198 trigger_error ("url_stat(): disk resource '{$share}' not found in '{$host}'", E_USER_WARNING);
199 }
200 break;
201 case 'path':
202 if ($o = smb::execute ('dir "'.$pu['path'].'"', $pu)) {
203 $p = split ("[\\]", $pu['path']);
204 $name = $p[count($p)-1];
205 if (isset ($o['info'][$name])) {
206 $stat = smb::addstatcache ($url, $o['info'][$name]);
207 } else {
208 trigger_error ("url_stat(): path '{$pu['path']}' not found", E_USER_WARNING);
209 }
210 } else {
211 trigger_error ("url_stat(): dir failed for path '{$pu['path']}'", E_USER_WARNING);
212 }
213 break;
214 default: trigger_error ('error in URL', E_USER_ERROR);
215 }
216 return $stat;
217 }
218
219 function addstatcache ($url, $info) {
220 global $__smb_cache;
221 $is_file = (strpos ($info['attr'],'D') === FALSE);
222 $s = ($is_file) ? stat ('/etc/passwd') : stat ('/tmp');
223 $s[7] = $s['size'] = $info['size'];
224 $s[8] = $s[9] = $s[10] = $s['atime'] = $s['mtime'] = $s['ctime'] = $info['time'];
225 return $__smb_cache['stat'][$url] = $s;
226 }
227
228 function getstatcache ($url) {
229 global $__smb_cache;
230 return isset ($__smb_cache['stat'][$url]) ? $__smb_cache['stat'][$url] : FALSE;
231 }
232
233 function clearstatcache ($url='') {
234 global $__smb_cache;
235 if ($url == '') $__smb_cache['stat'] = array (); else unset ($__smb_cache['stat'][$url]);
236 }
237
238
239 # commands
240
241 function unlink ($url) {
242 $pu = smb::parse_url($url);
243 if ($pu['type'] <> 'path') trigger_error('unlink(): error in URL', E_USER_ERROR);
244 smb::clearstatcache ($url);
245 return smb::execute ('del "'.$pu['path'].'"', $pu);
246 }
247
248 function rename ($url_from, $url_to) {
249 list ($from, $to) = array (smb::parse_url($url_from), smb::parse_url($url_to));
250 if ($from['host'] <> $to['host'] ||
251 $from['share'] <> $to['share'] ||
252 $from['user'] <> $to['user'] ||
253 $from['pass'] <> $to['pass'] ||
254 $from['domain'] <> $to['domain']) {
255 trigger_error('rename(): FROM & TO must be in same server-share-user-pass-domain', E_USER_ERROR);
256 }
257 if ($from['type'] <> 'path' || $to['type'] <> 'path') {
258 trigger_error('rename(): error in URL', E_USER_ERROR);
259 }
260 smb::clearstatcache ($url_from);
261 return smb::execute ('rename "'.$from['path'].'" "'.$to['path'].'"', $to);
262 }
263
264 function mkdir ($url, $mode, $options) {
265 $pu = smb::parse_url($url);
266 if ($pu['type'] <> 'path') trigger_error('mkdir(): error in URL', E_USER_ERROR);
267 return smb::execute ('mkdir "'.$pu['path'].'"', $pu);
268 }
269
270 function rmdir ($url) {
271 $pu = smb::parse_url($url);
272 if ($pu['type'] <> 'path') trigger_error('rmdir(): error in URL', E_USER_ERROR);
273 smb::clearstatcache ($url);
274 return smb::execute ('rmdir "'.$pu['path'].'"', $pu);
275 }
276
277 }
278
279 ###################################################################
280 # SMB_STREAM_WRAPPER - class to be registered for smb:// URLs
281 ###################################################################
282
283 class smb_stream_wrapper extends smb {
284
285 # variables
286
287 var $stream, $url, $parsed_url = array (), $mode, $tmpfile;
288 var $need_flush = FALSE;
289 var $dir = array (), $dir_index = -1;
290
291
292 # directories
293
294 function dir_opendir ($url, $options) {
295 if ($d = $this->getdircache ($url)) {
296 $this->dir = $d;
297 $this->dir_index = 0;
298 return TRUE;
299 }
300 $pu = smb::parse_url ($url);
301 switch ($pu['type']) {
302 case 'host':
303 if ($o = smb::look ($pu)) {
304 $this->dir = $o['disk'];
305 $this->dir_index = 0;
306 } else {
307 trigger_error ("dir_opendir(): list failed for host '{$pu['host']}'", E_USER_WARNING);
308 }
309 break;
310 case 'share':
311 case 'path':
312 if ($o = smb::execute ('dir "'.$pu['path'].'\*"', $pu)) {
313 $this->dir = array_keys($o['info']);
314 $this->dir_index = 0;
315 $this->adddircache ($url, $this->dir);
316 foreach ($o['info'] as $name => $info) {
317 smb::addstatcache($url . '/' . urlencode($name), $info);
318 }
319 } else {
320 trigger_error ("dir_opendir(): dir failed for path '{$path}'", E_USER_WARNING);
321 }
322 break;
323 default:
324 trigger_error ('dir_opendir(): error in URL', E_USER_ERROR);
325 }
326 return TRUE;
327 }
328
329 function dir_readdir () { return ($this->dir_index < count($this->dir)) ? $this->dir[$this->dir_index++] : FALSE; }
330
331 function dir_rewinddir () { $this->dir_index = 0; }
332
333 function dir_closedir () { $this->dir = array(); $this->dir_index = -1; return TRUE; }
334
335
336 # cache
337
338 function adddircache ($url, $content) {
339 global $__smb_cache;
340 return $__smb_cache['dir'][$url] = $content;
341 }
342
343 function getdircache ($url) {
344 global $__smb_cache;
345 return isset ($__smb_cache['dir'][$url]) ? $__smb_cache['dir'][$url] : FALSE;
346 }
347
348 function cleardircache ($url='') {
349 global $__smb_cache;
350 if ($url == '') $__smb_cache['dir'] = array (); else unset ($__smb_cache['dir'][$url]);
351 }
352
353
354 # streams
355
356 function stream_open ($url, $mode, $options, $opened_path) {
357 $this->url = $url;
358 $this->mode = $mode;
359 $this->parsed_url = $pu = smb::parse_url($url);
360 if ($pu['type'] <> 'path') trigger_error('stream_open(): error in URL', E_USER_ERROR);
361 switch ($mode) {
362 case 'r':
363 case 'r+':
364 case 'rb':
365 case 'a':
366 case 'a+': $this->tmpfile = tempnam('/tmp', 'smb.down.');
367 smb::execute ('get "'.$pu['path'].'" "'.$this->tmpfile.'"', $pu);
368 break;
369 case 'w':
370 case 'w+':
371 case 'wb':
372 case 'x':
373 case 'x+': $this->cleardircache();
374 $this->tmpfile = tempnam('/tmp', 'smb.up.');
375 }
376 $this->stream = fopen ($this->tmpfile, $mode);
377 return TRUE;
378 }
379
380 function stream_close () { return fclose($this->stream); }
381
382 function stream_read ($count) { return fread($this->stream, $count); }
383
384 function stream_write ($data) { $this->need_flush = TRUE; return fwrite($this->stream, $data); }
385
386 function stream_eof () { return feof($this->stream); }
387
388 function stream_tell () { return ftell($this->stream); }
389
390 function stream_seek ($offset, $whence=null) { return fseek($this->stream, $offset, $whence); }
391
392 function stream_flush () {
393 if ($this->mode <> 'r' && $this->need_flush) {
394 smb::clearstatcache ($this->url);
395 smb::execute ('put "'.$this->tmpfile.'" "'.$this->parsed_url['path'].'"', $this->parsed_url);
396 $this->need_flush = FALSE;
397 }
398 }
399
400 function stream_stat () { return smb::url_stat ($this->url); }
401
402 function __destruct () {
403 if ($this->tmpfile <> '') {
404 if ($this->need_flush) $this->stream_flush ();
405 unlink ($this->tmpfile);
406
407 }
408 }
409
410 }
411
412 ###################################################################
413 # Register 'smb' protocol !
414 ###################################################################
415
416 stream_wrapper_register('smb', 'smb_stream_wrapper')
417 or die ('Failed to register protocol');
418
419 ?>