Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

MDL-36538 repository_webdav - save files directly to local filesystem…

…, rather than buffering in memory
  • Loading branch information...
commit cf839b43962347e1180ba8e0d46bfbd97bd7e428 1 parent 325e266
Davo Smith davosmith authored

Showing 2 changed files with 63 additions and 45 deletions. Show diff stats Hide diff stats

  1. +62 40 lib/webdavlib.php
  2. +1 5 repository/webdav/lib.php
102 lib/webdavlib.php
@@ -265,15 +265,17 @@ function mkcol($path) {
265 265 * Public method get
266 266 *
267 267 * Gets a file from a webdav collection.
268   - * @param string path, string &buffer
269   - * @return status code and &$buffer (by reference) with response data from server on success. False on error.
  268 + * @param string $path the path to the file on the webdav server
  269 + * @param string &$buffer the buffer to store the data in
  270 + * @param resource $fp optional if included, the data is written directly to this resource and not to the buffer
  271 + * @return string|bool status code and &$buffer (by reference) with response data from server on success. False on error.
270 272 */
271   - function get($path, &$buffer) {
  273 + function get($path, &$buffer, $fp = null) {
272 274 $this->_path = $this->translate_uri($path);
273 275 $this->header_unset();
274 276 $this->create_basic_request('GET');
275 277 $this->send_request();
276   - $this->get_respond();
  278 + $this->get_respond($fp);
277 279 $response = $this->process_respond();
278 280
279 281 $http_version = $response['status']['http-version'];
@@ -283,8 +285,13 @@ function get($path, &$buffer) {
283 285 // seems to be http ... proceed
284 286 // We expect a 200 code
285 287 if ($response['status']['status-code'] == 200 ) {
286   - $this->_error_log('returning buffer with ' . strlen($response['body']) . ' bytes.');
287   - $buffer = $response['body'];
  288 + if (!is_null($fp)) {
  289 + $stat = fstat($fp);
  290 + $this->_error_log('file created with ' . $stat['size'] . ' bytes.');
  291 + } else {
  292 + $this->_error_log('returning buffer with ' . strlen($response['body']) . ' bytes.');
  293 + $buffer = $response['body'];
  294 + }
288 295 }
289 296 return $response['status']['status-code'];
290 297 }
@@ -387,27 +394,24 @@ function put_file($path, $filename) {
387 394 * Gets a file from a collection into local filesystem.
388 395 *
389 396 * fopen() is used.
390   - * @param string srcpath, string localpath
391   - * @return true on success. false on error.
  397 + * @param string $srcpath
  398 + * @param string $localpath
  399 + * @return bool true on success. false on error.
392 400 */
393 401 function get_file($srcpath, $localpath) {
394 402
395   - if ($this->get($srcpath, $buffer)) {
396   - // convert utf-8 filename to iso-8859-1
  403 + $localpath = $this->utf_decode_path($localpath);
397 404
398   - $localpath = $this->utf_decode_path($localpath);
399   -
400   - $handle = fopen ($localpath, 'w');
401   - if ($handle) {
402   - fwrite($handle, $buffer);
403   - fclose($handle);
  405 + $handle = fopen($localpath, 'wb');
  406 + if ($handle) {
  407 + $unused = '';
  408 + $ret = $this->get($srcpath, $unused, $handle);
  409 + fclose($handle);
  410 + if ($ret) {
404 411 return true;
405   - } else {
406   - return false;
407 412 }
408   - } else {
409   - return false;
410 413 }
  414 + return false;
411 415 }
412 416
413 417 /**
@@ -1447,8 +1451,9 @@ private function send_request() {
1447 1451 * This routine is the weakest part of this class, because it very depends how php does handle a socket stream.
1448 1452 * If the stream is blocked for some reason php is blocked as well.
1449 1453 * @access private
  1454 + * @param resource $fp optional the file handle to write the body content to (stored internally in the '_body' if not set)
1450 1455 */
1451   - private function get_respond() {
  1456 + private function get_respond($fp = null) {
1452 1457 $this->_error_log('get_respond()');
1453 1458 // init vars (good coding style ;-)
1454 1459 $buffer = '';
@@ -1509,7 +1514,8 @@ private function get_respond() {
1509 1514 $read = 0;
1510 1515 // Reading the chunk in one bite is not secure, we read it byte by byte.
1511 1516 while ($read < $chunk_size) {
1512   - $buffer .= fread($this->sock, 1);
  1517 + $chunk = fread($this->sock, 1);
  1518 + self::update_file_or_buffer($chunk, $fp, $buffer);
1513 1519 $read++;
1514 1520 }
1515 1521 }
@@ -1525,21 +1531,20 @@ private function get_respond() {
1525 1531 if ($matches[1] <= $max_chunk_size ) {
1526 1532 // only read something if Content-Length is bigger than 0
1527 1533 if ($matches[1] > 0 ) {
1528   - $buffer = fread($this->sock, $matches[1]);
1529   - $loadsize = strlen($buffer);
  1534 + $chunk = fread($this->sock, $matches[1]);
  1535 + $loadsize = strlen($chunk);
1530 1536 //did we realy get the full length?
1531 1537 if ($loadsize < $matches[1]) {
1532 1538 $max_chunk_size = $loadsize;
1533 1539 do {
1534   - $mod = $max_chunk_size % ($matches[1] - strlen($buffer));
1535   - $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - strlen($buffer));
1536   - $buffer .= fread($this->sock, $chunk_size);
1537   - $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . strlen($buffer));
  1540 + $mod = $max_chunk_size % ($matches[1] - strlen($chunk));
  1541 + $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - strlen($chunk));
  1542 + $chunk .= fread($this->sock, $chunk_size);
  1543 + $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . strlen($chunk));
1538 1544 } while ($mod == $max_chunk_size);
1539   - break;
1540   - } else {
1541   - break;
1542 1545 }
  1546 + self::update_file_or_buffer($chunk, $fp, $buffer);
  1547 + break;
1543 1548 } else {
1544 1549 $buffer = '';
1545 1550 break;
@@ -1548,20 +1553,23 @@ private function get_respond() {
1548 1553
1549 1554 // data is to big to handle it as one. Get it chunk per chunk...
1550 1555 //trying to get the full length of max_chunk_size
1551   - $buffer = fread($this->sock, $max_chunk_size);
1552   - $loadsize = strlen($buffer);
  1556 + $chunk = fread($this->sock, $max_chunk_size);
  1557 + $loadsize = strlen($chunk);
  1558 + self::update_file_or_buffer($chunk, $fp, $buffer);
1553 1559 if ($loadsize < $max_chunk_size) {
1554 1560 $max_chunk_size = $loadsize;
1555 1561 }
1556 1562 do {
1557   - $mod = $max_chunk_size % ($matches[1] - strlen($buffer));
1558   - $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - strlen($buffer));
1559   - $buffer .= fread($this->sock, $chunk_size);
1560   - $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . strlen($buffer));
  1563 + $mod = $max_chunk_size % ($matches[1] - $loadsize);
  1564 + $chunk_size = ($mod == $max_chunk_size ? $max_chunk_size : $matches[1] - $loadsize);
  1565 + $chunk = fread($this->sock, $chunk_size);
  1566 + self::update_file_or_buffer($chunk, $fp, $buffer);
  1567 + $loadsize += strlen($chunk);
  1568 + $this->_error_log('mod: ' . $mod . ' chunk: ' . $chunk_size . ' total: ' . $loadsize);
1561 1569 } while ($mod == $max_chunk_size);
1562   - $loadsize = strlen($buffer);
1563 1570 if ($loadsize < $matches[1]) {
1564   - $buffer .= fread($this->sock, $matches[1] - $loadsize);
  1571 + $chunk = fread($this->sock, $matches[1] - $loadsize);
  1572 + self::update_file_or_buffer($chunk, $fp, $buffer);
1565 1573 }
1566 1574 break;
1567 1575
@@ -1577,7 +1585,8 @@ private function get_respond() {
1577 1585 $this->_error_log('reading until feof...' . $header);
1578 1586 socket_set_timeout($this->sock, 0, 0);
1579 1587 while (!feof($this->sock)) {
1580   - $buffer .= fread($this->sock, 4096);
  1588 + $chunk = fread($this->sock, 4096);
  1589 + self::update_file_or_buffer($chunk, $fp, $buffer);
1581 1590 }
1582 1591 // renew the socket timeout...does it do something ???? Is it needed. More debugging needed...
1583 1592 socket_set_timeout($this->sock, $this->_socket_timeout, 0);
@@ -1591,6 +1600,19 @@ private function get_respond() {
1591 1600
1592 1601 }
1593 1602
  1603 + /**
  1604 + * Write the chunk to the file if $fp is set, otherwise append the data to the buffer
  1605 + * @param string $chunk the data to add
  1606 + * @param resource $fp the file handle to write to (or null)
  1607 + * @param string &$buffer the buffer to append to (if $fp is null)
  1608 + */
  1609 + static private function update_file_or_buffer($chunk, $fp, &$buffer) {
  1610 + if ($fp) {
  1611 + fwrite($fp, $chunk);
  1612 + } else {
  1613 + $buffer .= $chunk;
  1614 + }
  1615 + }
1594 1616
1595 1617 /**
1596 1618 * Private method process_respond
6 repository/webdav/lib.php
@@ -71,17 +71,13 @@ public function check_login() {
71 71 return true;
72 72 }
73 73 public function get_file($url, $title = '') {
74   - global $CFG;
75 74 $url = urldecode($url);
76 75 $path = $this->prepare_file($title);
77   - $buffer = '';
78 76 if (!$this->dav->open()) {
79 77 return false;
80 78 }
81 79 $webdavpath = rtrim('/'.ltrim($this->options['webdav_path'], '/ '), '/ '); // without slash in the end
82   - $this->dav->get($webdavpath. $url, $buffer);
83   - $fp = fopen($path, 'wb');
84   - fwrite($fp, $buffer);
  80 + $this->dav->get_file($webdavpath. $url, $path);
85 81 return array('path'=>$path);
86 82 }
87 83 public function global_search() {

0 comments on commit cf839b4

Please sign in to comment.
Something went wrong with that request. Please try again.