Passed
Push — v3 ( 432ffb...f9ff88 )
by Andrew
40:19 queued 27:54
created

UrlHelper   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Test Coverage

Coverage 13.1%

Importance

Changes 2
Bugs 2 Features 0
Metric Value
wmc 39
eloc 84
dl 0
loc 189
ccs 11
cts 84
cp 0.131
rs 9.28
c 2
b 2
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
C absoluteUrlWithProtocol() 0 40 14
A pageTriggerValue() 0 18 6
A siteUrl() 0 22 5
B encodeUrlQueryParams() 0 33 9
A decomposeUrl() 0 18 4
A urlHasSubDir() 0 3 1
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\helpers;
13
14
use Craft;
15
use craft\errors\SiteNotFoundException;
16
use craft\helpers\UrlHelper as CraftUrlHelper;
17
use nystudio107\seomatic\Seomatic;
18
use yii\base\Exception;
19
20
/**
21
 * @author    nystudio107
22
 * @package   Seomatic
23
 * @since     3.0.0
24
 */
25
class UrlHelper extends CraftUrlHelper
26
{
27
    // Public Static Properties
28
    // =========================================================================
29
30
    // Public Static Methods
31
    // =========================================================================
32
33
    /**
34
     * @inheritDoc
35
     */
36
    public static function siteUrl(string $path = '', $params = null, string $scheme = null, int $siteId = null): string
37
    {
38
        $siteUrl = Seomatic::$settings->siteUrlOverride;
39
        if (!empty($siteUrl)) {
40
            $siteUrl = MetaValue::parseString($siteUrl);
41
            // Extract out just the path part
42
            $parts = self::decomposeUrl($path);
43
            $path = $parts['path'] . $parts['suffix'];
44
            $url = rtrim($siteUrl, '/') . '/' . ltrim($path, '/');
45
            // Handle trailing slashes properly for generated URLs
46
            $generalConfig = Craft::$app->getConfig()->getGeneral();
47
            if ($generalConfig->addTrailingSlashesToUrls && !preg_match('/\.[^\/]+$/', $url)) {
48
                $url = rtrim($url, '/') . '/';
49
            }
50
            if (!$generalConfig->addTrailingSlashesToUrls) {
51
                $url = rtrim($url, '/');
52
            }
53
54
            return $url;
55
        }
56
57
        return DynamicMeta::sanitizeUrl(parent::siteUrl($path, $params, $scheme, $siteId), false, false);
58
    }
59
60
    /**
61
     * Return the page trigger and the value of the page trigger (null if it doesn't exist)
62
     *
63
     * @return array
64
     */
65
    public static function pageTriggerValue(): array
66
    {
67
        $pageTrigger = Craft::$app->getConfig()->getGeneral()->pageTrigger;
68
        if (!\is_string($pageTrigger) || $pageTrigger === '') {
69
            $pageTrigger = 'p';
70
        }
71
        // Is this query string-based pagination?
72
        if ($pageTrigger[0] === '?') {
73
            $pageTrigger = trim($pageTrigger, '?=');
74
        }
75
        // Avoid conflict with the path param
76
        $pathParam = Craft::$app->getConfig()->getGeneral()->pathParam;
77
        if ($pageTrigger === $pathParam) {
78
            $pageTrigger = $pathParam === 'p' ? 'pg' : 'p';
79
        }
80
        $pageTriggerValue = Craft::$app->getRequest()->getParam($pageTrigger);
81
82
        return [$pageTrigger, $pageTriggerValue];
83
    }
84
85
    /**
86
     * Return an absolute URL with protocol that curl will be happy with
87
     *
88
     * @param string $url
89
     *
90
     * @return string
91
     */
92
    public static function absoluteUrlWithProtocol($url): string
93
    {
94
        // Make this a full URL
95
        if (!self::isAbsoluteUrl($url)) {
96
            $protocol = 'http';
97
            if (isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (IssetNode && strcasecmp...PROTO'], 'https') === 0, Probably Intended Meaning: IssetNode && (strcasecmp...ROTO'], 'https') === 0)
Loading history...
98
                || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0
99
            ) {
100
                $protocol = 'https';
101
            }
102
            if (self::isProtocolRelativeUrl($url)) {
103
                try {
104
                    $url = self::urlWithScheme($url, $protocol);
105
                } catch (SiteNotFoundException $e) {
106
                    Craft::error($e->getMessage(), __METHOD__);
107
                }
108
            } else {
109
                try {
110
                    $url = self::siteUrl($url, null, $protocol);
111
                    if (self::isProtocolRelativeUrl($url)) {
112
                        $url = self::urlWithScheme($url, $protocol);
113
                    }
114
                } catch (Exception $e) {
115
                    Craft::error($e->getMessage(), __METHOD__);
116
                }
117
            }
118
        }
