Completed
Pull Request — master (#104)
by
unknown
03:04 queued 01:11
created

URLSanitisationService::removeStageParam()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\StaticPublishQueue\Service;
4
5
use SilverStripe\Core\Config\Configurable;
6
use SilverStripe\Core\Injector\Injectable;
7
8
/**
9
 * Class URLSanitisationService
10
 * Provides an abstraction for populating and generating a list of
11
 * URLs to be cached by StaticPublishQueue.
12
 *
13
 * @package SilverStripe\StaticPublishQueue\Service
14
 */
15
class URLSanitisationService
16
{
17
    use Configurable;
18
    use Injectable;
19
20
    /**
21
     * Enable to force all URLs to be changed to https
22
     *
23
     * @var bool
24
     * @config
25
     */
26
    private static $force_ssl = false;
0 ignored issues
show
introduced by
The private property $force_ssl is not used, and could be removed.
Loading history...
27
28
    /**
29
     * @var array
30
     */
31
    private $urls = [];
32
33
    /**
34
     * @var int
35
     */
36
    private $pointer = 0;
37
38
    /**
39
     * @param string $url
40
     */
41
    public function addURL(string $url): void
42
    {
43
        $url = $this->removeStageParam($url);
44
        $url = $this->enforceTrailingSlash($url);
45
        $url = $this->enforceSSL($url);
46
47
        // Check if this URL is already represented.
48
        if (array_key_exists($url, $this->urls)) {
49
            // Don't need to add it again if it is.
50
            return;
51
        }
52
53
        $this->urls[$url] = $this->pointer;
54
        $this->pointer += 1;
55
    }
56
57
    /**
58
     * @param array $urls
59
     */
60
    public function addURLs(array $urls): void
61
    {
62
        foreach ($urls as $url) {
63
            $this->addURL($url);
64
        }
65
    }
66
67
    /**
68
     * @return array
69
     */
70
    public function getURLs($formatted = false): array
71
    {
72
        if ($formatted) {
73
            return $this->urls;
74
        }
75
76
        return array_keys($this->urls);
77
    }
78
79
    /**
80
     * We never want to have stage=Stage present in our cached URLs. This will safely remove "stage" params, but
81
     * keep any others. It doesn't matter where in the string "stage=" exists.
82
     * this issue is caused by VersionedStateExtension::updateLink() which injects stage param into URLs
83
     * param injection happens when $readingMode !== get_default_reading_mode()
84
     * we can't enforce properly set reading modes while collecting URLs as the urlsToCache is an interface
85
     * while this doesn't seem to happen in majority cases, it's better to be 100% sure
86
     *
87
     * @param string $url
88
     * @return string
89
     */
90
    protected function removeStageParam(string $url): string
91
    {
92
        $url = preg_replace('/([?&])stage=[^&]+(&|$)/', '$1', $url);
93
94
        // Trim any trailing "?" or "&".
95
        $url = rtrim($url, '&');
96
        $url = rtrim($url, '?');
97
98
        return $url;
99
    }
100
101
    /**
102
     * Make sure we don't have multiple variations of the same URL (with and without trailing slash)
103
     *
104
     * @param string $url
105
     * @return string
106
     */
107
    protected function enforceTrailingSlash(string $url): string
108
    {
109
        $query = parse_url($url, PHP_URL_QUERY);
110
        $queryString = strlen($query) > 0
111
            ? '?' . $query
112
            : '';
113
114
        $url = str_replace('?' . $query, '', $url);
115
        $url = rtrim($url, '/') . '/';
116
117
        return $url . $queryString;
118
    }
119
120
    /**
121
     * Force SSL if needed
122
     *
123
     * @param string $url
124
     * @return string
125
     */
126
    protected function enforceSSL(string $url): string
127
    {
128
        $forceSSL = $this->getForceSSL();
129
        if (!$forceSSL) {
130
            return $url;
131
        }
132
133
        return str_replace('http://', 'https://', $url);
134
    }
135
136
    /**
137
     * Override this function if runtime change is needed (CMS setting or Environment variable)
138
     *
139
     * @return bool
140
     */
141
    protected function getForceSSL()
142
    {
143
        return (bool) $this->config()->get('force_ssl');
144
    }
145
}
146