aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/largefilehelper.php
blob: 5f5e14aca3583bc3cecc16556cddaaf21fb3bb2c (plain)
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
<?php
/**
 * Copyright (c) 2014 Andreas Fischer <bantu@owncloud.com>
 * This file is licensed under the Affero General Public License version 3 or
 * later.
 * See the COPYING-README file.
 */

namespace OC;

/**
 * Helper class for large files on 32-bit platforms.
 */
class LargeFileHelper {
	/**
	* @brief Tries to get the filesize of a file via various workarounds that
	*        even work for large files on 32-bit platforms.
	*
	* @param string $filename Path to the file.
	*
	* @return null|int|float Number of bytes as number (float or int) or
	*                        null on failure.
	*/
	public function getFilesize($filename) {
		$filesize = $this->getFilesizeViaCurl($filename);
		if (!is_null($filesize)) {
			return $filesize;
		}
		$filesize = $this->getFilesizeViaCOM($filename);
		if (!is_null($filesize)) {
			return $filesize;
		}
		$filesize = $this->getFilesizeViaExec($filename);
		if (!is_null($filesize)) {
			return $filesize;
		}
		return null;
	}

	/**
	* @brief Tries to get the filesize of a file via a CURL HEAD request.
	*
	* @param string $filename Path to the file.
	*
	* @return null|int|float Number of bytes as number (float or int) or
	*                        null on failure.
	*/
	public function getFilesizeViaCurl($filename) {
		if (function_exists('curl_init')) {
			$ch = curl_init("file://$filename");
			curl_setopt($ch, CURLOPT_NOBODY, true);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_HEADER, true);
			$data = curl_exec($ch);
			curl_close($ch);
			if ($data !== false) {
				$matches = array();
				preg_match('/Content-Length: (\d+)/', $data, $matches);
				if (isset($matches[1])) {
					return 0 + $matches[1];
				}
			}
		}
		return null;
	}

	/**
	* @brief Tries to get the filesize of a file via the Windows DOM extension.
	*
	* @param string $filename Path to the file.
	*
	* @return null|int|float Number of bytes as number (float or int) or
	*                        null on failure.
	*/
	public function getFilesizeViaCOM($filename) {
		if (class_exists('COM')) {
			$fsobj = new \COM("Scripting.FileSystemObject");
			$file = $fsobj->GetFile($filename);
			return 0 + $file->Size;
		}
		return null;
	}

	/**
	* @brief Tries to get the filesize of a file via an exec() call.
	*
	* @param string $filename Path to the file.
	*
	* @return null|int|float Number of bytes as number (float or int) or
	*                        null on failure.
	*/
	public function getFilesizeViaExec($filename) {
		if (\OC_Helper::is_function_enabled('exec')) {
			$os = strtolower(php_uname('s'));
			$arg = escapeshellarg($filename);
			$result = '';
			if (strpos($os, 'linux') !== false) {
				$result = $this->exec("stat -c %s $arg");
			} else if (strpos($os, 'bsd') !== false) {
				$result = $this->exec("stat -f %z $arg");
			} else if (strpos($os, 'win') !== false) {
				$result = $this->exec("for %F in ($arg) do @echo %~zF");
				if (is_null($result)) {
					// PowerShell
					$result = $this->exec("(Get-Item $arg).length");
				}
			}
			return $result;
		}
		return null;
	}

	protected function exec($cmd) {
		$result = trim(exec($cmd));
		return ctype_digit($result) ? 0 + $result : null;
	}
}