119
        // Ensure that any spaces in the URL are encoded
120
        $url = str_replace(' ', '%20', $url);
121
122
        // Handle trailing slashes properly for generated URLs
123
        $generalConfig = Craft::$app->getConfig()->getGeneral();
124
        if ($generalConfig->addTrailingSlashesToUrls && !preg_match('/\.[^\/]+$/', $url)) {
125
            $url = rtrim($url, '/') . '/';
126
        }
127
        if (!$generalConfig->addTrailingSlashesToUrls) {
128
            $url = rtrim($url, '/');
129
        }
130
131
        return DynamicMeta::sanitizeUrl($url, false, false);
132
    }
133
134
    /**
135
     * urlencode() just the query parameters in the URL
136
     *
137
     * @param string $url
138
     * @return string
139
     */
140 2
    public static function encodeUrlQueryParams(string $url): string
141
    {
142 2
        $urlParts = parse_url($url);
143 2
        $encodedUrl = "";
144 2
        if (isset($urlParts['scheme'])) {
145
            $encodedUrl .= $urlParts['scheme'] . '://';
146
        }
147 2
        if (isset($urlParts['host'])) {
148
            $encodedUrl .= $urlParts['host'];
149
        }
150 2
        if (isset($urlParts['port'])) {
151
            $encodedUrl .= ':' . $urlParts['port'];
152
        }
153 2
        if (isset($urlParts['path'])) {
154 2
            $encodedUrl .= $urlParts['path'];
155
        }
156 2
        if (isset($urlParts['query'])) {
157
            $query = explode('&', $urlParts['query']);
158
            foreach ($query as $j => $value) {
159
                $value = explode('=', $value, 2);
160
                if (count($value) === 2) {
161
                    $query[$j] = urlencode($value[0]) . '=' . urlencode($value[1]);
162
                } else {
163
                    $query[$j] = urlencode($value[0]);
164
                }
165
            }
166
            $encodedUrl .= '?' . implode('&', $query);
167
        }
168 2
        if (isset($urlParts['fragment'])) {
169
            $encodedUrl .= '#' . $urlParts['fragment'];
170
        }
171
172 2
        return $encodedUrl;
173
    }
174
175
    /**
176
     * Return whether this URL has a sub-directory as part of it
177
     *
178
     * @param string $url
179
     * @return bool
180
     */
181
    public static function urlHasSubDir(string $url): bool
182
    {
183
        return !empty(parse_url(trim($url, '/'), PHP_URL_PATH));
184
    }
185
186
    // Protected Methods
187
    // =========================================================================
188
189
    /**
190
     * Decompose a url into a prefix, path, and suffix
191
     *
192
     * @param $pathOrUrl
193
     *
194
     * @return array
195
     */
196
    protected static function decomposeUrl($pathOrUrl): array
197
    {
198
        $result = array();
199
200
        if (filter_var($pathOrUrl, FILTER_VALIDATE_URL)) {
201
            $url_parts = parse_url($pathOrUrl);
202
            $result['prefix'] = $url_parts['scheme'] . '://' . $url_parts['host'];
203
            $result['path'] = $url_parts['path'] ?? '';
204
            $result['suffix'] = '';
205
            $result['suffix'] .= empty($url_parts['query']) ? '' : '?' . $url_parts['query'];
206
            $result['suffix'] .= empty($url_parts['fragment']) ? '' : '#' . $url_parts['fragment'];
207
        } else {
208
            $result['prefix'] = '';
209
            $result['path'] = $pathOrUrl;
210
            $result['suffix'] = '';
211
        }
212
213
        return $result;
214
    }
215
}
216