Skip to content
This repository was archived by the owner on Nov 25, 2020. It is now read-only.

Commit 3f3513c

Browse files
committed
Use a dedicated mbParseUrl() function instead of parse_url that may fail with utf-8 on some specific installs (inc. macos)
1 parent d14c977 commit 3f3513c

File tree

10 files changed

+58
-19
lines changed

10 files changed

+58
-19
lines changed

core/src/core/src/pydio/Core/Utils/Vars/UrlUtils.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,38 @@
2929
*/
3030
class UrlUtils
3131
{
32+
/**
33+
* UTF8 support for parseUrl
34+
* @param $url
35+
* @return mixed
36+
*/
37+
public static function mbParseUrl($url, $part = -1){
38+
$enc_url = preg_replace_callback(
39+
'%[^:/@?&=#]+%usD',
40+
function ($matches)
41+
{
42+
return urlencode($matches[0]);
43+
},
44+
$url
45+
);
46+
47+
$parts = parse_url($enc_url, $part);
48+
49+
if($parts === false)
50+
{
51+
throw new \InvalidArgumentException('Malformed URL: ' . $url);
52+
}
53+
if($part !== -1){
54+
return urldecode($parts);
55+
}
56+
57+
foreach($parts as $name => $value)
58+
{
59+
$parts[$name] = urldecode($value);
60+
}
61+
62+
return $parts;
63+
}
3264

3365
/**
3466
* Parse URL ignoring # and ?
@@ -37,7 +69,7 @@ class UrlUtils
3769
*/
3870
public static function safeParseUrl($path)
3971
{
40-
$parts = parse_url(str_replace(array("#", "?"), array("__AJXP_FRAGMENT__", "__AJXP_MARK__"), $path));
72+
$parts = self::mbParseUrl(str_replace(array("#", "?"), array("__AJXP_FRAGMENT__", "__AJXP_MARK__"), $path));
4173
$parts["path"] = str_replace(array("__AJXP_FRAGMENT__", "__AJXP_MARK__"), array("#", "?"), $parts["path"]);
4274
return $parts;
4375
}

core/src/plugins/access.imap/ImapAccessDriver.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Pydio\Core\Exception\PydioException;
2929
use Pydio\Core\Model\ContextInterface;
3030
use Pydio\Core\Utils\Vars\StatHelper;
31+
use Pydio\Core\Utils\Vars\UrlUtils;
3132

3233
defined('AJXP_EXEC') or die( 'Access not allowed');
3334

@@ -107,7 +108,7 @@ public function enrichMetadata(&$ajxpNode)//, &$metadata, $wrapperClassName, &$r
107108
$currentNode = $ajxpNode->getUrl();
108109
$baseUrl = $ajxpNode->getContext()->getUrlBase();
109110
$metadata = $ajxpNode->metadata;
110-
$parsed = parse_url($currentNode);
111+
$parsed = UrlUtils::mbParseUrl($currentNode);
111112
if ( isSet($parsed["fragment"]) && strpos($parsed["fragment"], "attachments") === 0) {
112113
list(, $attachmentId) = explode("/", $parsed["fragment"]);
113114
$meta = ImapAccessWrapper::getCurrentAttachmentsMetadata();
@@ -144,7 +145,7 @@ public function enrichMetadata(&$ajxpNode)//, &$metadata, $wrapperClassName, &$r
144145
*/
145146
public function attachmentDLName($currentNode, &$localName, $wrapperClassName)
146147
{
147-
$parsed = parse_url($currentNode->getUrl());
148+
$parsed = UrlUtils::mbParseUrl($currentNode->getUrl());
148149
if ( isSet($parsed["fragment"]) && strpos($parsed["fragment"], "attachments") === 0) {
149150
list(, $attachmentId) = explode("/", $parsed["fragment"]);
150151
$meta = ImapAccessWrapper::getCurrentAttachmentsMetadata();

core/src/plugins/access.inbox/InboxAccessWrapper.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Pydio\Access\Core\IAjxpWrapper;
2727

2828
use Pydio\Core\Services\ApplicationState;
29+
use Pydio\Core\Utils\Vars\UrlUtils;
2930

3031
defined('AJXP_EXEC') or die('Access not allowed');
3132

@@ -180,7 +181,7 @@ public static function getRealFSReference($path, $persistent = false)
180181
$isRemote = MetaStreamWrapper::wrapperIsRemote($url);
181182
$realFilePointer = MetaStreamWrapper::getRealFSReference($url, true);
182183
if(!$isRemote){
183-
$ext = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION);
184+
$ext = pathinfo(UrlUtils::mbParseUrl($url, PHP_URL_PATH), PATHINFO_EXTENSION);
184185
$tmpname = tempnam(ApplicationState::getTemporaryFolder(), "real-file-inbox-pointer").".".$ext;
185186
copy($realFilePointer, $tmpname);
186187
$realFilePointer = $tmpname;

core/src/plugins/access.s3/S3AccessWrapper.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525

2626
use Pydio\Access\Driver\StreamProvider\FS\FsAccessWrapper;
2727
use Pydio\Core\Model\ContextInterface;
28-
use Pydio\Core\Services\ConfService;
2928
use Pydio\Core\Services\ApplicationState;
3029
use Pydio\Core\Utils\FileHelper;
30+
use Pydio\Core\Utils\Vars\UrlUtils;
3131
use Pydio\Log\Core\Logger;
3232

3333
defined('AJXP_EXEC') or die('Access not allowed');
@@ -126,7 +126,7 @@ protected static function getClientForContext(ContextInterface $ctx, $registerSt
126126
*/
127127
protected static function initPath($path, $streamType, $storeOpenContext = false, $skipZip = false)
128128
{
129-
$url = parse_url($path);
129+
$url = UrlUtils::mbParseUrl($path);
130130
$node = new AJXP_Node($path);
131131
$repoId = $node->getRepositoryId();
132132
$repoObject = $node->getRepository();
@@ -349,8 +349,8 @@ public function rename($from, $to)
349349
$s3Client = self::getClientForContext($node->getContext(), false);
350350
$bucket = $repoObject->getContextOption($ctx, "CONTAINER");
351351
$basePath = $repoObject->getContextOption($ctx, "PATH");
352-
$fromKeyname = trim(str_replace("//", "/", $basePath . parse_url($from, PHP_URL_PATH)), '/');
353-
$toKeyname = trim(str_replace("//", "/", $basePath . parse_url($to, PHP_URL_PATH)), '/');
352+
$fromKeyname = trim(str_replace("//", "/", $basePath . UrlUtils::mbParseUrl($from, PHP_URL_PATH)), '/');
353+
$toKeyname = trim(str_replace("//", "/", $basePath . UrlUtils::mbParseUrl($to, PHP_URL_PATH)), '/');
354354
if ($isViPR) {
355355
$toKeyname .= '/';
356356
$parts = explode('/', $bucket);

core/src/plugins/access.swift/SwiftAccessWrapper.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
use Pydio\Core\Services\ApplicationState;
2828
use Pydio\Core\Utils\FileHelper;
29+
use Pydio\Core\Utils\Vars\UrlUtils;
2930
use Pydio\Log\Core\Logger;
3031

3132
defined('AJXP_EXEC') or die( 'Access not allowed');
@@ -128,7 +129,7 @@ public function url_stat($path, $flags)
128129
// File and zip case
129130
// AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Stating $path");
130131

131-
$url = parse_url($path);
132+
$url = UrlUtils::mbParseUrl($path);
132133
if(empty($url["path"])){
133134
// This is root, return fake stat;
134135
return $this->fakeStat(true);
@@ -141,8 +142,7 @@ public function url_stat($path, $flags)
141142
if ($stat["mode"] == 0666) {
142143
$stat[2] = $stat["mode"] |= 0100000; // S_ISREG
143144
}
144-
$parsed = parse_url($path);
145-
if ($stat["mtime"] == $stat["ctime"] && $stat["ctime"] == $stat["atime"] && $stat["atime"] == 0 && $parsed["path"] != "/") {
145+
if ($stat["mtime"] == $stat["ctime"] && $stat["ctime"] == $stat["atime"] && $stat["atime"] == 0 && $url["path"] != "/") {
146146
//AJXP_Logger::debug(__CLASS__,__FUNCTION__,"Nullifying stats");
147147
return null;
148148
}

core/src/plugins/core.access/src/MetaStreamWrapper.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Pydio\Core\PluginFramework\PluginsService;
3232
use Pydio\Core\Services\RepositoryService;
3333
use Pydio\Core\Utils\Vars\PathUtils;
34+
use Pydio\Core\Utils\Vars\UrlUtils;
3435

3536
defined('AJXP_EXEC') or die('Access not allowed');
3637

@@ -153,7 +154,7 @@ protected static function getMetaWrappers($scheme) {
153154
* @throws \Exception
154155
*/
155156
protected static function getNextScheme($url, $context='core'){
156-
$parts = parse_url($url);
157+
$parts = UrlUtils::mbParseUrl($url);
157158
$metaWrapperKeys = array_keys(self::getMetaWrappers($context));
158159
$key = array_search($parts["scheme"], $metaWrapperKeys);
159160
if($key < count($metaWrapperKeys) - 1){
@@ -293,7 +294,7 @@ public static function actualRepositoryWrapperProtocol($node){
293294
* @param string $path
294295
*/
295296
public static function applyInitPathHook($path, $context = 'core') {
296-
$currentScheme = parse_url($path, PHP_URL_SCHEME);
297+
$currentScheme = UrlUtils::mbParseUrl($path, PHP_URL_SCHEME);
297298
$wrapper = self::findWrapperClassName(AJXP_Node::contextFromUrl($path), $currentScheme, $context);
298299

299300
if (is_callable(array($wrapper, "applyInitPathHook"))) {
@@ -418,7 +419,7 @@ public function dir_opendir($path, $options)
418419

419420
$this->handle = opendir($newPath);
420421
if($this->handle !== false){
421-
$this->currentDirPath = parse_url($path, PHP_URL_PATH);
422+
$this->currentDirPath = UrlUtils::mbParseUrl($path, PHP_URL_PATH);
422423
return true;
423424
}else{
424425
return false;

core/src/plugins/core.access/src/Model/AJXP_Node.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use Pydio\Core\Services\RepositoryService;
3838
use Pydio\Core\Utils\FileHelper;
3939
use Pydio\Access\Metastore\Core\IMetaStoreProvider;
40+
use Pydio\Core\Utils\Vars\UrlUtils;
4041

4142

4243
/**
@@ -766,12 +767,12 @@ protected function parseUrl()
766767
{
767768
if (strstr($this->_url, "#") !== false) {
768769
$url = str_replace("#", "__HASH__", $this->_url);
769-
$this->urlParts = parse_url($url);
770+
$this->urlParts = UrlUtils::mbParseUrl($url);
770771
foreach ($this->urlParts as $partKey => $partValue) {
771772
$this->urlParts[$partKey] = str_replace("__HASH__", "#", $partValue);
772773
}
773774
} else {
774-
$this->urlParts = parse_url($this->_url);
775+
$this->urlParts = UrlUtils::mbParseUrl($this->_url);
775776
}
776777
if(isSet($this->urlParts["user"])){
777778
$this->_user = $this->urlParts["user"];

core/src/plugins/core.tasks/src/Providers/SqlTasksProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Pydio\Access\Core\Model\AJXP_Node;
2424
use Pydio\Core\Model\RepositoryInterface;
2525
use Pydio\Core\Model\UserInterface;
26+
use Pydio\Core\Utils\Vars\UrlUtils;
2627
use Pydio\Log\Core\Logger;
2728
use Pydio\Tasks\ITasksProvider;
2829
use Pydio\Tasks\Schedule;
@@ -123,7 +124,7 @@ protected function insertOrUpdateNodes($task, $update = false){
123124
dibi::query("DELETE FROM [ajxp_tasks_nodes] WHERE [task_uid]=%s", $task->getId());
124125
}
125126
foreach($task->nodes as $nodeUrl){
126-
$nodePath = parse_url($nodeUrl, PHP_URL_PATH);
127+
$nodePath = UrlUtils::mbParseUrl($nodeUrl, PHP_URL_PATH);
127128
if(empty($nodePath)) $nodePath = "/";
128129
$nodeBaseUrl = preg_replace('/'. preg_quote($nodePath, '/') . '$/', "", $nodeUrl);
129130
$values = [

core/src/plugins/editor.eml/EmlParser.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
use Pydio\Core\PluginFramework\Plugin;
3939
use Pydio\Core\Utils\TextEncoder;
40+
use Pydio\Core\Utils\Vars\UrlUtils;
4041

4142
defined('AJXP_EXEC') or die( 'Access not allowed');
4243

@@ -241,7 +242,7 @@ public function extractMimeHeaders(&$ajxpNode, $isParent = false)
241242
if ($wrapperClassName == "imapAccessWrapper" && !$metadata["is_file"]) {
242243
$metadata["mimestring"] = "Mailbox";
243244
}
244-
$parsed = parse_url($currentNode);
245+
$parsed = UrlUtils::mbParseUrl($currentNode);
245246
if ( $noMail || ( isSet($parsed["fragment"]) && strpos($parsed["fragment"], "attachments") === 0 ) ) {
246247
EmlParser::$currentListingOnlyEmails = FALSE;
247248
return;

core/src/plugins/editor.pixlr/PixlrEditor.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Pydio\Core\PluginFramework\Plugin;
3636

3737
use GuzzleHttp\Client;
38+
use Pydio\Core\Utils\Vars\UrlUtils;
3839

3940
defined('AJXP_EXEC') or die( 'Access not allowed');
4041

@@ -145,7 +146,7 @@ public function switchAction(ServerRequestInterface &$request, ResponseInterface
145146
$this->logInfo('Edit', 'Retrieving content of '.$file.' from Pixlr server.', array("files" => $file));
146147
Controller::applyHook("node.before_change", array(&$selectedNode));
147148
$url = $httpVars["new_url"];
148-
$urlParts = parse_url($url);
149+
$urlParts = UrlUtils::mbParseUrl($url);
149150
$query = $urlParts["query"];
150151
if ($this->getContextualOption($ctx, "CHECK_SECURITY_TOKEN")) {
151152
$scriptName = basename($urlParts["path"]);

0 commit comments

Comments
 (0)