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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
<?php namespace Dropbox;
/** * Path validation functions. */ final class Path { /** * Return whether the given path is a valid Dropbox path. * * @param string $path * The path you want to check for validity. * * @return bool * Whether the path was valid or not. */ static function isValid($path) { $error = self::findError($path); return ($error === null); }
/** * Return whether the given path is a valid non-root Dropbox path. * This is the same as {@link isValid} except <code>"/"</code> is not allowed. * * @param string $path * The path you want to check for validity. * * @return bool * Whether the path was valid or not. */ static function isValidNonRoot($path) { $error = self::findErrorNonRoot($path); return ($error === null); }
/** * If the given path is a valid Dropbox path, return <code>null</code>, * otherwise return an English string error message describing what is wrong with the path. * * @param string $path * The path you want to check for validity. * * @return string|null * If the path was valid, return <code>null</code>. Otherwise, returns * an English string describing the problem. */ static function findError($path) { Checker::argString("path", $path);
$matchResult = preg_match('%^(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBD] # excluding overlongs, FFFE, and FFFF | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates )*$%xs', $path);
if ($matchResult !== 1) { return "must be valid UTF-8; BMP only, no surrogates, no U+FFFE or U+FFFF"; }
if (\substr_compare($path, "/", 0, 1) !== 0) return "must start with \"/\""; $l = strlen($path); if ($l === 1) return null; // Special case for "/"
if ($path[$l-1] === "/") return "must not end with \"/\"";
// TODO: More checks.
return null; }
/** * If the given path is a valid non-root Dropbox path, return <code>null</code>, * otherwise return an English string error message describing what is wrong with the path. * This is the same as {@link findError} except <code>"/"</code> will yield an error message. * * @param string $path * The path you want to check for validity. * * @return string|null * If the path was valid, return <code>null</code>. Otherwise, returns * an English string describing the problem. */ static function findErrorNonRoot($path) { if ($path == "/") return "root path not allowed"; return self::findError($path); }
/** * Return the last component of a path (the file or folder name). * * <code> * Path::getName("/Misc/Notes.txt") // "Notes.txt" * Path::getName("/Misc") // "Misc" * Path::getName("/") // null * </code> * * @param string $path * The full path you want to get the last component of. * * @return null|string * The last component of <code>$path</code> or <code>null</code> if the given * <code>$path</code> was <code>"/"<code>. */ static function getName($path) { Checker::argString("path", $path);
if (\substr_compare($path, "/", 0, 1) !== 0) { throw new \InvalidArgumentException("'path' must start with \"/\""); } $l = strlen($path); if ($l === 1) return null; if ($path[$l-1] === "/") { throw new \InvalidArgumentException("'path' must not end with \"/\""); }
$lastSlash = strrpos($path, "/"); return substr($path, $lastSlash+1); }
/** * @internal * * @param string $argName * @param mixed $value * @throws \InvalidArgumentException */ static function checkArg($argName, $value) { if ($value === null) throw new \InvalidArgumentException("'$argName' must not be null"); if (!is_string($value)) throw new \InvalidArgumentException("'$argName' must be a string"); $error = self::findError($value); if ($error !== null) throw new \InvalidArgumentException("'$argName'': bad path: $error: ".var_export($value, true)); }
/** * @internal * * @param string $argName * @param mixed $value * @throws \InvalidArgumentException */ static function checkArgOrNull($argName, $value) { if ($value === null) return; self::checkArg($argName, $value); }
/** * @internal * * @param string $argName * @param mixed $value * @throws \InvalidArgumentException */ static function checkArgNonRoot($argName, $value) { if ($value === null) throw new \InvalidArgumentException("'$argName' must not be null"); if (!is_string($value)) throw new \InvalidArgumentException("'$argName' must be a string"); $error = self::findErrorNonRoot($value); if ($error !== null) throw new \InvalidArgumentException("'$argName'': bad path: $error: ".var_export($value, true)); } }
|