-
Notifications
You must be signed in to change notification settings - Fork 19
/
UrlBuilder.php
204 lines (163 loc) · 7.06 KB
/
UrlBuilder.php
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
<?php
namespace Imgix;
use Imgix\Validator;
class UrlBuilder {
private $currentVersion = "3.3.1";
private $domain;
private $useHttps;
private $signKey;
const TARGET_WIDTHS = array(
100, 116, 134, 156, 182, 210, 244, 282,
328, 380, 442, 512, 594, 688, 798, 926,
1074, 1246, 1446, 1678, 1946, 2258, 2618,
3038, 3524, 4088, 4742, 5500, 6380, 7400, 8192);
// define class constants
// should be private; but visibility modifiers are not supported php version <7.1
const TARGET_RATIOS = array(1, 2, 3, 4, 5);
const DPR_QUALITIES = array(1 => 75, 2 => 50, 3 => 35, 4 => 23, 5 => 20);
const MIN_WIDTH = 100;
const MAX_WIDTH = 8192;
const SRCSET_WIDTH_TOLERANCE = 0.08;
// constants cannot be dynamically assigned; keeping as a class variable instead
private $targetWidths;
public function __construct($domain, $useHttps = true, $signKey = "", $includeLibraryParam = true) {
if (!is_string($domain)) {
throw new \InvalidArgumentException("UrlBuilder must be passed a string domain");
}
$this->domain = $domain;
$this->validateDomain($this->domain);
$this->useHttps = $useHttps;
$this->signKey = $signKey;
$this->includeLibraryParam = $includeLibraryParam;
$this->targetWidths = $this->targetWidths();
}
private function validateDomain($domain) {
$DOMAIN_PATTERN = "/^(?:[a-z\d\-_]{1,62}\.){0,125}(?:[a-z\d](?:\-(?=\-*[a-z\d])|[a-z]|\d){0,62}\.)[a-z\d]{1,63}$/";
if(!preg_match($DOMAIN_PATTERN, $domain)) {
throw new \InvalidArgumentException('Domain must be passed in as fully-qualified ' .
'domain name and should not include a protocol or any path element, i.e. ' .
'"example.imgix.net".');
}
}
public function setSignKey($key) {
$this->signKey = $key;
}
public function setUseHttps($useHttps) {
$this->useHttps = $useHttps;
}
public function setIncludeLibraryParam($includeLibraryParam) {
$this->includeLibraryParam = $includeLibraryParam;
}
public function createURL($path, $params=array()) {
$scheme = $this->useHttps ? "https" : "http";
$domain = $this->domain;
if ($this->includeLibraryParam) {
$params['ixlib'] = "php-" . $this->currentVersion;
}
$uh = new UrlHelper($domain, $path, $scheme, $this->signKey, $params);
return $uh->getURL();
}
public function createSrcSet($path, $params=array(), $options=array()) {
$widthsArray = isset($options['widths']) ? $options['widths'] : NULL;
if (isset($widthsArray)) {
Validator::validateWidths($widthsArray);
return $this->createSrcSetPairs($path, $params=$params, $widthsArray);
}
$_start = isset($options['start']) ? $options['start'] : self::MIN_WIDTH;
$_stop = isset($options['stop']) ? $options['stop'] : self::MAX_WIDTH;
$_tol = isset($options['tol']) ? $options['tol'] : self::SRCSET_WIDTH_TOLERANCE;
$_disableVariableQuality = isset($options['disableVariableQuality'])
? $options['disableVariableQuality'] : false;
if ($this->isDpr($params)) {
return $this->createDPRSrcSet(
$path=$path,
$params=$params,
$disableVariableQuality=$_disableVariableQuality);
}
else {
$targets = $this->targetWidths($start=$_start, $stop=$_stop, $tol=$_tol);
return $this->createSrcSetPairs($path, $params=$params, $targets=$targets);
}
}
/**
* Generate a list of target widths.
*
* This function generates an array of target widths used to
* width-describe image candidate strings (URLs) within a
* srcset attribute.
*
* This function returns an array of integer values that denote
* image target widths. This array begins with `$start`
* and ends with `$stop`. The `$tol` or tolerance value dictates
* the amount of tolerable width variation between each width
* in the range of values that lie between `$start` and `$stop`.
*
* @param int $start Starting minimum width value.
* @param int $stop Stopping maximum width value.
* @param int $tol Tolerable amount of width variation.
* @return int[] $resolutions An array of integer values.
*/
public function targetWidths(
$start=self::MIN_WIDTH,
$stop=self::MAX_WIDTH,
$tol=self::SRCSET_WIDTH_TOLERANCE) {
if ($start == $stop) {
return array((int) $start);
}
Validator::validateMinMaxTol($start, $stop, $tol);
$resolutions = array();
while ($start < $stop && $start < self::MAX_WIDTH) {
array_push($resolutions, (int) round($start));
$start *= 1 + $tol * 2;
}
// The most recently appended value may, or may not, be
// the `stop` value. In order to be inclusive of the
// stop value, check for this case and add it, if necessary.
if (end($resolutions) < $stop) {
array_push($resolutions, (int) $stop);
}
return $resolutions;
}
private function isDpr($params) {
if (empty($params)) {
// If the params array is empty, then
// it is _not_ dpr based.
return false;
}
$hasWidth = array_key_exists('w', $params) ? $params['w'] : NULL;
$hasHeight = array_key_exists('h', $params) ? $params['h'] : NULL;
$hasAspectRatio = array_key_exists('ar', $params) ? $params['ar'] : NULL;
// If `params` have a width or height parameter then the
// srcset to be constructed with these params _is dpr based
return $hasWidth || $hasHeight;
}
private function createDPRSrcSet($path, $params, $disableVariableQuality=false) {
$srcset = "";
$size = count(self::TARGET_RATIOS);
for ($i = 0; $i < $size; $i++) {
$currentParams = $params;
$currentParams['dpr'] = $i+1;
$currentRatio = self::TARGET_RATIOS[$i];
// If variable quality output has been disabled _and_
// the `q` param _has not_ been passed:
if (!$disableVariableQuality && !isset($params["q"])) {
$currentParams["q"] = self::DPR_QUALITIES[$i + 1];
}
$srcset .= $this->createURL($path, $currentParams) . " " . $currentRatio . "x,\n";
}
return substr($srcset, 0, strlen($srcset) - 2);
}
private function createSrcSetPairs($path, $params, $targets=self::TARGET_WIDTHS) {
$srcset = "";
$currentWidth = NULL;
$currentParams = NULL;
$size = count($targets);
for ($i = 0; $i < $size; $i++) {
$currentWidth = $targets[$i];
$currentParams = $params;
$currentParams['w'] = $currentWidth;
$srcset .= $this->createURL($path, $currentParams) . " " . $currentWidth . "w,\n";
}
return substr($srcset, 0, strlen($srcset) - 2);
}
}