@@ -306,6 +306,9 @@ |
||
306 | 306 | |
307 | 307 | /** |
308 | 308 | * @see http://www.php.net/manual/en/function.str-pad.php#111147 |
309 | + * @param string $str |
|
310 | + * @param integer $padLen |
|
311 | + * @param integer $dir |
|
309 | 312 | */ |
310 | 313 | protected function _mbStrpad($str, $padLen, $padStr = ' ', $dir = STR_PAD_RIGHT) { |
311 | 314 | $strLen = mb_strlen($str); |
@@ -123,7 +123,7 @@ discard block |
||
123 | 123 | |
124 | 124 | // @todo should be done in Setting model |
125 | 125 | $ad = explode('|', $this->_sOptions['video_domains_allowed']); |
126 | - $trim = function ($v) { |
|
126 | + $trim = function($v) { |
|
127 | 127 | return trim($v); |
128 | 128 | }; |
129 | 129 | $this->_allowedVideoDomains = array_fill_keys(array_map($trim, $ad), 1); |
@@ -193,9 +193,9 @@ discard block |
||
193 | 193 | } |
194 | 194 | } |
195 | 195 | |
196 | - $out = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="' . $width . '" height="' . $height . '"> |
|
197 | - <param name="movie" value="' . $url . '"></param> |
|
198 | - <embed src="' . $url . '" width="' . $width . '" height="' . $height . '" type="application/x-shockwave-flash" wmode="opaque" style="width:' . $width . 'px; height:' . $height . 'px;" id="VideoPlayback" flashvars=""> </embed> </object>'; |
|
196 | + $out = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="'.$width.'" height="'.$height.'"> |
|
197 | + <param name="movie" value="' . $url.'"></param> |
|
198 | + <embed src="' . $url.'" width="'.$width.'" height="'.$height.'" type="application/x-shockwave-flash" wmode="opaque" style="width:'.$width.'px; height:'.$height.'px;" id="VideoPlayback" flashvars=""> </embed> </object>'; |
|
199 | 199 | return $out; |
200 | 200 | } |
201 | 201 | |
@@ -258,12 +258,12 @@ discard block |
||
258 | 258 | protected function _parse($content, $attributes) { |
259 | 259 | $listPieces = explode('[*]', $content); |
260 | 260 | unset($listPieces[0]); |
261 | - $listPieceProcessor = function ($li) { |
|
262 | - return '<li>' . $li . '</li>' . "\n"; |
|
261 | + $listPieceProcessor = function($li) { |
|
262 | + return '<li>'.$li.'</li>'."\n"; |
|
263 | 263 | }; |
264 | 264 | $listPieces = array_map($listPieceProcessor, $listPieces); |
265 | 265 | |
266 | - return '<ul>' . implode('', $listPieces) . '</ul>'; |
|
266 | + return '<ul>'.implode('', $listPieces).'</ul>'; |
|
267 | 267 | } |
268 | 268 | |
269 | 269 | } |
@@ -280,14 +280,14 @@ discard block |
||
280 | 280 | } |
281 | 281 | |
282 | 282 | $title = $this->_mbStrpad( |
283 | - ' ' . __('Spoiler') . ' ', |
|
283 | + ' '.__('Spoiler').' ', |
|
284 | 284 | $length, |
285 | 285 | '▇', |
286 | 286 | STR_PAD_BOTH |
287 | 287 | ); |
288 | 288 | |
289 | 289 | $json = json_encode(['string' => $content]); |
290 | - $id = 'spoiler_' . rand(0, 9999999999999); |
|
290 | + $id = 'spoiler_'.rand(0, 9999999999999); |
|
291 | 291 | |
292 | 292 | $out = <<<EOF |
293 | 293 | <div class="richtext-spoiler" style="display: inline;"> |
@@ -320,19 +320,19 @@ discard block |
||
320 | 320 | $result = null; |
321 | 321 | $repeat = ceil($strLen - $padStrLen + $padLen); |
322 | 322 | if ($dir == STR_PAD_RIGHT) { |
323 | - $result = $str . str_repeat($padStr, $repeat); |
|
323 | + $result = $str.str_repeat($padStr, $repeat); |
|
324 | 324 | $result = mb_substr($result, 0, $padLen); |
325 | 325 | } else { |
326 | 326 | if ($dir == STR_PAD_LEFT) { |
327 | - $result = str_repeat($padStr, $repeat) . $str; |
|
327 | + $result = str_repeat($padStr, $repeat).$str; |
|
328 | 328 | $result = mb_substr($result, -$padLen); |
329 | 329 | } else { |
330 | 330 | if ($dir == STR_PAD_BOTH) { |
331 | 331 | $length = ($padLen - $strLen) / 2; |
332 | 332 | $repeat = ceil($length / $padStrLen); |
333 | 333 | $result = mb_substr(str_repeat($padStr, $repeat), 0, |
334 | - floor($length)) . |
|
335 | - $str . |
|
334 | + floor($length)). |
|
335 | + $str. |
|
336 | 336 | mb_substr(str_repeat($padStr, $repeat), 0, ceil($length)); |
337 | 337 | } |
338 | 338 | } |
@@ -1,295 +1,295 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Plugin\BbcodeParser\Lib\jBBCode\Definitions; |
|
3 | + namespace Plugin\BbcodeParser\Lib\jBBCode\Definitions; |
|
4 | 4 | |
5 | - use Plugin\BbcodeParser\Lib\Helper\Message; |
|
6 | - use Plugin\BbcodeParser\Lib\Helper\UrlParserTrait; |
|
7 | - use Saito\DomainParser; |
|
5 | + use Plugin\BbcodeParser\Lib\Helper\Message; |
|
6 | + use Plugin\BbcodeParser\Lib\Helper\UrlParserTrait; |
|
7 | + use Saito\DomainParser; |
|
8 | 8 | |
9 | - include 'CodeDefinition.php'; |
|
10 | - include 'JbbHtml5MediaCodeDefinition.php'; |
|
11 | - include 'JbbCodeCodeDefinition.php'; |
|
9 | + include 'CodeDefinition.php'; |
|
10 | + include 'JbbHtml5MediaCodeDefinition.php'; |
|
11 | + include 'JbbCodeCodeDefinition.php'; |
|
12 | 12 | |
13 | - /** |
|
14 | - * Class Email handles [email][email protected][/email] |
|
15 | - * |
|
16 | - * @package Saito\Jbb\CodeDefinition |
|
17 | - */ |
|
18 | - class Email extends CodeDefinition { |
|
13 | + /** |
|
14 | + * Class Email handles [email][email protected][/email] |
|
15 | + * |
|
16 | + * @package Saito\Jbb\CodeDefinition |
|
17 | + */ |
|
18 | + class Email extends CodeDefinition { |
|
19 | 19 | |
20 | - use UrlParserTrait; |
|
20 | + use UrlParserTrait; |
|
21 | 21 | |
22 | - protected $_sParseContent = false; |
|
22 | + protected $_sParseContent = false; |
|
23 | 23 | |
24 | - protected $_sTagName = 'email'; |
|
24 | + protected $_sTagName = 'email'; |
|
25 | 25 | |
26 | - protected function _parse($url, $attributes) { |
|
27 | - return $this->_email($url); |
|
28 | - } |
|
26 | + protected function _parse($url, $attributes) { |
|
27 | + return $this->_email($url); |
|
28 | + } |
|
29 | 29 | |
30 | - } |
|
30 | + } |
|
31 | 31 | |
32 | - /** |
|
33 | - * Class EmailWithAttributes handles [[email protected]]foobar[/email] |
|
34 | - * |
|
35 | - * @package Saito\Jbb\CodeDefinition |
|
36 | - */ |
|
37 | - class EmailWithAttributes extends Email { |
|
32 | + /** |
|
33 | + * Class EmailWithAttributes handles [[email protected]]foobar[/email] |
|
34 | + * |
|
35 | + * @package Saito\Jbb\CodeDefinition |
|
36 | + */ |
|
37 | + class EmailWithAttributes extends Email { |
|
38 | 38 | |
39 | - protected $_sUseOptions = true; |
|
39 | + protected $_sUseOptions = true; |
|
40 | 40 | |
41 | - protected function _parse($content, $attributes) { |
|
42 | - return $this->_email($attributes['email'], $content); |
|
43 | - } |
|
41 | + protected function _parse($content, $attributes) { |
|
42 | + return $this->_email($attributes['email'], $content); |
|
43 | + } |
|
44 | 44 | |
45 | - } |
|
45 | + } |
|
46 | 46 | |
47 | 47 | |
48 | - class Embed extends CodeDefinition { |
|
48 | + class Embed extends CodeDefinition { |
|
49 | 49 | |
50 | - protected $_sTagName = 'embed'; |
|
50 | + protected $_sTagName = 'embed'; |
|
51 | 51 | |
52 | - protected $_sParseContent = false; |
|
52 | + protected $_sParseContent = false; |
|
53 | 53 | |
54 | - protected function _parse($content, $attributes) { |
|
55 | - if (empty($this->_sOptions['embedly_enabled'])) { |
|
56 | - return $this->_sHelper->Html->link($content, $content); |
|
57 | - } |
|
54 | + protected function _parse($content, $attributes) { |
|
55 | + if (empty($this->_sOptions['embedly_enabled'])) { |
|
56 | + return $this->_sHelper->Html->link($content, $content); |
|
57 | + } |
|
58 | 58 | |
59 | - $this->Embedly->setApiKey($this->_sOptions['embedly_key']); |
|
60 | - $embedly = $this->Embedly->embedly($content); |
|
61 | - if ($embedly !== false) { |
|
62 | - return $embedly; |
|
63 | - } |
|
59 | + $this->Embedly->setApiKey($this->_sOptions['embedly_key']); |
|
60 | + $embedly = $this->Embedly->embedly($content); |
|
61 | + if ($embedly !== false) { |
|
62 | + return $embedly; |
|
63 | + } |
|
64 | 64 | |
65 | - return __('Embedding failed.'); |
|
66 | - } |
|
65 | + return __('Embedding failed.'); |
|
66 | + } |
|
67 | 67 | |
68 | - } |
|
68 | + } |
|
69 | 69 | |
70 | - class Iframe extends CodeDefinition { |
|
70 | + class Iframe extends CodeDefinition { |
|
71 | 71 | |
72 | - protected $_sTagName = 'iframe'; |
|
72 | + protected $_sTagName = 'iframe'; |
|
73 | 73 | |
74 | - protected $_sParseContent = false; |
|
74 | + protected $_sParseContent = false; |
|
75 | 75 | |
76 | - protected $_sUseOptions = true; |
|
76 | + protected $_sUseOptions = true; |
|
77 | 77 | |
78 | - /** |
|
79 | - * Array with domains from which embedding video is allowed |
|
80 | - * |
|
81 | - * array( |
|
82 | - * 'youtube' => 1, |
|
83 | - * 'vimeo' => 1, |
|
84 | - * ); |
|
85 | - * |
|
86 | - * array('*' => 1) means every domain allowed |
|
87 | - * |
|
88 | - * @var array |
|
89 | - */ |
|
90 | - protected $_allowedVideoDomains = null; |
|
78 | + /** |
|
79 | + * Array with domains from which embedding video is allowed |
|
80 | + * |
|
81 | + * array( |
|
82 | + * 'youtube' => 1, |
|
83 | + * 'vimeo' => 1, |
|
84 | + * ); |
|
85 | + * |
|
86 | + * array('*' => 1) means every domain allowed |
|
87 | + * |
|
88 | + * @var array |
|
89 | + */ |
|
90 | + protected $_allowedVideoDomains = null; |
|
91 | 91 | |
92 | - protected function _parse($content, $attributes) { |
|
93 | - if (empty($attributes['src'])) { |
|
94 | - return false; |
|
95 | - } |
|
92 | + protected function _parse($content, $attributes) { |
|
93 | + if (empty($attributes['src'])) { |
|
94 | + return false; |
|
95 | + } |
|
96 | 96 | |
97 | - unset($attributes['iframe']); |
|
97 | + unset($attributes['iframe']); |
|
98 | 98 | |
99 | - $allowed = $this->_checkHostAllowed($attributes['src']); |
|
100 | - if ($allowed !== true) { |
|
101 | - return $allowed; |
|
102 | - } |
|
99 | + $allowed = $this->_checkHostAllowed($attributes['src']); |
|
100 | + if ($allowed !== true) { |
|
101 | + return $allowed; |
|
102 | + } |
|
103 | 103 | |
104 | - if (strpos($attributes['src'], '?') === false) { |
|
105 | - $attributes['src'] .= '?'; |
|
106 | - } |
|
107 | - // @todo @bogus unescaped & in html attribute? |
|
108 | - $attributes['src'] .= '&wmode=Opaque'; |
|
104 | + if (strpos($attributes['src'], '?') === false) { |
|
105 | + $attributes['src'] .= '?'; |
|
106 | + } |
|
107 | + // @todo @bogus unescaped & in html attribute? |
|
108 | + $attributes['src'] .= '&wmode=Opaque'; |
|
109 | 109 | |
110 | - $atrStr = ''; |
|
111 | - foreach ($attributes as $attributeName => $attributeValue) { |
|
112 | - $atrStr .= "$attributeName=\"$attributeValue\" "; |
|
113 | - } |
|
114 | - $atrStr = rtrim($atrStr); |
|
110 | + $atrStr = ''; |
|
111 | + foreach ($attributes as $attributeName => $attributeValue) { |
|
112 | + $atrStr .= "$attributeName=\"$attributeValue\" "; |
|
113 | + } |
|
114 | + $atrStr = rtrim($atrStr); |
|
115 | 115 | |
116 | - return "<iframe {$atrStr}></iframe>"; |
|
117 | - } |
|
116 | + return "<iframe {$atrStr}></iframe>"; |
|
117 | + } |
|
118 | 118 | |
119 | - protected function _allowedDomains() { |
|
120 | - if ($this->_allowedVideoDomains !== null) { |
|
121 | - return $this->_allowedVideoDomains; |
|
122 | - } |
|
119 | + protected function _allowedDomains() { |
|
120 | + if ($this->_allowedVideoDomains !== null) { |
|
121 | + return $this->_allowedVideoDomains; |
|
122 | + } |
|
123 | 123 | |
124 | - // @todo should be done in Setting model |
|
125 | - $ad = explode('|', $this->_sOptions['video_domains_allowed']); |
|
126 | - $trim = function ($v) { |
|
127 | - return trim($v); |
|
128 | - }; |
|
129 | - $this->_allowedVideoDomains = array_fill_keys(array_map($trim, $ad), 1); |
|
124 | + // @todo should be done in Setting model |
|
125 | + $ad = explode('|', $this->_sOptions['video_domains_allowed']); |
|
126 | + $trim = function ($v) { |
|
127 | + return trim($v); |
|
128 | + }; |
|
129 | + $this->_allowedVideoDomains = array_fill_keys(array_map($trim, $ad), 1); |
|
130 | 130 | |
131 | - return $this->_allowedVideoDomains; |
|
132 | - } |
|
133 | - |
|
134 | - protected function _checkHostAllowed($url) { |
|
135 | - $allowedDomains = $this->_allowedDomains(); |
|
136 | - if (empty($allowedDomains)) { |
|
137 | - return false; |
|
138 | - } |
|
131 | + return $this->_allowedVideoDomains; |
|
132 | + } |
|
133 | + |
|
134 | + protected function _checkHostAllowed($url) { |
|
135 | + $allowedDomains = $this->_allowedDomains(); |
|
136 | + if (empty($allowedDomains)) { |
|
137 | + return false; |
|
138 | + } |
|
139 | 139 | |
140 | - if ($allowedDomains === ['*' => 1]) { |
|
141 | - return true; |
|
142 | - } |
|
140 | + if ($allowedDomains === ['*' => 1]) { |
|
141 | + return true; |
|
142 | + } |
|
143 | 143 | |
144 | - $host = DomainParser::domain($url); |
|
145 | - if ($host && isset($allowedDomains[$host])) { |
|
146 | - return true; |
|
147 | - } |
|
148 | - |
|
149 | - $message = sprintf( |
|
150 | - __('Domain <strong>%s</strong> not allowed for embedding video.'), |
|
151 | - $host |
|
152 | - ); |
|
153 | - return Message::format($message); |
|
154 | - } |
|
155 | - |
|
156 | - } |
|
157 | - |
|
158 | - class Flash extends Iframe { |
|
159 | - |
|
160 | - protected $_sTagName = 'flash_video'; |
|
161 | - |
|
162 | - protected $_sParseContent = false; |
|
163 | - |
|
164 | - protected $_sUseOptions = false; |
|
165 | - |
|
166 | - protected static $_flashVideoDomainsWithHttps = [ |
|
167 | - 'vimeo' => 1, |
|
168 | - 'youtube' => 1 |
|
169 | - ]; |
|
170 | - |
|
171 | - protected function _parse($content, $attributes) { |
|
172 | - $match = preg_match( |
|
173 | - "#(?P<url>.+?)\|(?P<width>.+?)\|(?<height>\d+)#is", |
|
174 | - $content, |
|
175 | - $matches); |
|
176 | - if (!$match) { |
|
177 | - return Message::format(__('No Flash detected.')); |
|
178 | - } |
|
179 | - |
|
180 | - $height = $matches['height']; |
|
181 | - $url = $matches['url']; |
|
182 | - $width = $matches['width']; |
|
183 | - |
|
184 | - $allowed = $this->_checkHostAllowed($url); |
|
185 | - if ($allowed !== true) { |
|
186 | - return $allowed; |
|
187 | - } |
|
188 | - |
|
189 | - if (env('HTTPS')) { |
|
190 | - $host = DomainParser::domain($url); |
|
191 | - if (isset(self::$_flashVideoDomainsWithHttps[$host])) { |
|
192 | - $url = str_ireplace('http://', 'https://', $url); |
|
193 | - } |
|
194 | - } |
|
195 | - |
|
196 | - $out = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="' . $width . '" height="' . $height . '"> |
|
144 | + $host = DomainParser::domain($url); |
|
145 | + if ($host && isset($allowedDomains[$host])) { |
|
146 | + return true; |
|
147 | + } |
|
148 | + |
|
149 | + $message = sprintf( |
|
150 | + __('Domain <strong>%s</strong> not allowed for embedding video.'), |
|
151 | + $host |
|
152 | + ); |
|
153 | + return Message::format($message); |
|
154 | + } |
|
155 | + |
|
156 | + } |
|
157 | + |
|
158 | + class Flash extends Iframe { |
|
159 | + |
|
160 | + protected $_sTagName = 'flash_video'; |
|
161 | + |
|
162 | + protected $_sParseContent = false; |
|
163 | + |
|
164 | + protected $_sUseOptions = false; |
|
165 | + |
|
166 | + protected static $_flashVideoDomainsWithHttps = [ |
|
167 | + 'vimeo' => 1, |
|
168 | + 'youtube' => 1 |
|
169 | + ]; |
|
170 | + |
|
171 | + protected function _parse($content, $attributes) { |
|
172 | + $match = preg_match( |
|
173 | + "#(?P<url>.+?)\|(?P<width>.+?)\|(?<height>\d+)#is", |
|
174 | + $content, |
|
175 | + $matches); |
|
176 | + if (!$match) { |
|
177 | + return Message::format(__('No Flash detected.')); |
|
178 | + } |
|
179 | + |
|
180 | + $height = $matches['height']; |
|
181 | + $url = $matches['url']; |
|
182 | + $width = $matches['width']; |
|
183 | + |
|
184 | + $allowed = $this->_checkHostAllowed($url); |
|
185 | + if ($allowed !== true) { |
|
186 | + return $allowed; |
|
187 | + } |
|
188 | + |
|
189 | + if (env('HTTPS')) { |
|
190 | + $host = DomainParser::domain($url); |
|
191 | + if (isset(self::$_flashVideoDomainsWithHttps[$host])) { |
|
192 | + $url = str_ireplace('http://', 'https://', $url); |
|
193 | + } |
|
194 | + } |
|
195 | + |
|
196 | + $out = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="' . $width . '" height="' . $height . '"> |
|
197 | 197 | <param name="movie" value="' . $url . '"></param> |
198 | 198 | <embed src="' . $url . '" width="' . $width . '" height="' . $height . '" type="application/x-shockwave-flash" wmode="opaque" style="width:' . $width . 'px; height:' . $height . 'px;" id="VideoPlayback" flashvars=""> </embed> </object>'; |
199 | - return $out; |
|
200 | - } |
|
201 | - |
|
202 | - } |
|
203 | - |
|
204 | - class Image extends CodeDefinition { |
|
205 | - |
|
206 | - protected $_sTagName = 'img'; |
|
207 | - |
|
208 | - protected $_sParseContent = false; |
|
209 | - |
|
210 | - protected function _parse($url, $attributes) { |
|
211 | - // process [img=(parameters)] |
|
212 | - $options = []; |
|
213 | - if (!empty($attributes['img'])) { |
|
214 | - $default = trim($attributes['img']); |
|
215 | - switch ($default) { |
|
216 | - case 'left': |
|
217 | - $options['style'] = 'float: left;'; |
|
218 | - break; |
|
219 | - case 'right': |
|
220 | - $options['style'] = 'float: right;'; |
|
221 | - break; |
|
222 | - default: |
|
223 | - preg_match('/(\d{0,3})(?:x(\d{0,3}))?/i', $default, $dimension); |
|
224 | - // $dimension for [img=50] or [img=50x100] |
|
225 | - // [0] (50) or (50x100) |
|
226 | - // [1] (50) |
|
227 | - // [2] (100) |
|
228 | - if (!empty($dimension[1])) { |
|
229 | - $options['width'] = $dimension[1]; |
|
230 | - if (!empty($dimension[2])) { |
|
231 | - $options['height'] = $dimension[2]; |
|
232 | - } |
|
233 | - } |
|
234 | - } |
|
235 | - } |
|
236 | - |
|
237 | - return $this->Html->image($url, $options); |
|
238 | - } |
|
239 | - |
|
240 | - } |
|
241 | - |
|
242 | - class ImageWithAttributes extends Image { |
|
243 | - |
|
244 | - protected $_sUseOptions = true; |
|
245 | - |
|
246 | - } |
|
247 | - |
|
248 | - /** |
|
249 | - * Class UlList handles [list][*]…[/list] |
|
250 | - * |
|
251 | - * @see https://gist.github.com/jbowens/5646994 |
|
252 | - * @package Saito\Jbb\CodeDefinition |
|
253 | - */ |
|
254 | - class UlList extends CodeDefinition { |
|
255 | - |
|
256 | - protected $_sTagName = 'list'; |
|
257 | - |
|
258 | - protected function _parse($content, $attributes) { |
|
259 | - $listPieces = explode('[*]', $content); |
|
260 | - unset($listPieces[0]); |
|
261 | - $listPieceProcessor = function ($li) { |
|
262 | - return '<li>' . $li . '</li>' . "\n"; |
|
263 | - }; |
|
264 | - $listPieces = array_map($listPieceProcessor, $listPieces); |
|
265 | - |
|
266 | - return '<ul>' . implode('', $listPieces) . '</ul>'; |
|
267 | - } |
|
268 | - |
|
269 | - } |
|
270 | - |
|
271 | - class Spoiler extends CodeDefinition { |
|
272 | - |
|
273 | - protected $_sTagName = 'spoiler'; |
|
274 | - |
|
275 | - protected function _parse($content, $attributes) { |
|
276 | - $length = mb_strlen(strip_tags($content)); |
|
277 | - $minLenght = mb_strlen(__('Spoiler')) + 4; |
|
278 | - if ($length < $minLenght) { |
|
279 | - $length = $minLenght; |
|
280 | - } |
|
281 | - |
|
282 | - $title = $this->_mbStrpad( |
|
283 | - ' ' . __('Spoiler') . ' ', |
|
284 | - $length, |
|
285 | - '▇', |
|
286 | - STR_PAD_BOTH |
|
287 | - ); |
|
288 | - |
|
289 | - $json = json_encode(['string' => $content]); |
|
290 | - $id = 'spoiler_' . rand(0, 9999999999999); |
|
291 | - |
|
292 | - $out = <<<EOF |
|
199 | + return $out; |
|
200 | + } |
|
201 | + |
|
202 | + } |
|
203 | + |
|
204 | + class Image extends CodeDefinition { |
|
205 | + |
|
206 | + protected $_sTagName = 'img'; |
|
207 | + |
|
208 | + protected $_sParseContent = false; |
|
209 | + |
|
210 | + protected function _parse($url, $attributes) { |
|
211 | + // process [img=(parameters)] |
|
212 | + $options = []; |
|
213 | + if (!empty($attributes['img'])) { |
|
214 | + $default = trim($attributes['img']); |
|
215 | + switch ($default) { |
|
216 | + case 'left': |
|
217 | + $options['style'] = 'float: left;'; |
|
218 | + break; |
|
219 | + case 'right': |
|
220 | + $options['style'] = 'float: right;'; |
|
221 | + break; |
|
222 | + default: |
|
223 | + preg_match('/(\d{0,3})(?:x(\d{0,3}))?/i', $default, $dimension); |
|
224 | + // $dimension for [img=50] or [img=50x100] |
|
225 | + // [0] (50) or (50x100) |
|
226 | + // [1] (50) |
|
227 | + // [2] (100) |
|
228 | + if (!empty($dimension[1])) { |
|
229 | + $options['width'] = $dimension[1]; |
|
230 | + if (!empty($dimension[2])) { |
|
231 | + $options['height'] = $dimension[2]; |
|
232 | + } |
|
233 | + } |
|
234 | + } |
|
235 | + } |
|
236 | + |
|
237 | + return $this->Html->image($url, $options); |
|
238 | + } |
|
239 | + |
|
240 | + } |
|
241 | + |
|
242 | + class ImageWithAttributes extends Image { |
|
243 | + |
|
244 | + protected $_sUseOptions = true; |
|
245 | + |
|
246 | + } |
|
247 | + |
|
248 | + /** |
|
249 | + * Class UlList handles [list][*]…[/list] |
|
250 | + * |
|
251 | + * @see https://gist.github.com/jbowens/5646994 |
|
252 | + * @package Saito\Jbb\CodeDefinition |
|
253 | + */ |
|
254 | + class UlList extends CodeDefinition { |
|
255 | + |
|
256 | + protected $_sTagName = 'list'; |
|
257 | + |
|
258 | + protected function _parse($content, $attributes) { |
|
259 | + $listPieces = explode('[*]', $content); |
|
260 | + unset($listPieces[0]); |
|
261 | + $listPieceProcessor = function ($li) { |
|
262 | + return '<li>' . $li . '</li>' . "\n"; |
|
263 | + }; |
|
264 | + $listPieces = array_map($listPieceProcessor, $listPieces); |
|
265 | + |
|
266 | + return '<ul>' . implode('', $listPieces) . '</ul>'; |
|
267 | + } |
|
268 | + |
|
269 | + } |
|
270 | + |
|
271 | + class Spoiler extends CodeDefinition { |
|
272 | + |
|
273 | + protected $_sTagName = 'spoiler'; |
|
274 | + |
|
275 | + protected function _parse($content, $attributes) { |
|
276 | + $length = mb_strlen(strip_tags($content)); |
|
277 | + $minLenght = mb_strlen(__('Spoiler')) + 4; |
|
278 | + if ($length < $minLenght) { |
|
279 | + $length = $minLenght; |
|
280 | + } |
|
281 | + |
|
282 | + $title = $this->_mbStrpad( |
|
283 | + ' ' . __('Spoiler') . ' ', |
|
284 | + $length, |
|
285 | + '▇', |
|
286 | + STR_PAD_BOTH |
|
287 | + ); |
|
288 | + |
|
289 | + $json = json_encode(['string' => $content]); |
|
290 | + $id = 'spoiler_' . rand(0, 9999999999999); |
|
291 | + |
|
292 | + $out = <<<EOF |
|
293 | 293 | <div class="richtext-spoiler" style="display: inline;"> |
294 | 294 | <script> |
295 | 295 | window.$id = $json; |
@@ -301,153 +301,153 @@ discard block |
||
301 | 301 | </a> |
302 | 302 | </div> |
303 | 303 | EOF; |
304 | - return $out; |
|
305 | - } |
|
306 | - |
|
307 | - /** |
|
308 | - * @see http://www.php.net/manual/en/function.str-pad.php#111147 |
|
309 | - */ |
|
310 | - protected function _mbStrpad($str, $padLen, $padStr = ' ', $dir = STR_PAD_RIGHT) { |
|
311 | - $strLen = mb_strlen($str); |
|
312 | - $padStrLen = mb_strlen($padStr); |
|
313 | - if (!$strLen && ($dir == STR_PAD_RIGHT || $dir == STR_PAD_LEFT)) { |
|
314 | - $strLen = 1; // @debug |
|
315 | - } |
|
316 | - if (!$padLen || !$padStrLen || $padLen <= $strLen) { |
|
317 | - return $str; |
|
318 | - } |
|
319 | - |
|
320 | - $result = null; |
|
321 | - $repeat = ceil($strLen - $padStrLen + $padLen); |
|
322 | - if ($dir == STR_PAD_RIGHT) { |
|
323 | - $result = $str . str_repeat($padStr, $repeat); |
|
324 | - $result = mb_substr($result, 0, $padLen); |
|
325 | - } else { |
|
326 | - if ($dir == STR_PAD_LEFT) { |
|
327 | - $result = str_repeat($padStr, $repeat) . $str; |
|
328 | - $result = mb_substr($result, -$padLen); |
|
329 | - } else { |
|
330 | - if ($dir == STR_PAD_BOTH) { |
|
331 | - $length = ($padLen - $strLen) / 2; |
|
332 | - $repeat = ceil($length / $padStrLen); |
|
333 | - $result = mb_substr(str_repeat($padStr, $repeat), 0, |
|
334 | - floor($length)) . |
|
335 | - $str . |
|
336 | - mb_substr(str_repeat($padStr, $repeat), 0, ceil($length)); |
|
337 | - } |
|
338 | - } |
|
339 | - } |
|
340 | - |
|
341 | - return $result; |
|
342 | - } |
|
343 | - |
|
344 | - } |
|
345 | - |
|
346 | - class Upload extends CodeDefinition { |
|
347 | - |
|
348 | - protected $_sTagName = 'upload'; |
|
349 | - |
|
350 | - protected $_sParseContent = false; |
|
351 | - |
|
352 | - protected function _parse($content, $attributes) { |
|
353 | - $this->FileUpload->reset(); |
|
354 | - $params = $this->_getUploadParams($attributes); |
|
355 | - return $this->FileUpload->image($content, $params); |
|
356 | - } |
|
357 | - |
|
358 | - protected function _getUploadParams($attributes) { |
|
359 | - return []; |
|
360 | - } |
|
361 | - |
|
362 | - } |
|
363 | - |
|
364 | - class UploadWithAttributes extends Upload { |
|
365 | - |
|
366 | - protected $_sUseOptions = true; |
|
367 | - |
|
368 | - protected function _getUploadParams($attributes) { |
|
369 | - if (empty($attributes)) { |
|
370 | - return []; |
|
371 | - } |
|
372 | - |
|
373 | - $_allowedKeys = array_fill_keys(['width', 'height'], false); |
|
374 | - $_allowedAttributes = array_intersect_key($attributes, $_allowedKeys); |
|
375 | - $params = [ |
|
376 | - 'autoResize' => false, |
|
377 | - 'resizeThumbOnly' => false, |
|
378 | - ] + $_allowedAttributes; |
|
379 | - return $params; |
|
380 | - } |
|
381 | - |
|
382 | - } |
|
383 | - |
|
384 | - /** |
|
385 | - * Class Url handles [url]http://example.com[/url] |
|
386 | - * |
|
387 | - * @package Saito\Jbb\CodeDefinition |
|
388 | - */ |
|
389 | - class Url extends CodeDefinition { |
|
390 | - |
|
391 | - use UrlParserTrait; |
|
392 | - |
|
393 | - protected $_sParseContent = false; |
|
394 | - |
|
395 | - protected $_sTagName = 'url'; |
|
396 | - |
|
397 | - protected function _parse($url, $attributes) { |
|
398 | - $defaults = ['label' => true]; |
|
399 | - // parser may return $attributes = null |
|
400 | - if (empty($attributes)) { |
|
401 | - $attributes = []; |
|
402 | - } |
|
403 | - $attributes = $attributes + $defaults; |
|
404 | - return $this->_getUrl($url, $attributes); |
|
405 | - } |
|
406 | - |
|
407 | - protected function _getUrl($content, $attributes) { |
|
408 | - $shortTag = true; |
|
409 | - return $this->_url($content, $content, $attributes['label'], $shortTag); |
|
410 | - } |
|
411 | - |
|
412 | - } |
|
413 | - |
|
414 | - /** |
|
415 | - * Class Link handles [link]http://example.com[/link] |
|
416 | - * |
|
417 | - * @package Saito\Jbb\CodeDefinition |
|
418 | - */ |
|
419 | - class Link extends Url { |
|
420 | - |
|
421 | - protected $_sTagName = 'link'; |
|
422 | - |
|
423 | - } |
|
424 | - |
|
425 | - /** |
|
426 | - * Class UrlWithAttributes handles [url=http://example.com]foo[/url] |
|
427 | - * |
|
428 | - * @package Saito\Jbb\CodeDefinition |
|
429 | - */ |
|
430 | - class UrlWithAttributes extends Url { |
|
304 | + return $out; |
|
305 | + } |
|
306 | + |
|
307 | + /** |
|
308 | + * @see http://www.php.net/manual/en/function.str-pad.php#111147 |
|
309 | + */ |
|
310 | + protected function _mbStrpad($str, $padLen, $padStr = ' ', $dir = STR_PAD_RIGHT) { |
|
311 | + $strLen = mb_strlen($str); |
|
312 | + $padStrLen = mb_strlen($padStr); |
|
313 | + if (!$strLen && ($dir == STR_PAD_RIGHT || $dir == STR_PAD_LEFT)) { |
|
314 | + $strLen = 1; // @debug |
|
315 | + } |
|
316 | + if (!$padLen || !$padStrLen || $padLen <= $strLen) { |
|
317 | + return $str; |
|
318 | + } |
|
319 | + |
|
320 | + $result = null; |
|
321 | + $repeat = ceil($strLen - $padStrLen + $padLen); |
|
322 | + if ($dir == STR_PAD_RIGHT) { |
|
323 | + $result = $str . str_repeat($padStr, $repeat); |
|
324 | + $result = mb_substr($result, 0, $padLen); |
|
325 | + } else { |
|
326 | + if ($dir == STR_PAD_LEFT) { |
|
327 | + $result = str_repeat($padStr, $repeat) . $str; |
|
328 | + $result = mb_substr($result, -$padLen); |
|
329 | + } else { |
|
330 | + if ($dir == STR_PAD_BOTH) { |
|
331 | + $length = ($padLen - $strLen) / 2; |
|
332 | + $repeat = ceil($length / $padStrLen); |
|
333 | + $result = mb_substr(str_repeat($padStr, $repeat), 0, |
|
334 | + floor($length)) . |
|
335 | + $str . |
|
336 | + mb_substr(str_repeat($padStr, $repeat), 0, ceil($length)); |
|
337 | + } |
|
338 | + } |
|
339 | + } |
|
340 | + |
|
341 | + return $result; |
|
342 | + } |
|
343 | + |
|
344 | + } |
|
345 | + |
|
346 | + class Upload extends CodeDefinition { |
|
347 | + |
|
348 | + protected $_sTagName = 'upload'; |
|
349 | + |
|
350 | + protected $_sParseContent = false; |
|
351 | + |
|
352 | + protected function _parse($content, $attributes) { |
|
353 | + $this->FileUpload->reset(); |
|
354 | + $params = $this->_getUploadParams($attributes); |
|
355 | + return $this->FileUpload->image($content, $params); |
|
356 | + } |
|
357 | + |
|
358 | + protected function _getUploadParams($attributes) { |
|
359 | + return []; |
|
360 | + } |
|
361 | + |
|
362 | + } |
|
363 | + |
|
364 | + class UploadWithAttributes extends Upload { |
|
365 | + |
|
366 | + protected $_sUseOptions = true; |
|
367 | + |
|
368 | + protected function _getUploadParams($attributes) { |
|
369 | + if (empty($attributes)) { |
|
370 | + return []; |
|
371 | + } |
|
372 | + |
|
373 | + $_allowedKeys = array_fill_keys(['width', 'height'], false); |
|
374 | + $_allowedAttributes = array_intersect_key($attributes, $_allowedKeys); |
|
375 | + $params = [ |
|
376 | + 'autoResize' => false, |
|
377 | + 'resizeThumbOnly' => false, |
|
378 | + ] + $_allowedAttributes; |
|
379 | + return $params; |
|
380 | + } |
|
381 | + |
|
382 | + } |
|
383 | + |
|
384 | + /** |
|
385 | + * Class Url handles [url]http://example.com[/url] |
|
386 | + * |
|
387 | + * @package Saito\Jbb\CodeDefinition |
|
388 | + */ |
|
389 | + class Url extends CodeDefinition { |
|
390 | + |
|
391 | + use UrlParserTrait; |
|
392 | + |
|
393 | + protected $_sParseContent = false; |
|
394 | + |
|
395 | + protected $_sTagName = 'url'; |
|
396 | + |
|
397 | + protected function _parse($url, $attributes) { |
|
398 | + $defaults = ['label' => true]; |
|
399 | + // parser may return $attributes = null |
|
400 | + if (empty($attributes)) { |
|
401 | + $attributes = []; |
|
402 | + } |
|
403 | + $attributes = $attributes + $defaults; |
|
404 | + return $this->_getUrl($url, $attributes); |
|
405 | + } |
|
406 | + |
|
407 | + protected function _getUrl($content, $attributes) { |
|
408 | + $shortTag = true; |
|
409 | + return $this->_url($content, $content, $attributes['label'], $shortTag); |
|
410 | + } |
|
411 | + |
|
412 | + } |
|
413 | + |
|
414 | + /** |
|
415 | + * Class Link handles [link]http://example.com[/link] |
|
416 | + * |
|
417 | + * @package Saito\Jbb\CodeDefinition |
|
418 | + */ |
|
419 | + class Link extends Url { |
|
420 | + |
|
421 | + protected $_sTagName = 'link'; |
|
422 | + |
|
423 | + } |
|
424 | + |
|
425 | + /** |
|
426 | + * Class UrlWithAttributes handles [url=http://example.com]foo[/url] |
|
427 | + * |
|
428 | + * @package Saito\Jbb\CodeDefinition |
|
429 | + */ |
|
430 | + class UrlWithAttributes extends Url { |
|
431 | 431 | |
432 | - protected $_sParseContent = true; |
|
432 | + protected $_sParseContent = true; |
|
433 | 433 | |
434 | - protected $_sUseOptions = true; |
|
434 | + protected $_sUseOptions = true; |
|
435 | 435 | |
436 | - protected function _getUrl($content, $attributes) { |
|
437 | - $shortTag = false; |
|
438 | - $url = $attributes[$this->_sTagName]; |
|
439 | - return $this->_url($url, $content, $attributes['label'], $shortTag); |
|
440 | - } |
|
436 | + protected function _getUrl($content, $attributes) { |
|
437 | + $shortTag = false; |
|
438 | + $url = $attributes[$this->_sTagName]; |
|
439 | + return $this->_url($url, $content, $attributes['label'], $shortTag); |
|
440 | + } |
|
441 | 441 | |
442 | - } |
|
442 | + } |
|
443 | 443 | |
444 | - /** |
|
445 | - * Class LinkWithAttributes handles [link=http://example.com]foo[/link] |
|
446 | - * |
|
447 | - * @package Saito\Jbb\CodeDefinition |
|
448 | - */ |
|
449 | - class LinkWithAttributes extends UrlWithAttributes { |
|
444 | + /** |
|
445 | + * Class LinkWithAttributes handles [link=http://example.com]foo[/link] |
|
446 | + * |
|
447 | + * @package Saito\Jbb\CodeDefinition |
|
448 | + */ |
|
449 | + class LinkWithAttributes extends UrlWithAttributes { |
|
450 | 450 | |
451 | - protected $_sTagName = 'link'; |
|
451 | + protected $_sTagName = 'link'; |
|
452 | 452 | |
453 | - } |
|
453 | + } |
@@ -102,6 +102,9 @@ |
||
102 | 102 | return $this->_lastRuns; |
103 | 103 | } |
104 | 104 | |
105 | + /** |
|
106 | + * @param string $msg |
|
107 | + */ |
|
105 | 108 | protected function _log($msg) { |
106 | 109 | if (Configure::read('Saito.Globals.logInfo')) { |
107 | 110 | return CakeLog::write('saito.info', $msg); |
@@ -61,7 +61,7 @@ |
||
61 | 61 | } |
62 | 62 | $jobsExecuted++; |
63 | 63 | $job->execute(); |
64 | - $this->_log('Run cron-job ' . $job->uid); |
|
64 | + $this->_log('Run cron-job '.$job->uid); |
|
65 | 65 | $this->_lastRuns[$job->due][$job->uid] = $this->_now; |
66 | 66 | } |
67 | 67 | if ($jobsExecuted === 0) { |
@@ -1,111 +1,111 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - App::uses('CronJob', 'Cron.Lib'); |
|
4 | - App::uses('CakeLog', 'Log'); |
|
5 | - |
|
6 | - class Cron { |
|
7 | - |
|
8 | - private static $__instance = null; |
|
9 | - |
|
10 | - protected $_jobs = []; |
|
11 | - |
|
12 | - protected $_lastRuns = null; |
|
13 | - |
|
14 | - protected $_now; |
|
15 | - |
|
16 | - /** |
|
17 | - * defines time intervals in seconds |
|
18 | - * |
|
19 | - * @var array |
|
20 | - */ |
|
21 | - protected $_dues = [ |
|
22 | - // a little shorter than a Cake's default cache-config invalidation hour |
|
23 | - 'hourly' => 3300, |
|
24 | - // if no cron job was triggered in one hour then Cake's default cache file is |
|
25 | - // invalidated and hourly is also triggered |
|
26 | - 'daily' => 86400 |
|
27 | - ]; |
|
28 | - |
|
29 | - protected function __construct() { |
|
30 | - $this->_now = time(); |
|
31 | - } |
|
32 | - |
|
33 | - protected function __clone() { |
|
34 | - } |
|
35 | - |
|
36 | - public static function getInstance() { |
|
37 | - if (self::$__instance === null) { |
|
38 | - $name = get_called_class(); |
|
39 | - self::$__instance = new $name; |
|
40 | - } |
|
41 | - return self::$__instance; |
|
42 | - } |
|
43 | - |
|
44 | - public function addCronJob($id, $due, callable $func) { |
|
45 | - $this->_jobs[$id] = new CronJob($id, $due, $func); |
|
46 | - } |
|
47 | - |
|
48 | - public function execute() { |
|
49 | - $lastRuns = $this->_getLastRuns(); |
|
50 | - $jobsExecuted = 0; |
|
51 | - foreach ($this->_jobs as $job) { |
|
52 | - if (!empty($lastRuns[$job->due][$job->uid])) { |
|
53 | - if (isset($this->_dues[$job->due])) { |
|
54 | - $due = $lastRuns[$job->due][$job->uid] + $this->_dues[$job->due]; |
|
55 | - } else { |
|
56 | - $due = strtotime($job->due, $lastRuns[$job->due][$job->uid]); |
|
57 | - } |
|
58 | - if ($this->_now < $due) { |
|
59 | - continue; |
|
60 | - } |
|
61 | - } |
|
62 | - $jobsExecuted++; |
|
63 | - $job->execute(); |
|
64 | - $this->_log('Run cron-job ' . $job->uid); |
|
65 | - $this->_lastRuns[$job->due][$job->uid] = $this->_now; |
|
66 | - } |
|
67 | - if ($jobsExecuted === 0) { |
|
68 | - return; |
|
69 | - } |
|
70 | - Cache::write('Plugin.Cron.lastRuns', $this->_lastRuns); |
|
71 | - } |
|
72 | - |
|
73 | - public function clearHistory() { |
|
74 | - $this->_lastRuns = []; |
|
75 | - $this->_now = time(); |
|
76 | - Cache::write('Plugin.Cron.lastRuns', $this->_getNewCacheData()); |
|
77 | - } |
|
78 | - |
|
79 | - protected function _getNewCacheData() { |
|
80 | - return ['meta' => ['lastDailyReset' => $this->_now]]; |
|
81 | - } |
|
82 | - |
|
83 | - protected function _getLastRuns() { |
|
84 | - if ($this->_lastRuns) { |
|
85 | - return $this->_lastRuns; |
|
86 | - } |
|
87 | - $cache = Cache::read('Plugin.Cron.lastRuns'); |
|
88 | - |
|
89 | - if (// cache file is not created yet |
|
90 | - !isset($cache['meta']['lastDailyReset']) || |
|
91 | - // cache is outdated |
|
92 | - $cache['meta']['lastDailyReset'] + $this->_dues['daily'] < $this->_now |
|
93 | - ) { |
|
94 | - $cache = $this->_getNewCacheData(); |
|
95 | - // This request may trigger many jobs and take some time. |
|
96 | - // Update cache immediately and not after all jobs are done (at the |
|
97 | - // end of this request), so that following requests arriving in that |
|
98 | - // time-frame don't assume they have to run the same jobs too. |
|
99 | - Cache::write('Plugin.Cron.lastRuns', $cache); |
|
100 | - } |
|
101 | - $this->_lastRuns = $cache; |
|
102 | - return $this->_lastRuns; |
|
103 | - } |
|
104 | - |
|
105 | - protected function _log($msg) { |
|
106 | - if (Configure::read('Saito.Globals.logInfo')) { |
|
107 | - return CakeLog::write('saito.info', $msg); |
|
108 | - } |
|
109 | - } |
|
110 | - |
|
111 | - } |
|
3 | + App::uses('CronJob', 'Cron.Lib'); |
|
4 | + App::uses('CakeLog', 'Log'); |
|
5 | + |
|
6 | + class Cron { |
|
7 | + |
|
8 | + private static $__instance = null; |
|
9 | + |
|
10 | + protected $_jobs = []; |
|
11 | + |
|
12 | + protected $_lastRuns = null; |
|
13 | + |
|
14 | + protected $_now; |
|
15 | + |
|
16 | + /** |
|
17 | + * defines time intervals in seconds |
|
18 | + * |
|
19 | + * @var array |
|
20 | + */ |
|
21 | + protected $_dues = [ |
|
22 | + // a little shorter than a Cake's default cache-config invalidation hour |
|
23 | + 'hourly' => 3300, |
|
24 | + // if no cron job was triggered in one hour then Cake's default cache file is |
|
25 | + // invalidated and hourly is also triggered |
|
26 | + 'daily' => 86400 |
|
27 | + ]; |
|
28 | + |
|
29 | + protected function __construct() { |
|
30 | + $this->_now = time(); |
|
31 | + } |
|
32 | + |
|
33 | + protected function __clone() { |
|
34 | + } |
|
35 | + |
|
36 | + public static function getInstance() { |
|
37 | + if (self::$__instance === null) { |
|
38 | + $name = get_called_class(); |
|
39 | + self::$__instance = new $name; |
|
40 | + } |
|
41 | + return self::$__instance; |
|
42 | + } |
|
43 | + |
|
44 | + public function addCronJob($id, $due, callable $func) { |
|
45 | + $this->_jobs[$id] = new CronJob($id, $due, $func); |
|
46 | + } |
|
47 | + |
|
48 | + public function execute() { |
|
49 | + $lastRuns = $this->_getLastRuns(); |
|
50 | + $jobsExecuted = 0; |
|
51 | + foreach ($this->_jobs as $job) { |
|
52 | + if (!empty($lastRuns[$job->due][$job->uid])) { |
|
53 | + if (isset($this->_dues[$job->due])) { |
|
54 | + $due = $lastRuns[$job->due][$job->uid] + $this->_dues[$job->due]; |
|
55 | + } else { |
|
56 | + $due = strtotime($job->due, $lastRuns[$job->due][$job->uid]); |
|
57 | + } |
|
58 | + if ($this->_now < $due) { |
|
59 | + continue; |
|
60 | + } |
|
61 | + } |
|
62 | + $jobsExecuted++; |
|
63 | + $job->execute(); |
|
64 | + $this->_log('Run cron-job ' . $job->uid); |
|
65 | + $this->_lastRuns[$job->due][$job->uid] = $this->_now; |
|
66 | + } |
|
67 | + if ($jobsExecuted === 0) { |
|
68 | + return; |
|
69 | + } |
|
70 | + Cache::write('Plugin.Cron.lastRuns', $this->_lastRuns); |
|
71 | + } |
|
72 | + |
|
73 | + public function clearHistory() { |
|
74 | + $this->_lastRuns = []; |
|
75 | + $this->_now = time(); |
|
76 | + Cache::write('Plugin.Cron.lastRuns', $this->_getNewCacheData()); |
|
77 | + } |
|
78 | + |
|
79 | + protected function _getNewCacheData() { |
|
80 | + return ['meta' => ['lastDailyReset' => $this->_now]]; |
|
81 | + } |
|
82 | + |
|
83 | + protected function _getLastRuns() { |
|
84 | + if ($this->_lastRuns) { |
|
85 | + return $this->_lastRuns; |
|
86 | + } |
|
87 | + $cache = Cache::read('Plugin.Cron.lastRuns'); |
|
88 | + |
|
89 | + if (// cache file is not created yet |
|
90 | + !isset($cache['meta']['lastDailyReset']) || |
|
91 | + // cache is outdated |
|
92 | + $cache['meta']['lastDailyReset'] + $this->_dues['daily'] < $this->_now |
|
93 | + ) { |
|
94 | + $cache = $this->_getNewCacheData(); |
|
95 | + // This request may trigger many jobs and take some time. |
|
96 | + // Update cache immediately and not after all jobs are done (at the |
|
97 | + // end of this request), so that following requests arriving in that |
|
98 | + // time-frame don't assume they have to run the same jobs too. |
|
99 | + Cache::write('Plugin.Cron.lastRuns', $cache); |
|
100 | + } |
|
101 | + $this->_lastRuns = $cache; |
|
102 | + return $this->_lastRuns; |
|
103 | + } |
|
104 | + |
|
105 | + protected function _log($msg) { |
|
106 | + if (Configure::read('Saito.Globals.logInfo')) { |
|
107 | + return CakeLog::write('saito.info', $msg); |
|
108 | + } |
|
109 | + } |
|
110 | + |
|
111 | + } |
@@ -30,6 +30,9 @@ |
||
30 | 30 | return $this->_schema; |
31 | 31 | } |
32 | 32 | |
33 | + /** |
|
34 | + * @param string $key |
|
35 | + */ |
|
33 | 36 | public function resolveKey(Model $model, $key) { |
34 | 37 | if (strpos('.', $key) === false) { |
35 | 38 | return $model->alias . '.' . $key; |
@@ -32,7 +32,7 @@ discard block |
||
32 | 32 | |
33 | 33 | public function resolveKey(Model $model, $key) { |
34 | 34 | if (strpos('.', $key) === false) { |
35 | - return $model->alias . '.' . $key; |
|
35 | + return $model->alias.'.'.$key; |
|
36 | 36 | } |
37 | 37 | return $key; |
38 | 38 | } |
@@ -60,9 +60,9 @@ discard block |
||
60 | 60 | if ($plugin) { |
61 | 61 | $folderPath = CakePlugin::path($plugin); |
62 | 62 | } else { |
63 | - $folderPath = ROOT . DS; |
|
63 | + $folderPath = ROOT.DS; |
|
64 | 64 | } |
65 | - $folderPath .= 'docs' . DS . 'help' . DS . $lang; |
|
65 | + $folderPath .= 'docs'.DS.'help'.DS.$lang; |
|
66 | 66 | |
67 | 67 | $folder = new Folder($folderPath); |
68 | 68 | $files = $folder->find("$id(-.*?)?\.md"); |
@@ -70,7 +70,7 @@ discard block |
||
70 | 70 | return false; |
71 | 71 | } |
72 | 72 | $name = $files[0]; |
73 | - $file = new File($folderPath . DS . $name, false, 0444); |
|
73 | + $file = new File($folderPath.DS.$name, false, 0444); |
|
74 | 74 | $text = $file->read(); |
75 | 75 | $file->close(); |
76 | 76 | $result = [ |
@@ -1,90 +1,90 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - App::uses('DataSource', 'Model/Datasource'); |
|
4 | - App::uses('File', 'Utility'); |
|
5 | - App::uses('Folder', 'Utility'); |
|
3 | + App::uses('DataSource', 'Model/Datasource'); |
|
4 | + App::uses('File', 'Utility'); |
|
5 | + App::uses('Folder', 'Utility'); |
|
6 | 6 | |
7 | - class SaitoHelpSource extends DataSource { |
|
7 | + class SaitoHelpSource extends DataSource { |
|
8 | 8 | |
9 | - protected $_schema = [ |
|
10 | - 'id' => [ |
|
11 | - 'type' => 'string', |
|
12 | - 'null' => false, |
|
13 | - 'key' => 'primary', |
|
14 | - 'length' => 255 |
|
15 | - ], |
|
16 | - 'text' => [ |
|
17 | - 'type' => 'text', |
|
18 | - ] |
|
19 | - ]; |
|
9 | + protected $_schema = [ |
|
10 | + 'id' => [ |
|
11 | + 'type' => 'string', |
|
12 | + 'null' => false, |
|
13 | + 'key' => 'primary', |
|
14 | + 'length' => 255 |
|
15 | + ], |
|
16 | + 'text' => [ |
|
17 | + 'type' => 'text', |
|
18 | + ] |
|
19 | + ]; |
|
20 | 20 | |
21 | - public function calculate($model, $func, $params) { |
|
22 | - return 'COUNT'; |
|
23 | - } |
|
21 | + public function calculate($model, $func, $params) { |
|
22 | + return 'COUNT'; |
|
23 | + } |
|
24 | 24 | |
25 | - public function listSources($data = null) { |
|
26 | - return null; |
|
27 | - } |
|
25 | + public function listSources($data = null) { |
|
26 | + return null; |
|
27 | + } |
|
28 | 28 | |
29 | - public function describe($model) { |
|
30 | - return $this->_schema; |
|
31 | - } |
|
29 | + public function describe($model) { |
|
30 | + return $this->_schema; |
|
31 | + } |
|
32 | 32 | |
33 | - public function resolveKey(Model $model, $key) { |
|
34 | - if (strpos('.', $key) === false) { |
|
35 | - return $model->alias . '.' . $key; |
|
36 | - } |
|
37 | - return $key; |
|
38 | - } |
|
33 | + public function resolveKey(Model $model, $key) { |
|
34 | + if (strpos('.', $key) === false) { |
|
35 | + return $model->alias . '.' . $key; |
|
36 | + } |
|
37 | + return $key; |
|
38 | + } |
|
39 | 39 | |
40 | - public function read(Model $model, $queryData = [], $recursive = null) { |
|
41 | - // normalize conditions to `Model.field` |
|
42 | - if ($queryData['conditions']) { |
|
43 | - foreach ($queryData['conditions'] as $key => $value) { |
|
44 | - if (is_string($key)) { |
|
45 | - $queryData['conditions'][$this->resolveKey($model, $key)] = $value; |
|
46 | - unset($queryData['conditions'][$key]); |
|
47 | - } |
|
48 | - } |
|
49 | - } |
|
40 | + public function read(Model $model, $queryData = [], $recursive = null) { |
|
41 | + // normalize conditions to `Model.field` |
|
42 | + if ($queryData['conditions']) { |
|
43 | + foreach ($queryData['conditions'] as $key => $value) { |
|
44 | + if (is_string($key)) { |
|
45 | + $queryData['conditions'][$this->resolveKey($model, $key)] = $value; |
|
46 | + unset($queryData['conditions'][$key]); |
|
47 | + } |
|
48 | + } |
|
49 | + } |
|
50 | 50 | |
51 | - $queryData['conditions'] += [ |
|
52 | - $this->resolveKey($model, 'language') => 'eng' |
|
53 | - ]; |
|
51 | + $queryData['conditions'] += [ |
|
52 | + $this->resolveKey($model, 'language') => 'eng' |
|
53 | + ]; |
|
54 | 54 | |
55 | - $id = $queryData['conditions'][$this->resolveKey($model, 'id')]; |
|
56 | - list($plugin, $id) = pluginSplit($id); |
|
55 | + $id = $queryData['conditions'][$this->resolveKey($model, 'id')]; |
|
56 | + list($plugin, $id) = pluginSplit($id); |
|
57 | 57 | |
58 | - $lang = $queryData['conditions'][$this->resolveKey($model, 'language')]; |
|
58 | + $lang = $queryData['conditions'][$this->resolveKey($model, 'language')]; |
|
59 | 59 | |
60 | - if ($plugin) { |
|
61 | - $folderPath = CakePlugin::path($plugin); |
|
62 | - } else { |
|
63 | - $folderPath = ROOT . DS; |
|
64 | - } |
|
65 | - $folderPath .= 'docs' . DS . 'help' . DS . $lang; |
|
60 | + if ($plugin) { |
|
61 | + $folderPath = CakePlugin::path($plugin); |
|
62 | + } else { |
|
63 | + $folderPath = ROOT . DS; |
|
64 | + } |
|
65 | + $folderPath .= 'docs' . DS . 'help' . DS . $lang; |
|
66 | 66 | |
67 | - $folder = new Folder($folderPath); |
|
68 | - $files = $folder->find("$id(-.*?)?\.md"); |
|
69 | - if (!$files) { |
|
70 | - return false; |
|
71 | - } |
|
72 | - $name = $files[0]; |
|
73 | - $file = new File($folderPath . DS . $name, false, 0444); |
|
74 | - $text = $file->read(); |
|
75 | - $file->close(); |
|
76 | - $result = [ |
|
77 | - $model->alias => [ |
|
78 | - 'file' => $name, |
|
79 | - 'id' => $id, |
|
80 | - 'lang' => $lang, |
|
81 | - 'text' => $text |
|
82 | - ] |
|
83 | - ]; |
|
84 | - if (!empty($queryData['limit'])) { |
|
85 | - $result = [0 => $result]; |
|
86 | - } |
|
87 | - return $result; |
|
88 | - } |
|
67 | + $folder = new Folder($folderPath); |
|
68 | + $files = $folder->find("$id(-.*?)?\.md"); |
|
69 | + if (!$files) { |
|
70 | + return false; |
|
71 | + } |
|
72 | + $name = $files[0]; |
|
73 | + $file = new File($folderPath . DS . $name, false, 0444); |
|
74 | + $text = $file->read(); |
|
75 | + $file->close(); |
|
76 | + $result = [ |
|
77 | + $model->alias => [ |
|
78 | + 'file' => $name, |
|
79 | + 'id' => $id, |
|
80 | + 'lang' => $lang, |
|
81 | + 'text' => $text |
|
82 | + ] |
|
83 | + ]; |
|
84 | + if (!empty($queryData['limit'])) { |
|
85 | + $result = [0 => $result]; |
|
86 | + } |
|
87 | + return $result; |
|
88 | + } |
|
89 | 89 | |
90 | - } |
|
91 | 90 | \ No newline at end of file |
91 | + } |
|
92 | 92 | \ No newline at end of file |
@@ -37,7 +37,7 @@ discard block |
||
37 | 37 | /** |
38 | 38 | * Setup instance |
39 | 39 | * |
40 | - * @param type $Model |
|
40 | + * @param Model $Model |
|
41 | 41 | * @param type $settings |
42 | 42 | */ |
43 | 43 | public function setup(Model $Model, $settings = array()) { |
@@ -183,6 +183,8 @@ discard block |
||
183 | 183 | /** |
184 | 184 | * build and log error message |
185 | 185 | * 2009-12-18 ms |
186 | + * @param string $msg |
|
187 | + * @param string $internalMsg |
|
186 | 188 | */ |
187 | 189 | private function error($msg = null, $internalMsg = null) { |
188 | 190 | if (!empty($msg)) { |
@@ -91,7 +91,7 @@ discard block |
||
91 | 91 | $dummyField = $this->settings[$this->Model->alias]['dummyField']; |
92 | 92 | if (!empty($data[$dummyField])) { |
93 | 93 | # dummy field not empty - SPAM! |
94 | - return $this->error('Illegal content', 'DummyField = \'' . $data[$dummyField] . '\''); |
|
94 | + return $this->error('Illegal content', 'DummyField = \''.$data[$dummyField].'\''); |
|
95 | 95 | } |
96 | 96 | return true; |
97 | 97 | } |
@@ -108,7 +108,7 @@ discard block |
||
108 | 108 | } |
109 | 109 | |
110 | 110 | if (isSet($data['captcha_hash']) && isSet($data['captcha_time']) |
111 | - && ( $data['captcha_time'] < time() - $this->settings[$this->Model->alias]['minTime'] ) |
|
111 | + && ($data['captcha_time'] < time() - $this->settings[$this->Model->alias]['minTime']) |
|
112 | 112 | ) { |
113 | 113 | return true; |
114 | 114 | } |
@@ -127,7 +127,7 @@ discard block |
||
127 | 127 | return true; |
128 | 128 | } |
129 | 129 | if (isSet($data['captcha_hash']) && isSet($data['captcha_time']) |
130 | - && ( $data['captcha_time'] + $this->settings[$this->Model->alias]['maxTime'] > time() ) |
|
130 | + && ($data['captcha_time'] + $this->settings[$this->Model->alias]['maxTime'] > time()) |
|
131 | 131 | ) { |
132 | 132 | return true; |
133 | 133 | } |
@@ -161,7 +161,7 @@ discard block |
||
161 | 161 | return true; |
162 | 162 | } |
163 | 163 | # wrong captcha content or session expired |
164 | - return $this->error('Captcha incorrect', 'SubmittedResult = \'' . $data['captcha'] . '\''); |
|
164 | + return $this->error('Captcha incorrect', 'SubmittedResult = \''.$data['captcha'].'\''); |
|
165 | 165 | } |
166 | 166 | |
167 | 167 | /** |
@@ -210,12 +210,12 @@ discard block |
||
210 | 210 | } |
211 | 211 | |
212 | 212 | App::import('Component', 'RequestHandler'); |
213 | - $msg = 'Ip \'' . RequestHandlerComponent::getClientIP() . '\', Agent \'' . env('HTTP_USER_AGENT') . '\', Referer \'' . env('HTTP_REFERER') . '\', Host-Referer \'' . RequestHandlerComponent::getReferer() . '\''; |
|
213 | + $msg = 'Ip \''.RequestHandlerComponent::getClientIP().'\', Agent \''.env('HTTP_USER_AGENT').'\', Referer \''.env('HTTP_REFERER').'\', Host-Referer \''.RequestHandlerComponent::getReferer().'\''; |
|
214 | 214 | if (!empty($this->error)) { |
215 | - $msg .= ', ' . $this->error; |
|
215 | + $msg .= ', '.$this->error; |
|
216 | 216 | } |
217 | 217 | if (!empty($this->internalError)) { |
218 | - $msg .= ' (' . $this->internalError . ')'; |
|
218 | + $msg .= ' ('.$this->internalError.')'; |
|
219 | 219 | } |
220 | 220 | $this->log($msg, 'captcha'); |
221 | 221 | return true; |
@@ -9,217 +9,217 @@ |
||
9 | 9 | */ |
10 | 10 | class SimpleCaptchaBehavior extends ModelBehavior { |
11 | 11 | |
12 | - private $defaults = array( |
|
13 | - /** |
|
14 | - * Minimum time in seconds which is considered necessary for a human to fill the form |
|
15 | - * |
|
16 | - * We assume that only a bot is able to fill and answer the form faster. |
|
17 | - */ |
|
18 | - 'minTime' => 6, |
|
19 | - /** |
|
20 | - * Maximum time in seconds the form is valid. |
|
21 | - * |
|
22 | - * Prevents harvesting hashs for later use. |
|
23 | - */ |
|
24 | - 'maxTime' => 1200, |
|
25 | - 'log' => false, |
|
26 | - ); |
|
27 | - |
|
28 | - private $methods = array('hash', 'db', 'session'); |
|
29 | - private $method = 'hash'; |
|
30 | - private $log = false; |
|
31 | - private $error = ''; |
|
32 | - private $internalError = ''; |
|
33 | - |
|
34 | - //private $types = array('passive','active','both'); |
|
35 | - //private $useSession = false; |
|
36 | - |
|
37 | - /** |
|
38 | - * Setup instance |
|
39 | - * |
|
40 | - * @param type $Model |
|
41 | - * @param type $settings |
|
42 | - */ |
|
43 | - public function setup(Model $Model, $settings = array()) { |
|
44 | - $this->defaults = array_merge(SimpleCaptcha::$defaults, $this->defaults); |
|
45 | - |
|
46 | - # bootstrap configs |
|
47 | - $configs = (array) Configure::read('Captcha'); |
|
48 | - if (!empty($configs)) { |
|
49 | - $this->settings = array_merge($this->settings, $configs); |
|
50 | - } |
|
51 | - |
|
52 | - if (!isset($this->settings[$Model->alias])) { |
|
53 | - $this->settings[$Model->alias] = $this->defaults; |
|
54 | - } |
|
55 | - $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], (array) $settings); |
|
56 | - } |
|
57 | - |
|
58 | - /** |
|
59 | - * Callback which initializes all the captcha related checking |
|
60 | - * |
|
61 | - * @param Model $Model |
|
62 | - * @return bool |
|
63 | - */ |
|
64 | - public function beforeValidate(Model $Model, $options = array()) { |
|
65 | - $this->Model = &$Model; |
|
66 | - |
|
67 | - if (!$this->_validateCaptchaMinTime($this->Model->data[$this->Model->name])) { |
|
68 | - $this->Model->invalidate('captcha', 'captchaResultTooFast', true); |
|
69 | - } elseif (!$this->_validateCaptchaMaxTime($this->Model->data[$this->Model->name])) { |
|
70 | - $this->Model->invalidate('captcha', 'captchaResultTooLate', true); |
|
71 | - } elseif (!$this->_validateDummyField($this->Model->data[$this->Model->name])) { |
|
72 | - $this->Model->invalidate('captcha', 'captchaIllegalContent', true); |
|
73 | - } elseif ($this->settings[$this->Model->alias]['type'] == 'active' && !$this->_validateCaptcha($this->Model->data[$this->Model->name])) { |
|
74 | - $this->Model->invalidate('captcha', 'captchaResultIncorrect', true); |
|
75 | - } |
|
76 | - |
|
77 | - unset($this->Model->data[$this->Model->name]['captcha']); |
|
78 | - unset($this->Model->data[$this->Model->name]['captcha_hash']); |
|
79 | - unset($this->Model->data[$this->Model->name]['captcha_time']); |
|
80 | - |
|
81 | - return true; |
|
82 | - } |
|
83 | - |
|
84 | - /** |
|
85 | - * Validates the dummy field |
|
86 | - * |
|
87 | - * @param array $data |
|
88 | - * @return bool |
|
89 | - */ |
|
90 | - protected function _validateDummyField($data) { |
|
91 | - $dummyField = $this->settings[$this->Model->alias]['dummyField']; |
|
92 | - if (!empty($data[$dummyField])) { |
|
93 | - # dummy field not empty - SPAM! |
|
94 | - return $this->error('Illegal content', 'DummyField = \'' . $data[$dummyField] . '\''); |
|
95 | - } |
|
96 | - return true; |
|
97 | - } |
|
98 | - |
|
99 | - /** |
|
100 | - * Validates the minimum time |
|
101 | - * |
|
102 | - * @param array $data |
|
103 | - * @return bool |
|
104 | - */ |
|
105 | - protected function _validateCaptchaMinTime($data) { |
|
106 | - if ($this->settings[$this->Model->alias]['minTime'] <= 0) { |
|
107 | - return true; |
|
108 | - } |
|
109 | - |
|
110 | - if (isSet($data['captcha_hash']) && isSet($data['captcha_time']) |
|
111 | - && ( $data['captcha_time'] < time() - $this->settings[$this->Model->alias]['minTime'] ) |
|
112 | - ) { |
|
113 | - return true; |
|
114 | - } |
|
115 | - |
|
116 | - return false; |
|
117 | - } |
|
118 | - |
|
119 | - /** |
|
120 | - * validates maximum time |
|
121 | - * |
|
122 | - * @param array $data |
|
123 | - * @return bool |
|
124 | - */ |
|
125 | - protected function _validateCaptchaMaxTime($data) { |
|
126 | - if ($this->settings[$this->Model->alias]['maxTime'] <= 0) { |
|
127 | - return true; |
|
128 | - } |
|
129 | - if (isSet($data['captcha_hash']) && isSet($data['captcha_time']) |
|
130 | - && ( $data['captcha_time'] + $this->settings[$this->Model->alias]['maxTime'] > time() ) |
|
131 | - ) { |
|
132 | - return true; |
|
133 | - } |
|
134 | - |
|
135 | - return false; |
|
136 | - } |
|
137 | - |
|
138 | - /** |
|
139 | - * Validates captcha calculation |
|
140 | - * |
|
141 | - * flood protection by false fields and math code |
|
142 | - * TODO: build in floodProtection (max Trials etc) |
|
143 | - * TODO: SESSION based one as alternative |
|
144 | - * |
|
145 | - * @param array $data |
|
146 | - * @return bool |
|
147 | - */ |
|
148 | - protected function _validateCaptcha($data) { |
|
149 | - if (!isset($data['captcha'])) { |
|
150 | - # form inputs missing? SPAM! |
|
151 | - return $this->error('Captcha content missing'); |
|
152 | - } |
|
153 | - |
|
154 | - $captcha_params = array( |
|
155 | - 'timestamp' => $data['captcha_time'], |
|
156 | - 'result' => $data['captcha'], |
|
157 | - ); |
|
158 | - $hash = SimpleCaptcha::buildHash($captcha_params, $this->settings[$this->Model->alias]); |
|
159 | - |
|
160 | - if ($data['captcha_hash'] == $hash) { |
|
161 | - return true; |
|
162 | - } |
|
163 | - # wrong captcha content or session expired |
|
164 | - return $this->error('Captcha incorrect', 'SubmittedResult = \'' . $data['captcha'] . '\''); |
|
165 | - } |
|
166 | - |
|
167 | - /** |
|
168 | - * return error message (or empty string if none) |
|
169 | - * @return string |
|
170 | - */ |
|
171 | - public function errors() { |
|
172 | - return $this->error; |
|
173 | - } |
|
174 | - |
|
175 | - /** |
|
176 | - * only neccessary if there is more than one request per model |
|
177 | - * 2009-12-18 ms |
|
178 | - */ |
|
179 | - public function reset() { |
|
180 | - $this->error = ''; |
|
181 | - } |
|
182 | - |
|
183 | - /** |
|
184 | - * build and log error message |
|
185 | - * 2009-12-18 ms |
|
186 | - */ |
|
187 | - private function error($msg = null, $internalMsg = null) { |
|
188 | - if (!empty($msg)) { |
|
189 | - $this->error = $msg; |
|
190 | - } |
|
191 | - if (!empty($internalMsg)) { |
|
192 | - $this->internalError = $internalMsg; |
|
193 | - } |
|
194 | - |
|
195 | - if ($this->log) { |
|
196 | - $this->logAttempt(); |
|
197 | - } |
|
198 | - return false; |
|
199 | - } |
|
200 | - |
|
201 | - /** |
|
202 | - * logs attempts |
|
203 | - * @param bool errorsOnly (only if error occured, otherwise always) |
|
204 | - * @returns null if not logged, true otherwise |
|
205 | - * 2009-12-18 ms |
|
206 | - */ |
|
207 | - private function logAttempt($errorsOnly = true) { |
|
208 | - if ($errorsOnly === true && empty($this->error) && empty($this->internalError)) { |
|
209 | - return null; |
|
210 | - } |
|
211 | - |
|
212 | - App::import('Component', 'RequestHandler'); |
|
213 | - $msg = 'Ip \'' . RequestHandlerComponent::getClientIP() . '\', Agent \'' . env('HTTP_USER_AGENT') . '\', Referer \'' . env('HTTP_REFERER') . '\', Host-Referer \'' . RequestHandlerComponent::getReferer() . '\''; |
|
214 | - if (!empty($this->error)) { |
|
215 | - $msg .= ', ' . $this->error; |
|
216 | - } |
|
217 | - if (!empty($this->internalError)) { |
|
218 | - $msg .= ' (' . $this->internalError . ')'; |
|
219 | - } |
|
220 | - $this->log($msg, 'captcha'); |
|
221 | - return true; |
|
222 | - } |
|
12 | + private $defaults = array( |
|
13 | + /** |
|
14 | + * Minimum time in seconds which is considered necessary for a human to fill the form |
|
15 | + * |
|
16 | + * We assume that only a bot is able to fill and answer the form faster. |
|
17 | + */ |
|
18 | + 'minTime' => 6, |
|
19 | + /** |
|
20 | + * Maximum time in seconds the form is valid. |
|
21 | + * |
|
22 | + * Prevents harvesting hashs for later use. |
|
23 | + */ |
|
24 | + 'maxTime' => 1200, |
|
25 | + 'log' => false, |
|
26 | + ); |
|
27 | + |
|
28 | + private $methods = array('hash', 'db', 'session'); |
|
29 | + private $method = 'hash'; |
|
30 | + private $log = false; |
|
31 | + private $error = ''; |
|
32 | + private $internalError = ''; |
|
33 | + |
|
34 | + //private $types = array('passive','active','both'); |
|
35 | + //private $useSession = false; |
|
36 | + |
|
37 | + /** |
|
38 | + * Setup instance |
|
39 | + * |
|
40 | + * @param type $Model |
|
41 | + * @param type $settings |
|
42 | + */ |
|
43 | + public function setup(Model $Model, $settings = array()) { |
|
44 | + $this->defaults = array_merge(SimpleCaptcha::$defaults, $this->defaults); |
|
45 | + |
|
46 | + # bootstrap configs |
|
47 | + $configs = (array) Configure::read('Captcha'); |
|
48 | + if (!empty($configs)) { |
|
49 | + $this->settings = array_merge($this->settings, $configs); |
|
50 | + } |
|
51 | + |
|
52 | + if (!isset($this->settings[$Model->alias])) { |
|
53 | + $this->settings[$Model->alias] = $this->defaults; |
|
54 | + } |
|
55 | + $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], (array) $settings); |
|
56 | + } |
|
57 | + |
|
58 | + /** |
|
59 | + * Callback which initializes all the captcha related checking |
|
60 | + * |
|
61 | + * @param Model $Model |
|
62 | + * @return bool |
|
63 | + */ |
|
64 | + public function beforeValidate(Model $Model, $options = array()) { |
|
65 | + $this->Model = &$Model; |
|
66 | + |
|
67 | + if (!$this->_validateCaptchaMinTime($this->Model->data[$this->Model->name])) { |
|
68 | + $this->Model->invalidate('captcha', 'captchaResultTooFast', true); |
|
69 | + } elseif (!$this->_validateCaptchaMaxTime($this->Model->data[$this->Model->name])) { |
|
70 | + $this->Model->invalidate('captcha', 'captchaResultTooLate', true); |
|
71 | + } elseif (!$this->_validateDummyField($this->Model->data[$this->Model->name])) { |
|
72 | + $this->Model->invalidate('captcha', 'captchaIllegalContent', true); |
|
73 | + } elseif ($this->settings[$this->Model->alias]['type'] == 'active' && !$this->_validateCaptcha($this->Model->data[$this->Model->name])) { |
|
74 | + $this->Model->invalidate('captcha', 'captchaResultIncorrect', true); |
|
75 | + } |
|
76 | + |
|
77 | + unset($this->Model->data[$this->Model->name]['captcha']); |
|
78 | + unset($this->Model->data[$this->Model->name]['captcha_hash']); |
|
79 | + unset($this->Model->data[$this->Model->name]['captcha_time']); |
|
80 | + |
|
81 | + return true; |
|
82 | + } |
|
83 | + |
|
84 | + /** |
|
85 | + * Validates the dummy field |
|
86 | + * |
|
87 | + * @param array $data |
|
88 | + * @return bool |
|
89 | + */ |
|
90 | + protected function _validateDummyField($data) { |
|
91 | + $dummyField = $this->settings[$this->Model->alias]['dummyField']; |
|
92 | + if (!empty($data[$dummyField])) { |
|
93 | + # dummy field not empty - SPAM! |
|
94 | + return $this->error('Illegal content', 'DummyField = \'' . $data[$dummyField] . '\''); |
|
95 | + } |
|
96 | + return true; |
|
97 | + } |
|
98 | + |
|
99 | + /** |
|
100 | + * Validates the minimum time |
|
101 | + * |
|
102 | + * @param array $data |
|
103 | + * @return bool |
|
104 | + */ |
|
105 | + protected function _validateCaptchaMinTime($data) { |
|
106 | + if ($this->settings[$this->Model->alias]['minTime'] <= 0) { |
|
107 | + return true; |
|
108 | + } |
|
109 | + |
|
110 | + if (isSet($data['captcha_hash']) && isSet($data['captcha_time']) |
|
111 | + && ( $data['captcha_time'] < time() - $this->settings[$this->Model->alias]['minTime'] ) |
|
112 | + ) { |
|
113 | + return true; |
|
114 | + } |
|
115 | + |
|
116 | + return false; |
|
117 | + } |
|
118 | + |
|
119 | + /** |
|
120 | + * validates maximum time |
|
121 | + * |
|
122 | + * @param array $data |
|
123 | + * @return bool |
|
124 | + */ |
|
125 | + protected function _validateCaptchaMaxTime($data) { |
|
126 | + if ($this->settings[$this->Model->alias]['maxTime'] <= 0) { |
|
127 | + return true; |
|
128 | + } |
|
129 | + if (isSet($data['captcha_hash']) && isSet($data['captcha_time']) |
|
130 | + && ( $data['captcha_time'] + $this->settings[$this->Model->alias]['maxTime'] > time() ) |
|
131 | + ) { |
|
132 | + return true; |
|
133 | + } |
|
134 | + |
|
135 | + return false; |
|
136 | + } |
|
137 | + |
|
138 | + /** |
|
139 | + * Validates captcha calculation |
|
140 | + * |
|
141 | + * flood protection by false fields and math code |
|
142 | + * TODO: build in floodProtection (max Trials etc) |
|
143 | + * TODO: SESSION based one as alternative |
|
144 | + * |
|
145 | + * @param array $data |
|
146 | + * @return bool |
|
147 | + */ |
|
148 | + protected function _validateCaptcha($data) { |
|
149 | + if (!isset($data['captcha'])) { |
|
150 | + # form inputs missing? SPAM! |
|
151 | + return $this->error('Captcha content missing'); |
|
152 | + } |
|
153 | + |
|
154 | + $captcha_params = array( |
|
155 | + 'timestamp' => $data['captcha_time'], |
|
156 | + 'result' => $data['captcha'], |
|
157 | + ); |
|
158 | + $hash = SimpleCaptcha::buildHash($captcha_params, $this->settings[$this->Model->alias]); |
|
159 | + |
|
160 | + if ($data['captcha_hash'] == $hash) { |
|
161 | + return true; |
|
162 | + } |
|
163 | + # wrong captcha content or session expired |
|
164 | + return $this->error('Captcha incorrect', 'SubmittedResult = \'' . $data['captcha'] . '\''); |
|
165 | + } |
|
166 | + |
|
167 | + /** |
|
168 | + * return error message (or empty string if none) |
|
169 | + * @return string |
|
170 | + */ |
|
171 | + public function errors() { |
|
172 | + return $this->error; |
|
173 | + } |
|
174 | + |
|
175 | + /** |
|
176 | + * only neccessary if there is more than one request per model |
|
177 | + * 2009-12-18 ms |
|
178 | + */ |
|
179 | + public function reset() { |
|
180 | + $this->error = ''; |
|
181 | + } |
|
182 | + |
|
183 | + /** |
|
184 | + * build and log error message |
|
185 | + * 2009-12-18 ms |
|
186 | + */ |
|
187 | + private function error($msg = null, $internalMsg = null) { |
|
188 | + if (!empty($msg)) { |
|
189 | + $this->error = $msg; |
|
190 | + } |
|
191 | + if (!empty($internalMsg)) { |
|
192 | + $this->internalError = $internalMsg; |
|
193 | + } |
|
194 | + |
|
195 | + if ($this->log) { |
|
196 | + $this->logAttempt(); |
|
197 | + } |
|
198 | + return false; |
|
199 | + } |
|
200 | + |
|
201 | + /** |
|
202 | + * logs attempts |
|
203 | + * @param bool errorsOnly (only if error occured, otherwise always) |
|
204 | + * @returns null if not logged, true otherwise |
|
205 | + * 2009-12-18 ms |
|
206 | + */ |
|
207 | + private function logAttempt($errorsOnly = true) { |
|
208 | + if ($errorsOnly === true && empty($this->error) && empty($this->internalError)) { |
|
209 | + return null; |
|
210 | + } |
|
211 | + |
|
212 | + App::import('Component', 'RequestHandler'); |
|
213 | + $msg = 'Ip \'' . RequestHandlerComponent::getClientIP() . '\', Agent \'' . env('HTTP_USER_AGENT') . '\', Referer \'' . env('HTTP_REFERER') . '\', Host-Referer \'' . RequestHandlerComponent::getReferer() . '\''; |
|
214 | + if (!empty($this->error)) { |
|
215 | + $msg .= ', ' . $this->error; |
|
216 | + } |
|
217 | + if (!empty($this->internalError)) { |
|
218 | + $msg .= ' (' . $this->internalError . ')'; |
|
219 | + } |
|
220 | + $this->log($msg, 'captcha'); |
|
221 | + return true; |
|
222 | + } |
|
223 | 223 | |
224 | 224 | } |
225 | 225 | ?> |
226 | 226 | \ No newline at end of file |
@@ -54,6 +54,9 @@ discard block |
||
54 | 54 | self::$_stopwatchCalls = 0; |
55 | 55 | } |
56 | 56 | |
57 | + /** |
|
58 | + * @param string $event |
|
59 | + */ |
|
57 | 60 | static protected function _addEvent($x, $event = null) { |
58 | 61 | if (self::$_enableTimer === false) { |
59 | 62 | return; |
@@ -264,7 +267,7 @@ discard block |
||
264 | 267 | /** |
265 | 268 | * Alias for self::stop |
266 | 269 | * |
267 | - * @param type $text |
|
270 | + * @param string $text |
|
268 | 271 | */ |
269 | 272 | public static function end($text) { |
270 | 273 | self::stop($text); |
@@ -100,10 +100,10 @@ discard block |
||
100 | 100 | |
101 | 101 | switch ($event) { |
102 | 102 | case 'start': |
103 | - $x = '* ' . $x; |
|
103 | + $x = '* '.$x; |
|
104 | 104 | break; |
105 | 105 | case 'stop': |
106 | - $x = '† ' . $x; |
|
106 | + $x = '† '.$x; |
|
107 | 107 | break; |
108 | 108 | } |
109 | 109 | |
@@ -143,13 +143,13 @@ discard block |
||
143 | 143 | self::start('now'); |
144 | 144 | |
145 | 145 | $out = ""; |
146 | - $out .= 'Time to Cake: ' . sprintf('%05.3f', self::_timeToCake()) . " s\n"; |
|
147 | - $out .= 'Cake bootstrap: ' . sprintf('%05.3f', self::_timeFromCakeToStopwatch()) . " s\n"; |
|
146 | + $out .= 'Time to Cake: '.sprintf('%05.3f', self::_timeToCake())." s\n"; |
|
147 | + $out .= 'Cake bootstrap: '.sprintf('%05.3f', self::_timeFromCakeToStopwatch())." s\n"; |
|
148 | 148 | |
149 | 149 | $out .= "W\tU\tW_delta\tU_delta\tMem [MB]\n"; |
150 | 150 | $_seriesIndex = 1; |
151 | 151 | foreach (self::$_events as $k => $v) { |
152 | - $out .= '<span id="stopwatch-' . $_seriesIndex++ . '" class="stopwatch-row">'; |
|
152 | + $out .= '<span id="stopwatch-'.$_seriesIndex++.'" class="stopwatch-row">'; |
|
153 | 153 | $out .= sprintf("%05.3f\t%05.3f\t%05.3f\t%05.3f\t%5.1f\t%s\n", |
154 | 154 | $v['wtime'], |
155 | 155 | $v['utime'], |
@@ -196,7 +196,7 @@ discard block |
||
196 | 196 | $k); |
197 | 197 | } |
198 | 198 | |
199 | - $out .= "\n\n" . self::printStatistic(); |
|
199 | + $out .= "\n\n".self::printStatistic(); |
|
200 | 200 | |
201 | 201 | return $out; |
202 | 202 | } |
@@ -238,7 +238,7 @@ discard block |
||
238 | 238 | } |
239 | 239 | |
240 | 240 | public static function printStatistic() { |
241 | - return self::$_stopwatchCalls . " calls with ca " . sprintf("%05.3f", self::$_stopwatchTime) . ' sec overhead.'; |
|
241 | + return self::$_stopwatchCalls." calls with ca ".sprintf("%05.3f", self::$_stopwatchTime).' sec overhead.'; |
|
242 | 242 | } |
243 | 243 | |
244 | 244 | public static function getWallTime($divider = null) { |
@@ -258,7 +258,7 @@ discard block |
||
258 | 258 | self::end('getWallTime()'); |
259 | 259 | $time = self::$_events[count(self::$_events) - 1]['wtime'] + |
260 | 260 | self::_timeToStopwatch(); |
261 | - return number_format( $time, 3, $decimal, $thousand); |
|
261 | + return number_format($time, 3, $decimal, $thousand); |
|
262 | 262 | } |
263 | 263 | |
264 | 264 | /** |
@@ -2,272 +2,272 @@ |
||
2 | 2 | |
3 | 3 | class Stopwatch { |
4 | 4 | |
5 | - protected static $_startupTime = 0; |
|
6 | - |
|
7 | - protected static $_instance = null; |
|
8 | - |
|
9 | - protected static $_enableTimer = false; |
|
10 | - |
|
11 | - protected static $_wallStart = 0; |
|
12 | - |
|
13 | - protected static $_userStart = 0; |
|
14 | - |
|
15 | - protected static $_wallLast = 0; |
|
16 | - |
|
17 | - protected static $_userLast = 0; |
|
18 | - |
|
19 | - protected static $_events; |
|
20 | - |
|
21 | - protected static $_sums = array(); |
|
22 | - |
|
23 | - protected static $_starts = array(); |
|
24 | - |
|
25 | - protected static $_stopwatchTime = 0; |
|
26 | - |
|
27 | - protected static $_stopwatchCalls = 0; |
|
28 | - |
|
29 | - public static function getInstance() { |
|
30 | - if (self::$_instance === null) { |
|
31 | - self::$_instance = new Stopwatch(); |
|
32 | - } |
|
33 | - return self::$_instance; |
|
34 | - } |
|
35 | - |
|
36 | - protected function __construct() { |
|
37 | - } |
|
38 | - |
|
39 | - private function __clone() { |
|
40 | - } |
|
41 | - |
|
42 | - static public function reset() { |
|
43 | - self::$_startupTime = 0; |
|
44 | - self::$_instance = null; |
|
45 | - self::$_enableTimer = false; |
|
46 | - self::$_wallStart = 0; |
|
47 | - self::$_userStart = 0; |
|
48 | - self::$_wallLast = 0; |
|
49 | - self::$_userLast = 0; |
|
50 | - self::$_events = []; |
|
51 | - self::$_sums = array(); |
|
52 | - self::$_starts = array(); |
|
53 | - self::$_stopwatchTime = 0; |
|
54 | - self::$_stopwatchCalls = 0; |
|
55 | - } |
|
56 | - |
|
57 | - static protected function _addEvent($x, $event = null) { |
|
58 | - if (self::$_enableTimer === false) { |
|
59 | - return; |
|
60 | - } |
|
61 | - |
|
62 | - list($usec, $sec) = explode(' ', microtime()); |
|
63 | - $wtime = ($sec + $usec); |
|
64 | - if (!self::$_wallStart) { |
|
65 | - self::$_wallStart = $wtime; |
|
66 | - } |
|
67 | - |
|
68 | - $dat = @getrusage(); |
|
69 | - if ($dat === null) { |
|
70 | - // some hosters disable getrusage() while hardening their PHP |
|
71 | - $utime = 0; |
|
72 | - } else { |
|
73 | - $utime = ($dat['ru_utime.tv_sec'] + $dat['ru_utime.tv_usec'] / 1000000); |
|
74 | - } |
|
75 | - |
|
76 | - if (!self::$_userStart) { |
|
77 | - self::$_userStart = $utime; |
|
78 | - } |
|
79 | - |
|
80 | - $udiff = ($wtime - self::$_wallStart == 0) ? 0 : $utime - self::$_userLast; |
|
81 | - self::$_userLast = $utime; |
|
82 | - |
|
83 | - $wdiff = ($wtime - self::$_wallStart == 0) ? 0 : $wtime - self::$_wallLast; |
|
84 | - self::$_wallLast = $wtime; |
|
85 | - |
|
86 | - if (!isset(self::$_starts[$x])) { |
|
87 | - self::$_starts[$x]['wtime'] = $wtime; |
|
88 | - self::$_starts[$x]['utime'] = $utime; |
|
89 | - } else { |
|
90 | - if (!isset(self::$_sums[$x]['wtime'])) { |
|
91 | - self::$_sums[$x]['wtime'] = 0; |
|
92 | - self::$_sums[$x]['utime'] = 0; |
|
93 | - self::$_sums[$x]['times'] = 0; |
|
94 | - } |
|
95 | - self::$_sums[$x]['wtime'] = self::$_sums[$x]['wtime'] + $wtime - self::$_starts[$x]['wtime']; |
|
96 | - self::$_sums[$x]['utime'] = self::$_sums[$x]['utime'] + $utime - self::$_starts[$x]['utime']; |
|
97 | - self::$_sums[$x]['times'] = self::$_sums[$x]['times'] + 1; |
|
98 | - unset(self::$_starts[$x]); |
|
99 | - } |
|
100 | - |
|
101 | - switch ($event) { |
|
102 | - case 'start': |
|
103 | - $x = '* ' . $x; |
|
104 | - break; |
|
105 | - case 'stop': |
|
106 | - $x = '† ' . $x; |
|
107 | - break; |
|
108 | - } |
|
109 | - |
|
110 | - self::$_events[] = array( |
|
111 | - 'title' => $x, |
|
112 | - 'wtime' => $wtime - self::$_wallStart, |
|
113 | - 'utime' => $utime - self::$_userStart, |
|
114 | - 'wdiff' => $wdiff, |
|
115 | - 'udiff' => $udiff, |
|
116 | - 'mem' => memory_get_usage() |
|
117 | - ); |
|
118 | - |
|
119 | - // endtime |
|
120 | - list($eusec, $esec) = explode(' ', microtime()); |
|
121 | - $ewtime = ($esec + $eusec); |
|
122 | - self::$_stopwatchTime += ($ewtime - $wtime); |
|
123 | - self::$_stopwatchCalls++; |
|
124 | - } |
|
125 | - |
|
126 | - static protected function _timeToCake() { |
|
127 | - return TIME_START - $_SERVER['REQUEST_TIME_FLOAT']; |
|
128 | - } |
|
129 | - |
|
130 | - static protected function _timeFromCakeToStopwatch() { |
|
131 | - return self::$_startupTime - TIME_START; |
|
132 | - } |
|
133 | - |
|
134 | - static protected function _timeToStopwatch() { |
|
135 | - return self::$_startupTime - $_SERVER['REQUEST_TIME_FLOAT']; |
|
136 | - } |
|
137 | - |
|
138 | - public static function getString() { |
|
139 | - if (self::$_enableTimer === false) { |
|
140 | - return; |
|
141 | - } |
|
142 | - |
|
143 | - self::start('now'); |
|
144 | - |
|
145 | - $out = ""; |
|
146 | - $out .= 'Time to Cake: ' . sprintf('%05.3f', self::_timeToCake()) . " s\n"; |
|
147 | - $out .= 'Cake bootstrap: ' . sprintf('%05.3f', self::_timeFromCakeToStopwatch()) . " s\n"; |
|
148 | - |
|
149 | - $out .= "W\tU\tW_delta\tU_delta\tMem [MB]\n"; |
|
150 | - $_seriesIndex = 1; |
|
151 | - foreach (self::$_events as $k => $v) { |
|
152 | - $out .= '<span id="stopwatch-' . $_seriesIndex++ . '" class="stopwatch-row">'; |
|
153 | - $out .= sprintf("%05.3f\t%05.3f\t%05.3f\t%05.3f\t%5.1f\t%s\n", |
|
154 | - $v['wtime'], |
|
155 | - $v['utime'], |
|
156 | - $v['wdiff'], |
|
157 | - $v['udiff'], |
|
158 | - $v['mem'] / 1048576, |
|
159 | - $v['title']); |
|
160 | - $out .= '</span>'; |
|
161 | - } |
|
162 | - |
|
163 | - $out .= "\n\n"; |
|
164 | - |
|
165 | - for ($i = 0; $i < 100; $i++) { |
|
166 | - Stopwatch::start('e'); |
|
167 | - Stopwatch::stop('e'); |
|
168 | - } |
|
169 | - $_e = array_pop(self::$_sums); |
|
170 | - $_eW = $_e['wtime'] / 100; |
|
171 | - $_eU = $_e['utime'] / 100; |
|
172 | - |
|
173 | - self::$_events = array_slice(self::$_events, 0, -200); |
|
174 | - |
|
175 | - $out .= "W_sum\tU_sum\tW_%\tU_%\t#\tW_ø\n"; |
|
176 | - |
|
177 | - $_lastTimestamp = end(self::$_events); |
|
178 | - $wlast = $_lastTimestamp['wtime'] / 100; |
|
179 | - $ulast = $_lastTimestamp['utime'] / 100; |
|
180 | - foreach (self::$_sums as $k => $v) { |
|
181 | - // on vagrant $ulast may be 0 for unknown reason when running test cases |
|
182 | - // ugly hack to suppress output in test-cases, where it isn't read anyway |
|
183 | - if (empty($ulast)) { |
|
184 | - break; |
|
185 | - } |
|
186 | - $v['wtime'] = $v['wtime'] - ($_eW * $v['times']); |
|
187 | - $v['utime'] = $v['utime'] - ($_eW * $v['times']); |
|
188 | - |
|
189 | - $out .= sprintf("%05.3f\t%05.3f\t%04.1f\t%04.1f\t%u\t%05.3f\t%s\n", |
|
190 | - $v['wtime'], |
|
191 | - $v['utime'], |
|
192 | - $v['wtime'] / $wlast, |
|
193 | - $v['utime'] / $ulast, |
|
194 | - $v['times'], |
|
195 | - $v['wtime'] / $v['times'], |
|
196 | - $k); |
|
197 | - } |
|
198 | - |
|
199 | - $out .= "\n\n" . self::printStatistic(); |
|
200 | - |
|
201 | - return $out; |
|
202 | - } |
|
203 | - |
|
204 | - public static function getJs() { |
|
205 | - if (self::$_enableTimer === false) { |
|
206 | - return; |
|
207 | - } |
|
208 | - $data = array(); |
|
209 | - foreach (self::$_events as $v) { |
|
210 | - $data[] = array( |
|
211 | - 'label' => $v['title'], |
|
212 | - 'data' => [[1, $v['wdiff']], [2, $v['udiff']]] |
|
213 | - ); |
|
214 | - } |
|
215 | - $out = json_encode($data); |
|
216 | - return $out; |
|
217 | - } |
|
218 | - |
|
219 | - public static function init() { |
|
220 | - self::reset(); |
|
221 | - self::$_startupTime = microtime(true); |
|
222 | - } |
|
223 | - |
|
224 | - public static function enable() { |
|
225 | - self::$_enableTimer = true; |
|
226 | - } |
|
227 | - |
|
228 | - public static function disable() { |
|
229 | - self::$_enableTimer = false; |
|
230 | - } |
|
231 | - |
|
232 | - public static function start($text) { |
|
233 | - self::_addEvent($text, 'start'); |
|
234 | - } |
|
235 | - |
|
236 | - public static function stop($text) { |
|
237 | - self::_addEvent($text, 'stop'); |
|
238 | - } |
|
239 | - |
|
240 | - public static function printStatistic() { |
|
241 | - return self::$_stopwatchCalls . " calls with ca " . sprintf("%05.3f", self::$_stopwatchTime) . ' sec overhead.'; |
|
242 | - } |
|
243 | - |
|
244 | - public static function getWallTime($divider = null) { |
|
245 | - $thousand = ''; |
|
246 | - |
|
247 | - if ($divider === 'eng') { |
|
248 | - $divider = '.'; |
|
249 | - } |
|
250 | - |
|
251 | - if (strlen($divider) < 2) { |
|
252 | - $decimal = $divider; |
|
253 | - } else { |
|
254 | - $decimal = ','; |
|
255 | - } |
|
256 | - |
|
257 | - self::start('getWallTime()'); |
|
258 | - self::end('getWallTime()'); |
|
259 | - $time = self::$_events[count(self::$_events) - 1]['wtime'] + |
|
260 | - self::_timeToStopwatch(); |
|
261 | - return number_format( $time, 3, $decimal, $thousand); |
|
262 | - } |
|
5 | + protected static $_startupTime = 0; |
|
6 | + |
|
7 | + protected static $_instance = null; |
|
8 | + |
|
9 | + protected static $_enableTimer = false; |
|
10 | + |
|
11 | + protected static $_wallStart = 0; |
|
12 | + |
|
13 | + protected static $_userStart = 0; |
|
14 | + |
|
15 | + protected static $_wallLast = 0; |
|
16 | + |
|
17 | + protected static $_userLast = 0; |
|
18 | + |
|
19 | + protected static $_events; |
|
20 | + |
|
21 | + protected static $_sums = array(); |
|
22 | + |
|
23 | + protected static $_starts = array(); |
|
24 | + |
|
25 | + protected static $_stopwatchTime = 0; |
|
26 | + |
|
27 | + protected static $_stopwatchCalls = 0; |
|
28 | + |
|
29 | + public static function getInstance() { |
|
30 | + if (self::$_instance === null) { |
|
31 | + self::$_instance = new Stopwatch(); |
|
32 | + } |
|
33 | + return self::$_instance; |
|
34 | + } |
|
35 | + |
|
36 | + protected function __construct() { |
|
37 | + } |
|
38 | + |
|
39 | + private function __clone() { |
|
40 | + } |
|
41 | + |
|
42 | + static public function reset() { |
|
43 | + self::$_startupTime = 0; |
|
44 | + self::$_instance = null; |
|
45 | + self::$_enableTimer = false; |
|
46 | + self::$_wallStart = 0; |
|
47 | + self::$_userStart = 0; |
|
48 | + self::$_wallLast = 0; |
|
49 | + self::$_userLast = 0; |
|
50 | + self::$_events = []; |
|
51 | + self::$_sums = array(); |
|
52 | + self::$_starts = array(); |
|
53 | + self::$_stopwatchTime = 0; |
|
54 | + self::$_stopwatchCalls = 0; |
|
55 | + } |
|
56 | + |
|
57 | + static protected function _addEvent($x, $event = null) { |
|
58 | + if (self::$_enableTimer === false) { |
|
59 | + return; |
|
60 | + } |
|
61 | + |
|
62 | + list($usec, $sec) = explode(' ', microtime()); |
|
63 | + $wtime = ($sec + $usec); |
|
64 | + if (!self::$_wallStart) { |
|
65 | + self::$_wallStart = $wtime; |
|
66 | + } |
|
67 | + |
|
68 | + $dat = @getrusage(); |
|
69 | + if ($dat === null) { |
|
70 | + // some hosters disable getrusage() while hardening their PHP |
|
71 | + $utime = 0; |
|
72 | + } else { |
|
73 | + $utime = ($dat['ru_utime.tv_sec'] + $dat['ru_utime.tv_usec'] / 1000000); |
|
74 | + } |
|
75 | + |
|
76 | + if (!self::$_userStart) { |
|
77 | + self::$_userStart = $utime; |
|
78 | + } |
|
79 | + |
|
80 | + $udiff = ($wtime - self::$_wallStart == 0) ? 0 : $utime - self::$_userLast; |
|
81 | + self::$_userLast = $utime; |
|
82 | + |
|
83 | + $wdiff = ($wtime - self::$_wallStart == 0) ? 0 : $wtime - self::$_wallLast; |
|
84 | + self::$_wallLast = $wtime; |
|
85 | + |
|
86 | + if (!isset(self::$_starts[$x])) { |
|
87 | + self::$_starts[$x]['wtime'] = $wtime; |
|
88 | + self::$_starts[$x]['utime'] = $utime; |
|
89 | + } else { |
|
90 | + if (!isset(self::$_sums[$x]['wtime'])) { |
|
91 | + self::$_sums[$x]['wtime'] = 0; |
|
92 | + self::$_sums[$x]['utime'] = 0; |
|
93 | + self::$_sums[$x]['times'] = 0; |
|
94 | + } |
|
95 | + self::$_sums[$x]['wtime'] = self::$_sums[$x]['wtime'] + $wtime - self::$_starts[$x]['wtime']; |
|
96 | + self::$_sums[$x]['utime'] = self::$_sums[$x]['utime'] + $utime - self::$_starts[$x]['utime']; |
|
97 | + self::$_sums[$x]['times'] = self::$_sums[$x]['times'] + 1; |
|
98 | + unset(self::$_starts[$x]); |
|
99 | + } |
|
100 | + |
|
101 | + switch ($event) { |
|
102 | + case 'start': |
|
103 | + $x = '* ' . $x; |
|
104 | + break; |
|
105 | + case 'stop': |
|
106 | + $x = '† ' . $x; |
|
107 | + break; |
|
108 | + } |
|
109 | + |
|
110 | + self::$_events[] = array( |
|
111 | + 'title' => $x, |
|
112 | + 'wtime' => $wtime - self::$_wallStart, |
|
113 | + 'utime' => $utime - self::$_userStart, |
|
114 | + 'wdiff' => $wdiff, |
|
115 | + 'udiff' => $udiff, |
|
116 | + 'mem' => memory_get_usage() |
|
117 | + ); |
|
118 | + |
|
119 | + // endtime |
|
120 | + list($eusec, $esec) = explode(' ', microtime()); |
|
121 | + $ewtime = ($esec + $eusec); |
|
122 | + self::$_stopwatchTime += ($ewtime - $wtime); |
|
123 | + self::$_stopwatchCalls++; |
|
124 | + } |
|
125 | + |
|
126 | + static protected function _timeToCake() { |
|
127 | + return TIME_START - $_SERVER['REQUEST_TIME_FLOAT']; |
|
128 | + } |
|
129 | + |
|
130 | + static protected function _timeFromCakeToStopwatch() { |
|
131 | + return self::$_startupTime - TIME_START; |
|
132 | + } |
|
133 | + |
|
134 | + static protected function _timeToStopwatch() { |
|
135 | + return self::$_startupTime - $_SERVER['REQUEST_TIME_FLOAT']; |
|
136 | + } |
|
137 | + |
|
138 | + public static function getString() { |
|
139 | + if (self::$_enableTimer === false) { |
|
140 | + return; |
|
141 | + } |
|
142 | + |
|
143 | + self::start('now'); |
|
144 | + |
|
145 | + $out = ""; |
|
146 | + $out .= 'Time to Cake: ' . sprintf('%05.3f', self::_timeToCake()) . " s\n"; |
|
147 | + $out .= 'Cake bootstrap: ' . sprintf('%05.3f', self::_timeFromCakeToStopwatch()) . " s\n"; |
|
148 | + |
|
149 | + $out .= "W\tU\tW_delta\tU_delta\tMem [MB]\n"; |
|
150 | + $_seriesIndex = 1; |
|
151 | + foreach (self::$_events as $k => $v) { |
|
152 | + $out .= '<span id="stopwatch-' . $_seriesIndex++ . '" class="stopwatch-row">'; |
|
153 | + $out .= sprintf("%05.3f\t%05.3f\t%05.3f\t%05.3f\t%5.1f\t%s\n", |
|
154 | + $v['wtime'], |
|
155 | + $v['utime'], |
|
156 | + $v['wdiff'], |
|
157 | + $v['udiff'], |
|
158 | + $v['mem'] / 1048576, |
|
159 | + $v['title']); |
|
160 | + $out .= '</span>'; |
|
161 | + } |
|
162 | + |
|
163 | + $out .= "\n\n"; |
|
164 | + |
|
165 | + for ($i = 0; $i < 100; $i++) { |
|
166 | + Stopwatch::start('e'); |
|
167 | + Stopwatch::stop('e'); |
|
168 | + } |
|
169 | + $_e = array_pop(self::$_sums); |
|
170 | + $_eW = $_e['wtime'] / 100; |
|
171 | + $_eU = $_e['utime'] / 100; |
|
172 | + |
|
173 | + self::$_events = array_slice(self::$_events, 0, -200); |
|
174 | + |
|
175 | + $out .= "W_sum\tU_sum\tW_%\tU_%\t#\tW_ø\n"; |
|
176 | + |
|
177 | + $_lastTimestamp = end(self::$_events); |
|
178 | + $wlast = $_lastTimestamp['wtime'] / 100; |
|
179 | + $ulast = $_lastTimestamp['utime'] / 100; |
|
180 | + foreach (self::$_sums as $k => $v) { |
|
181 | + // on vagrant $ulast may be 0 for unknown reason when running test cases |
|
182 | + // ugly hack to suppress output in test-cases, where it isn't read anyway |
|
183 | + if (empty($ulast)) { |
|
184 | + break; |
|
185 | + } |
|
186 | + $v['wtime'] = $v['wtime'] - ($_eW * $v['times']); |
|
187 | + $v['utime'] = $v['utime'] - ($_eW * $v['times']); |
|
188 | + |
|
189 | + $out .= sprintf("%05.3f\t%05.3f\t%04.1f\t%04.1f\t%u\t%05.3f\t%s\n", |
|
190 | + $v['wtime'], |
|
191 | + $v['utime'], |
|
192 | + $v['wtime'] / $wlast, |
|
193 | + $v['utime'] / $ulast, |
|
194 | + $v['times'], |
|
195 | + $v['wtime'] / $v['times'], |
|
196 | + $k); |
|
197 | + } |
|
198 | + |
|
199 | + $out .= "\n\n" . self::printStatistic(); |
|
200 | + |
|
201 | + return $out; |
|
202 | + } |
|
203 | + |
|
204 | + public static function getJs() { |
|
205 | + if (self::$_enableTimer === false) { |
|
206 | + return; |
|
207 | + } |
|
208 | + $data = array(); |
|
209 | + foreach (self::$_events as $v) { |
|
210 | + $data[] = array( |
|
211 | + 'label' => $v['title'], |
|
212 | + 'data' => [[1, $v['wdiff']], [2, $v['udiff']]] |
|
213 | + ); |
|
214 | + } |
|
215 | + $out = json_encode($data); |
|
216 | + return $out; |
|
217 | + } |
|
218 | + |
|
219 | + public static function init() { |
|
220 | + self::reset(); |
|
221 | + self::$_startupTime = microtime(true); |
|
222 | + } |
|
223 | + |
|
224 | + public static function enable() { |
|
225 | + self::$_enableTimer = true; |
|
226 | + } |
|
227 | + |
|
228 | + public static function disable() { |
|
229 | + self::$_enableTimer = false; |
|
230 | + } |
|
231 | + |
|
232 | + public static function start($text) { |
|
233 | + self::_addEvent($text, 'start'); |
|
234 | + } |
|
235 | + |
|
236 | + public static function stop($text) { |
|
237 | + self::_addEvent($text, 'stop'); |
|
238 | + } |
|
239 | + |
|
240 | + public static function printStatistic() { |
|
241 | + return self::$_stopwatchCalls . " calls with ca " . sprintf("%05.3f", self::$_stopwatchTime) . ' sec overhead.'; |
|
242 | + } |
|
243 | + |
|
244 | + public static function getWallTime($divider = null) { |
|
245 | + $thousand = ''; |
|
246 | + |
|
247 | + if ($divider === 'eng') { |
|
248 | + $divider = '.'; |
|
249 | + } |
|
250 | + |
|
251 | + if (strlen($divider) < 2) { |
|
252 | + $decimal = $divider; |
|
253 | + } else { |
|
254 | + $decimal = ','; |
|
255 | + } |
|
256 | + |
|
257 | + self::start('getWallTime()'); |
|
258 | + self::end('getWallTime()'); |
|
259 | + $time = self::$_events[count(self::$_events) - 1]['wtime'] + |
|
260 | + self::_timeToStopwatch(); |
|
261 | + return number_format( $time, 3, $decimal, $thousand); |
|
262 | + } |
|
263 | 263 | |
264 | 264 | /** |
265 | 265 | * Alias for self::stop |
266 | 266 | * |
267 | 267 | * @param type $text |
268 | 268 | */ |
269 | - public static function end($text) { |
|
270 | - self::stop($text); |
|
271 | - } |
|
269 | + public static function end($text) { |
|
270 | + self::stop($text); |
|
271 | + } |
|
272 | 272 | |
273 | 273 | } |
@@ -151,6 +151,9 @@ |
||
151 | 151 | return $this->Html->tag('span', $content, ['class' => 'infoText']); |
152 | 152 | } |
153 | 153 | |
154 | + /** |
|
155 | + * @param string $icon |
|
156 | + */ |
|
154 | 157 | public function textWithIcon($text, $icon) { |
155 | 158 | return <<<EOF |
156 | 159 | <i class="saito-icon fa fa-$icon"></i> |
@@ -13,8 +13,8 @@ discard block |
||
13 | 13 | protected $_themeImgUrl = null; |
14 | 14 | |
15 | 15 | public function beforeRender($viewFile) { |
16 | - $this->_themeImgUrl = $this->request->webroot . 'theme' . DS . $this->theme . |
|
17 | - DS . Configure::read('App.imageBaseUrl'); |
|
16 | + $this->_themeImgUrl = $this->request->webroot.'theme'.DS.$this->theme. |
|
17 | + DS.Configure::read('App.imageBaseUrl'); |
|
18 | 18 | } |
19 | 19 | |
20 | 20 | public function beforeLayout($layoutFile) { |
@@ -29,10 +29,10 @@ discard block |
||
29 | 29 | public function jQueryTag() { |
30 | 30 | $url = 'dist/'; |
31 | 31 | $name = 'jquery'; |
32 | - if ((int)Configure::read('debug') === 0) { |
|
33 | - $name = $name . '.min'; |
|
32 | + if ((int) Configure::read('debug') === 0) { |
|
33 | + $name = $name.'.min'; |
|
34 | 34 | } |
35 | - return $this->Html->script($this->Html->assetUrl($url . $name, |
|
35 | + return $this->Html->script($this->Html->assetUrl($url.$name, |
|
36 | 36 | ['ext' => '.js', 'fullBase' => true])); |
37 | 37 | } |
38 | 38 | |
@@ -69,14 +69,14 @@ discard block |
||
69 | 69 | 'title' => Configure::read('Saito.Settings.forum_name') |
70 | 70 | ]; |
71 | 71 | $html = []; |
72 | - $html[] = '<meta name="application-name" content="' . h($options['title']) . '"/>'; |
|
72 | + $html[] = '<meta name="application-name" content="'.h($options['title']).'"/>'; |
|
73 | 73 | if (isset($options['color'])) { |
74 | - $html[] = '<meta name="msapplication-TileColor" content="' . $options['color'] . '"/>'; |
|
74 | + $html[] = '<meta name="msapplication-TileColor" content="'.$options['color'].'"/>'; |
|
75 | 75 | } |
76 | 76 | |
77 | 77 | $_basename = $options['baseName']; |
78 | 78 | $url = "{$this->_themeImgUrl}{$_basename}.png"; |
79 | - $html[] = '<meta name="msapplication-TileImage" content="' . $url . '"/>'; |
|
79 | + $html[] = '<meta name="msapplication-TileImage" content="'.$url.'"/>'; |
|
80 | 80 | return implode("\n", $html); |
81 | 81 | } |
82 | 82 | |
@@ -225,7 +225,7 @@ discard block |
||
225 | 225 | $_content += ['first' => '', 'middle' => '', 'last' => '']; |
226 | 226 | $out = ''; |
227 | 227 | foreach (['first', 'middle', 'last'] as $key) { |
228 | - $out .= '<div class="heading-3-' . $key . '">'; |
|
228 | + $out .= '<div class="heading-3-'.$key.'">'; |
|
229 | 229 | $out .= $options['escape'] ? h($_content[$key]) : $_content[$key]; |
230 | 230 | $out .= '</div>'; |
231 | 231 | } |
@@ -235,7 +235,7 @@ discard block |
||
235 | 235 | public function linkToUserProfile($user, ForumsUserInterface $CurrentUser) { |
236 | 236 | if ($CurrentUser->isLoggedIn()) { |
237 | 237 | return $this->Html->link($user['username'], |
238 | - '/users/view/' . $user['id']); |
|
238 | + '/users/view/'.$user['id']); |
|
239 | 239 | } else { |
240 | 240 | return h($user['username']); |
241 | 241 | } |
@@ -1,183 +1,183 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | |
3 | - use Saito\User\ForumsUserInterface; |
|
4 | - |
|
5 | - App::uses('AppHelper', 'View/Helper'); |
|
6 | - |
|
7 | - class LayoutHelper extends AppHelper { |
|
8 | - |
|
9 | - public $helpers = [ |
|
10 | - 'Html' |
|
11 | - ]; |
|
12 | - |
|
13 | - protected $_themeImgUrl = null; |
|
14 | - |
|
15 | - public function beforeRender($viewFile) { |
|
16 | - $this->_themeImgUrl = $this->request->webroot . 'theme' . DS . $this->theme . |
|
17 | - DS . Configure::read('App.imageBaseUrl'); |
|
18 | - } |
|
19 | - |
|
20 | - public function beforeLayout($layoutFile) { |
|
21 | - if (Configure::read('debug')) { |
|
22 | - $stylesheets[] = 'stylesheets/cake.css'; |
|
23 | - } |
|
24 | - if (!empty($stylesheets)) { |
|
25 | - $this->Html->css($stylesheets, null, ['inline' => false]); |
|
26 | - } |
|
27 | - } |
|
28 | - |
|
29 | - public function jQueryTag() { |
|
30 | - $url = 'dist/'; |
|
31 | - $name = 'jquery'; |
|
32 | - if ((int)Configure::read('debug') === 0) { |
|
33 | - $name = $name . '.min'; |
|
34 | - } |
|
35 | - return $this->Html->script($this->Html->assetUrl($url . $name, |
|
36 | - ['ext' => '.js', 'fullBase' => true])); |
|
37 | - } |
|
38 | - |
|
39 | - /** |
|
40 | - * Output link to Android touch icon |
|
41 | - */ |
|
42 | - public function androidTouchIcon($size, array $options = []) { |
|
43 | - return $this->_touchIcon($size, |
|
44 | - $options + ['rel' => 'shortcut icon']); |
|
45 | - } |
|
46 | - |
|
47 | - /** |
|
48 | - * Output link to iOS touch icon |
|
49 | - */ |
|
50 | - public function appleTouchIcon($size, array $options = []) { |
|
51 | - return $this->_touchIcon($size, $options); |
|
52 | - } |
|
53 | - |
|
54 | - /** |
|
55 | - * Output tile info for Windows 8. |
|
56 | - * |
|
57 | - * @param array $size unused |
|
58 | - * @param array $options |
|
59 | - * - 'basename' (default: app-icon) |
|
60 | - * - 'color' Background color for tile. |
|
61 | - * - 'title' Title displayed on tile. |
|
62 | - * |
|
63 | - * @return string |
|
64 | - */ |
|
65 | - public function msTouchIcon(array $size = [], array $options = []) { |
|
66 | - $options += [ |
|
67 | - 'baseName' => 'app-icon', |
|
68 | - 'color' => null, |
|
69 | - 'title' => Configure::read('Saito.Settings.forum_name') |
|
70 | - ]; |
|
71 | - $html = []; |
|
72 | - $html[] = '<meta name="application-name" content="' . h($options['title']) . '"/>'; |
|
73 | - if (isset($options['color'])) { |
|
74 | - $html[] = '<meta name="msapplication-TileColor" content="' . $options['color'] . '"/>'; |
|
75 | - } |
|
76 | - |
|
77 | - $_basename = $options['baseName']; |
|
78 | - $url = "{$this->_themeImgUrl}{$_basename}.png"; |
|
79 | - $html[] = '<meta name="msapplication-TileImage" content="' . $url . '"/>'; |
|
80 | - return implode("\n", $html); |
|
81 | - } |
|
82 | - |
|
83 | - /** |
|
84 | - * Output link to touch icon |
|
85 | - * |
|
86 | - * Files must be placed in <theme>/webroot/img/<baseName>-<size>x<size>.png |
|
87 | - * |
|
88 | - * @param mixed $size integer or array with integer |
|
89 | - * @param array $options |
|
90 | - * `baseName` (default: 'app-icon') |
|
91 | - * `precomposed` adds '-precomposed' to baseName (default: false) |
|
92 | - * `rel` (default: 'apple-touch-icon') |
|
93 | - * `size` outputs "size"-attribute (default: true) |
|
94 | - * @return string |
|
95 | - */ |
|
96 | - protected function _touchIcon($size, array $options = []) { |
|
97 | - if (is_array($size)) { |
|
98 | - $_out = ''; |
|
99 | - foreach ($size as $s) { |
|
100 | - $_out .= $this->appleTouchIcon($s, $options); |
|
101 | - } |
|
102 | - return $_out; |
|
103 | - } |
|
104 | - |
|
105 | - $_defaults = [ |
|
106 | - 'baseName' => 'app-icon', |
|
107 | - 'precomposed' => false, |
|
108 | - 'rel' => 'apple-touch-icon', |
|
109 | - 'size' => true |
|
110 | - ]; |
|
111 | - $options += $_defaults; |
|
112 | - |
|
113 | - $_xSize = "{$size}x{$size}"; |
|
114 | - |
|
115 | - $_basename = $options['baseName']; |
|
116 | - if ($options['precomposed']) { |
|
117 | - $_basename .= '-precomposed'; |
|
118 | - } |
|
119 | - $_filename = "{$_basename}-{$_xSize}.png"; |
|
120 | - |
|
121 | - $url = "{$this->_themeImgUrl}{$_filename}"; |
|
122 | - |
|
123 | - $_out = "<link rel=\"{$options['rel']}\" "; |
|
124 | - if ($options['size']) { |
|
125 | - $_out .= "size=\"{$_xSize}\" "; |
|
126 | - } |
|
127 | - $_out .= "href=\"{$url}\">"; |
|
128 | - return $_out; |
|
129 | - } |
|
130 | - |
|
131 | - /** |
|
132 | - * Generates page heading html |
|
133 | - * |
|
134 | - * @param string $heading |
|
135 | - * @param string $tag |
|
136 | - * @return string |
|
137 | - */ |
|
138 | - public function pageHeading($heading, $tag = 'h1') { |
|
139 | - return $this->Html->tag($tag, |
|
140 | - $heading, |
|
141 | - ['class' => 'pageHeading', 'escape' => true]); |
|
142 | - } |
|
143 | - |
|
144 | - /** |
|
145 | - * Generates intoText tag |
|
146 | - * |
|
147 | - * @param string $content |
|
148 | - * @return string |
|
149 | - */ |
|
150 | - public function infoText($content) { |
|
151 | - return $this->Html->tag('span', $content, ['class' => 'infoText']); |
|
152 | - } |
|
153 | - |
|
154 | - public function textWithIcon($text, $icon) { |
|
155 | - return <<<EOF |
|
3 | + use Saito\User\ForumsUserInterface; |
|
4 | + |
|
5 | + App::uses('AppHelper', 'View/Helper'); |
|
6 | + |
|
7 | + class LayoutHelper extends AppHelper { |
|
8 | + |
|
9 | + public $helpers = [ |
|
10 | + 'Html' |
|
11 | + ]; |
|
12 | + |
|
13 | + protected $_themeImgUrl = null; |
|
14 | + |
|
15 | + public function beforeRender($viewFile) { |
|
16 | + $this->_themeImgUrl = $this->request->webroot . 'theme' . DS . $this->theme . |
|
17 | + DS . Configure::read('App.imageBaseUrl'); |
|
18 | + } |
|
19 | + |
|
20 | + public function beforeLayout($layoutFile) { |
|
21 | + if (Configure::read('debug')) { |
|
22 | + $stylesheets[] = 'stylesheets/cake.css'; |
|
23 | + } |
|
24 | + if (!empty($stylesheets)) { |
|
25 | + $this->Html->css($stylesheets, null, ['inline' => false]); |
|
26 | + } |
|
27 | + } |
|
28 | + |
|
29 | + public function jQueryTag() { |
|
30 | + $url = 'dist/'; |
|
31 | + $name = 'jquery'; |
|
32 | + if ((int)Configure::read('debug') === 0) { |
|
33 | + $name = $name . '.min'; |
|
34 | + } |
|
35 | + return $this->Html->script($this->Html->assetUrl($url . $name, |
|
36 | + ['ext' => '.js', 'fullBase' => true])); |
|
37 | + } |
|
38 | + |
|
39 | + /** |
|
40 | + * Output link to Android touch icon |
|
41 | + */ |
|
42 | + public function androidTouchIcon($size, array $options = []) { |
|
43 | + return $this->_touchIcon($size, |
|
44 | + $options + ['rel' => 'shortcut icon']); |
|
45 | + } |
|
46 | + |
|
47 | + /** |
|
48 | + * Output link to iOS touch icon |
|
49 | + */ |
|
50 | + public function appleTouchIcon($size, array $options = []) { |
|
51 | + return $this->_touchIcon($size, $options); |
|
52 | + } |
|
53 | + |
|
54 | + /** |
|
55 | + * Output tile info for Windows 8. |
|
56 | + * |
|
57 | + * @param array $size unused |
|
58 | + * @param array $options |
|
59 | + * - 'basename' (default: app-icon) |
|
60 | + * - 'color' Background color for tile. |
|
61 | + * - 'title' Title displayed on tile. |
|
62 | + * |
|
63 | + * @return string |
|
64 | + */ |
|
65 | + public function msTouchIcon(array $size = [], array $options = []) { |
|
66 | + $options += [ |
|
67 | + 'baseName' => 'app-icon', |
|
68 | + 'color' => null, |
|
69 | + 'title' => Configure::read('Saito.Settings.forum_name') |
|
70 | + ]; |
|
71 | + $html = []; |
|
72 | + $html[] = '<meta name="application-name" content="' . h($options['title']) . '"/>'; |
|
73 | + if (isset($options['color'])) { |
|
74 | + $html[] = '<meta name="msapplication-TileColor" content="' . $options['color'] . '"/>'; |
|
75 | + } |
|
76 | + |
|
77 | + $_basename = $options['baseName']; |
|
78 | + $url = "{$this->_themeImgUrl}{$_basename}.png"; |
|
79 | + $html[] = '<meta name="msapplication-TileImage" content="' . $url . '"/>'; |
|
80 | + return implode("\n", $html); |
|
81 | + } |
|
82 | + |
|
83 | + /** |
|
84 | + * Output link to touch icon |
|
85 | + * |
|
86 | + * Files must be placed in <theme>/webroot/img/<baseName>-<size>x<size>.png |
|
87 | + * |
|
88 | + * @param mixed $size integer or array with integer |
|
89 | + * @param array $options |
|
90 | + * `baseName` (default: 'app-icon') |
|
91 | + * `precomposed` adds '-precomposed' to baseName (default: false) |
|
92 | + * `rel` (default: 'apple-touch-icon') |
|
93 | + * `size` outputs "size"-attribute (default: true) |
|
94 | + * @return string |
|
95 | + */ |
|
96 | + protected function _touchIcon($size, array $options = []) { |
|
97 | + if (is_array($size)) { |
|
98 | + $_out = ''; |
|
99 | + foreach ($size as $s) { |
|
100 | + $_out .= $this->appleTouchIcon($s, $options); |
|
101 | + } |
|
102 | + return $_out; |
|
103 | + } |
|
104 | + |
|
105 | + $_defaults = [ |
|
106 | + 'baseName' => 'app-icon', |
|
107 | + 'precomposed' => false, |
|
108 | + 'rel' => 'apple-touch-icon', |
|
109 | + 'size' => true |
|
110 | + ]; |
|
111 | + $options += $_defaults; |
|
112 | + |
|
113 | + $_xSize = "{$size}x{$size}"; |
|
114 | + |
|
115 | + $_basename = $options['baseName']; |
|
116 | + if ($options['precomposed']) { |
|
117 | + $_basename .= '-precomposed'; |
|
118 | + } |
|
119 | + $_filename = "{$_basename}-{$_xSize}.png"; |
|
120 | + |
|
121 | + $url = "{$this->_themeImgUrl}{$_filename}"; |
|
122 | + |
|
123 | + $_out = "<link rel=\"{$options['rel']}\" "; |
|
124 | + if ($options['size']) { |
|
125 | + $_out .= "size=\"{$_xSize}\" "; |
|
126 | + } |
|
127 | + $_out .= "href=\"{$url}\">"; |
|
128 | + return $_out; |
|
129 | + } |
|
130 | + |
|
131 | + /** |
|
132 | + * Generates page heading html |
|
133 | + * |
|
134 | + * @param string $heading |
|
135 | + * @param string $tag |
|
136 | + * @return string |
|
137 | + */ |
|
138 | + public function pageHeading($heading, $tag = 'h1') { |
|
139 | + return $this->Html->tag($tag, |
|
140 | + $heading, |
|
141 | + ['class' => 'pageHeading', 'escape' => true]); |
|
142 | + } |
|
143 | + |
|
144 | + /** |
|
145 | + * Generates intoText tag |
|
146 | + * |
|
147 | + * @param string $content |
|
148 | + * @return string |
|
149 | + */ |
|
150 | + public function infoText($content) { |
|
151 | + return $this->Html->tag('span', $content, ['class' => 'infoText']); |
|
152 | + } |
|
153 | + |
|
154 | + public function textWithIcon($text, $icon) { |
|
155 | + return <<<EOF |
|
156 | 156 | <i class="saito-icon fa fa-$icon"></i> |
157 | 157 | <span class="saito-icon-text">$text</span> |
158 | 158 | EOF; |
159 | - } |
|
160 | - |
|
161 | - public function dropdownMenuButton(array $menuItems, array $options = []) { |
|
162 | - $options += ['class' => '']; |
|
163 | - $_divider = '<li class="dropdown-divider"></li>'; |
|
164 | - $_menu = ''; |
|
165 | - foreach ($menuItems as $_menuItem) { |
|
166 | - if ($_menuItem === 'divider') { |
|
167 | - $_menu .= $_divider; |
|
168 | - } else { |
|
169 | - $_menu .= "<li>$_menuItem</li>"; |
|
170 | - } |
|
171 | - } |
|
172 | - $_id = AppHelper::tagId(); |
|
173 | - $_button = $this->Html->tag( |
|
174 | - 'button', |
|
175 | - '<i class="fa fa-wrench"></i> <i class="fa fa-caret-down"></i>', |
|
176 | - $options + [ |
|
177 | - 'escape' => false, |
|
178 | - 'onclick' => "$(this).dropdown('attach', '#d$_id');" |
|
179 | - ]); |
|
180 | - $_out = <<<EOF |
|
159 | + } |
|
160 | + |
|
161 | + public function dropdownMenuButton(array $menuItems, array $options = []) { |
|
162 | + $options += ['class' => '']; |
|
163 | + $_divider = '<li class="dropdown-divider"></li>'; |
|
164 | + $_menu = ''; |
|
165 | + foreach ($menuItems as $_menuItem) { |
|
166 | + if ($_menuItem === 'divider') { |
|
167 | + $_menu .= $_divider; |
|
168 | + } else { |
|
169 | + $_menu .= "<li>$_menuItem</li>"; |
|
170 | + } |
|
171 | + } |
|
172 | + $_id = AppHelper::tagId(); |
|
173 | + $_button = $this->Html->tag( |
|
174 | + 'button', |
|
175 | + '<i class="fa fa-wrench"></i> <i class="fa fa-caret-down"></i>', |
|
176 | + $options + [ |
|
177 | + 'escape' => false, |
|
178 | + 'onclick' => "$(this).dropdown('attach', '#d$_id');" |
|
179 | + ]); |
|
180 | + $_out = <<<EOF |
|
181 | 181 | $_button |
182 | 182 | <div id="d$_id" class="dropdown-relative dropdown dropdown-tip"> |
183 | 183 | <ul class="dropdown-menu"> |
@@ -185,106 +185,106 @@ discard block |
||
185 | 185 | </ul> |
186 | 186 | </div> |
187 | 187 | EOF; |
188 | - return $_out; |
|
189 | - } |
|
190 | - |
|
191 | - public function panelHeading($content, array $options = []) { |
|
192 | - $options += [ |
|
193 | - 'class' => 'panel-heading', |
|
194 | - 'escape' => true, |
|
195 | - 'pageHeading' => false, |
|
196 | - 'tag' => 'h2' |
|
197 | - ]; |
|
198 | - if ($options['pageHeading']) { |
|
199 | - $options['class'] .= ' pageTitle'; |
|
200 | - $options['tag'] = 'h1'; |
|
201 | - } |
|
202 | - if (is_string($content)) { |
|
203 | - $content = ['middle' => $content]; |
|
204 | - } |
|
205 | - |
|
206 | - if ($options['escape']) { |
|
207 | - foreach ($content as $k => $v) { |
|
208 | - $content[$k] = h($v); |
|
209 | - } |
|
210 | - } |
|
211 | - |
|
212 | - $content['middle'] = "<{$options['tag']}>{$content['middle']}</{$options['tag']}>"; |
|
213 | - |
|
214 | - $options['escape'] = false; |
|
215 | - return $this->heading($content, $options); |
|
216 | - } |
|
217 | - |
|
218 | - public function heading($content, array $options = []) { |
|
219 | - $options += ['class' => '', 'escape' => true]; |
|
220 | - if (is_string($content)) { |
|
221 | - $_content = ['middle' => $content]; |
|
222 | - } else { |
|
223 | - $_content = $content; |
|
224 | - } |
|
225 | - $_content += ['first' => '', 'middle' => '', 'last' => '']; |
|
226 | - $out = ''; |
|
227 | - foreach (['first', 'middle', 'last'] as $key) { |
|
228 | - $out .= '<div class="heading-3-' . $key . '">'; |
|
229 | - $out .= $options['escape'] ? h($_content[$key]) : $_content[$key]; |
|
230 | - $out .= '</div>'; |
|
231 | - } |
|
232 | - return "<div class=\"{$options['class']} heading-3\">$out</div>"; |
|
233 | - } |
|
234 | - |
|
235 | - public function linkToUserProfile($user, ForumsUserInterface $CurrentUser) { |
|
236 | - if ($CurrentUser->isLoggedIn()) { |
|
237 | - return $this->Html->link($user['username'], |
|
238 | - '/users/view/' . $user['id']); |
|
239 | - } else { |
|
240 | - return h($user['username']); |
|
241 | - } |
|
242 | - } |
|
243 | - |
|
244 | - /** |
|
245 | - * creates a navigation link for the navigation bar |
|
246 | - * |
|
247 | - * @param $content link content |
|
248 | - * @param $url link url |
|
249 | - * @param array $options allows options as HtmlHelper::link |
|
250 | - * - 'class' a CSS class to apply to the navbar item |
|
251 | - * - 'position' [left]|center|right |
|
252 | - * @return string navigation link |
|
253 | - */ |
|
254 | - public function navbarItem($content, $url, array $options = []) { |
|
255 | - $defaults = [ |
|
256 | - 'class' => 'navbar-item', |
|
257 | - 'position' => 'left' |
|
258 | - ]; |
|
259 | - $class = ''; |
|
260 | - if (isset($options['class'])) { |
|
261 | - $class = $options['class']; |
|
262 | - unset($options['class']); |
|
263 | - } |
|
264 | - $options += $defaults; |
|
265 | - |
|
266 | - $options['class'] .= " {$options['position']} $class"; |
|
267 | - unset($class, $options['position']); |
|
268 | - |
|
269 | - return $this->Html->link($content, $url, $options); |
|
270 | - } |
|
271 | - |
|
272 | - public function navbarBack($url = null, $title = null, $options = []) { |
|
273 | - if ($title === null) { |
|
274 | - if ($url === null) { |
|
275 | - $title = __('back_to_forum_linkname'); |
|
276 | - } else { |
|
277 | - $title = __('Back'); |
|
278 | - } |
|
279 | - } |
|
280 | - |
|
281 | - if ($url === null) { |
|
282 | - $url = '/'; |
|
283 | - } |
|
284 | - $options += ['escape' => false]; |
|
285 | - $content = $this->textWithIcon(h($title), 'arrow-left'); |
|
286 | - |
|
287 | - return $this->navbarItem($content, $url, $options); |
|
288 | - } |
|
289 | - |
|
290 | - } |
|
188 | + return $_out; |
|
189 | + } |
|
190 | + |
|
191 | + public function panelHeading($content, array $options = []) { |
|
192 | + $options += [ |
|
193 | + 'class' => 'panel-heading', |
|
194 | + 'escape' => true, |
|
195 | + 'pageHeading' => false, |
|
196 | + 'tag' => 'h2' |
|
197 | + ]; |
|
198 | + if ($options['pageHeading']) { |
|
199 | + $options['class'] .= ' pageTitle'; |
|
200 | + $options['tag'] = 'h1'; |
|
201 | + } |
|
202 | + if (is_string($content)) { |
|
203 | + $content = ['middle' => $content]; |
|
204 | + } |
|
205 | + |
|
206 | + if ($options['escape']) { |
|
207 | + foreach ($content as $k => $v) { |
|
208 | + $content[$k] = h($v); |
|
209 | + } |
|
210 | + } |
|
211 | + |
|
212 | + $content['middle'] = "<{$options['tag']}>{$content['middle']}</{$options['tag']}>"; |
|
213 | + |
|
214 | + $options['escape'] = false; |
|
215 | + return $this->heading($content, $options); |
|
216 | + } |
|
217 | + |
|
218 | + public function heading($content, array $options = []) { |
|
219 | + $options += ['class' => '', 'escape' => true]; |
|
220 | + if (is_string($content)) { |
|
221 | + $_content = ['middle' => $content]; |
|
222 | + } else { |
|
223 | + $_content = $content; |
|
224 | + } |
|
225 | + $_content += ['first' => '', 'middle' => '', 'last' => '']; |
|
226 | + $out = ''; |
|
227 | + foreach (['first', 'middle', 'last'] as $key) { |
|
228 | + $out .= '<div class="heading-3-' . $key . '">'; |
|
229 | + $out .= $options['escape'] ? h($_content[$key]) : $_content[$key]; |
|
230 | + $out .= '</div>'; |
|
231 | + } |
|
232 | + return "<div class=\"{$options['class']} heading-3\">$out</div>"; |
|
233 | + } |
|
234 | + |
|
235 | + public function linkToUserProfile($user, ForumsUserInterface $CurrentUser) { |
|
236 | + if ($CurrentUser->isLoggedIn()) { |
|
237 | + return $this->Html->link($user['username'], |
|
238 | + '/users/view/' . $user['id']); |
|
239 | + } else { |
|
240 | + return h($user['username']); |
|
241 | + } |
|
242 | + } |
|
243 | + |
|
244 | + /** |
|
245 | + * creates a navigation link for the navigation bar |
|
246 | + * |
|
247 | + * @param $content link content |
|
248 | + * @param $url link url |
|
249 | + * @param array $options allows options as HtmlHelper::link |
|
250 | + * - 'class' a CSS class to apply to the navbar item |
|
251 | + * - 'position' [left]|center|right |
|
252 | + * @return string navigation link |
|
253 | + */ |
|
254 | + public function navbarItem($content, $url, array $options = []) { |
|
255 | + $defaults = [ |
|
256 | + 'class' => 'navbar-item', |
|
257 | + 'position' => 'left' |
|
258 | + ]; |
|
259 | + $class = ''; |
|
260 | + if (isset($options['class'])) { |
|
261 | + $class = $options['class']; |
|
262 | + unset($options['class']); |
|
263 | + } |
|
264 | + $options += $defaults; |
|
265 | + |
|
266 | + $options['class'] .= " {$options['position']} $class"; |
|
267 | + unset($class, $options['position']); |
|
268 | + |
|
269 | + return $this->Html->link($content, $url, $options); |
|
270 | + } |
|
271 | + |
|
272 | + public function navbarBack($url = null, $title = null, $options = []) { |
|
273 | + if ($title === null) { |
|
274 | + if ($url === null) { |
|
275 | + $title = __('back_to_forum_linkname'); |
|
276 | + } else { |
|
277 | + $title = __('Back'); |
|
278 | + } |
|
279 | + } |
|
280 | + |
|
281 | + if ($url === null) { |
|
282 | + $url = '/'; |
|
283 | + } |
|
284 | + $options += ['escape' => false]; |
|
285 | + $content = $this->textWithIcon(h($title), 'arrow-left'); |
|
286 | + |
|
287 | + return $this->navbarItem($content, $url, $options); |
|
288 | + } |
|
289 | + |
|
290 | + } |
@@ -40,6 +40,9 @@ |
||
40 | 40 | return $prepared; |
41 | 41 | } |
42 | 42 | |
43 | + /** |
|
44 | + * @param integer $lastId |
|
45 | + */ |
|
43 | 46 | protected function _readCache($lastId) { |
44 | 47 | $cache = Cache::read($this->_cacheKey); |
45 | 48 | if ($cache && $cache['lastId'] === $lastId) { |
@@ -15,7 +15,7 @@ discard block |
||
15 | 15 | if (empty($shouts)) { |
16 | 16 | return []; |
17 | 17 | } |
18 | - $lastId = (int)$shouts[0]['Shout']['id']; |
|
18 | + $lastId = (int) $shouts[0]['Shout']['id']; |
|
19 | 19 | $cache = $this->_readCache($lastId); |
20 | 20 | if ($cache) { |
21 | 21 | return $cache; |
@@ -24,14 +24,14 @@ discard block |
||
24 | 24 | $prepared = []; |
25 | 25 | foreach ($shouts as $shout) { |
26 | 26 | $prepared[] = [ |
27 | - 'id' => (int)$shout['Shout']['id'], |
|
27 | + 'id' => (int) $shout['Shout']['id'], |
|
28 | 28 | 'time' => $this->Api->mysqlTimestampToIso($shout['Shout']['time']), |
29 | 29 | 'text' => $shout['Shout']['text'], |
30 | 30 | 'html' => $this->Parser->parse( |
31 | 31 | $shout['Shout']['text'], |
32 | 32 | ['multimedia' => false, 'wrap' => false] |
33 | 33 | ), |
34 | - 'user_id' => (int)$shout['Shout']['user_id'], |
|
34 | + 'user_id' => (int) $shout['Shout']['user_id'], |
|
35 | 35 | 'user_name' => $shout['Shout']['username'] |
36 | 36 | ]; |
37 | 37 | } |
@@ -1,62 +1,62 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - App::uses('AppHelper', 'View/Helper'); |
|
4 | - |
|
5 | - class ShoutsHelper extends AppHelper { |
|
6 | - |
|
7 | - public $helpers = [ |
|
8 | - 'Api.Api', |
|
9 | - 'Parser' |
|
10 | - ]; |
|
11 | - |
|
12 | - protected $_cacheKey = 'Saito.Shouts.prepared'; |
|
13 | - |
|
14 | - public function prepare($shouts) { |
|
15 | - if (empty($shouts)) { |
|
16 | - return []; |
|
17 | - } |
|
18 | - $lastId = (int)$shouts[0]['Shout']['id']; |
|
19 | - $cache = $this->_readCache($lastId); |
|
20 | - if ($cache) { |
|
21 | - return $cache; |
|
22 | - } |
|
23 | - |
|
24 | - $prepared = []; |
|
25 | - foreach ($shouts as $shout) { |
|
26 | - $prepared[] = [ |
|
27 | - 'id' => (int)$shout['Shout']['id'], |
|
28 | - 'time' => $this->Api->mysqlTimestampToIso($shout['Shout']['time']), |
|
29 | - 'text' => $shout['Shout']['text'], |
|
30 | - 'html' => $this->Parser->parse( |
|
31 | - $shout['Shout']['text'], |
|
32 | - ['multimedia' => false, 'wrap' => false] |
|
33 | - ), |
|
34 | - 'user_id' => (int)$shout['Shout']['user_id'], |
|
35 | - 'user_name' => $shout['Shout']['username'] |
|
36 | - ]; |
|
37 | - } |
|
38 | - |
|
39 | - $this->_writeCache($prepared); |
|
40 | - return $prepared; |
|
41 | - } |
|
42 | - |
|
43 | - protected function _readCache($lastId) { |
|
44 | - $cache = Cache::read($this->_cacheKey); |
|
45 | - if ($cache && $cache['lastId'] === $lastId) { |
|
46 | - return $cache['data']; |
|
47 | - } |
|
48 | - return false; |
|
49 | - } |
|
50 | - |
|
51 | - protected function _writeCache($prepared) { |
|
52 | - $lastId = $prepared[0]['id']; |
|
53 | - Cache::write( |
|
54 | - $this->_cacheKey, |
|
55 | - [ |
|
56 | - 'lastId' => $lastId, |
|
57 | - 'data' => $prepared |
|
58 | - ] |
|
59 | - ); |
|
60 | - } |
|
61 | - |
|
62 | - } |
|
63 | 3 | \ No newline at end of file |
4 | + App::uses('AppHelper', 'View/Helper'); |
|
5 | + |
|
6 | + class ShoutsHelper extends AppHelper { |
|
7 | + |
|
8 | + public $helpers = [ |
|
9 | + 'Api.Api', |
|
10 | + 'Parser' |
|
11 | + ]; |
|
12 | + |
|
13 | + protected $_cacheKey = 'Saito.Shouts.prepared'; |
|
14 | + |
|
15 | + public function prepare($shouts) { |
|
16 | + if (empty($shouts)) { |
|
17 | + return []; |
|
18 | + } |
|
19 | + $lastId = (int)$shouts[0]['Shout']['id']; |
|
20 | + $cache = $this->_readCache($lastId); |
|
21 | + if ($cache) { |
|
22 | + return $cache; |
|
23 | + } |
|
24 | + |
|
25 | + $prepared = []; |
|
26 | + foreach ($shouts as $shout) { |
|
27 | + $prepared[] = [ |
|
28 | + 'id' => (int)$shout['Shout']['id'], |
|
29 | + 'time' => $this->Api->mysqlTimestampToIso($shout['Shout']['time']), |
|
30 | + 'text' => $shout['Shout']['text'], |
|
31 | + 'html' => $this->Parser->parse( |
|
32 | + $shout['Shout']['text'], |
|
33 | + ['multimedia' => false, 'wrap' => false] |
|
34 | + ), |
|
35 | + 'user_id' => (int)$shout['Shout']['user_id'], |
|
36 | + 'user_name' => $shout['Shout']['username'] |
|
37 | + ]; |
|
38 | + } |
|
39 | + |
|
40 | + $this->_writeCache($prepared); |
|
41 | + return $prepared; |
|
42 | + } |
|
43 | + |
|
44 | + protected function _readCache($lastId) { |
|
45 | + $cache = Cache::read($this->_cacheKey); |
|
46 | + if ($cache && $cache['lastId'] === $lastId) { |
|
47 | + return $cache['data']; |
|
48 | + } |
|
49 | + return false; |
|
50 | + } |
|
51 | + |
|
52 | + protected function _writeCache($prepared) { |
|
53 | + $lastId = $prepared[0]['id']; |
|
54 | + Cache::write( |
|
55 | + $this->_cacheKey, |
|
56 | + [ |
|
57 | + 'lastId' => $lastId, |
|
58 | + 'data' => $prepared |
|
59 | + ] |
|
60 | + ); |
|
61 | + } |
|
62 | + |
|
63 | + } |
|
64 | 64 | \ No newline at end of file |
@@ -112,6 +112,9 @@ |
||
112 | 112 | return $_timeString; |
113 | 113 | } |
114 | 114 | |
115 | + /** |
|
116 | + * @param integer $timestamp |
|
117 | + */ |
|
115 | 118 | protected function _normal($timestamp) { |
116 | 119 | if ($timestamp > $this->_today || $timestamp > ($this->_now - 21600)) { |
117 | 120 | // today or in the last 6 hours |
@@ -56,9 +56,9 @@ discard block |
||
56 | 56 | $timeInTimezone = new DateTime('now', $timezone); |
57 | 57 | $timeDiffToUtc = $timeInTimezone->getOffset() / 3600; |
58 | 58 | $options[$groupTitle][$timeZoneTitle] = |
59 | - $timeZoneTitle . |
|
60 | - ' (' . $timeInTimezone->format('H:m') . |
|
61 | - '; ' . $timeDiffToUtc . ')'; |
|
59 | + $timeZoneTitle. |
|
60 | + ' ('.$timeInTimezone->format('H:m'). |
|
61 | + '; '.$timeDiffToUtc.')'; |
|
62 | 62 | endforeach; |
63 | 63 | endforeach; |
64 | 64 | |
@@ -118,7 +118,7 @@ discard block |
||
118 | 118 | $time = strftime("%H:%M", $timestamp); |
119 | 119 | } elseif ($timestamp > ($this->_today - 64800)) { |
120 | 120 | // yesterday but in the last 18 hours |
121 | - $time = __('yesterday') . ' ' . strftime("%H:%M", $timestamp); |
|
121 | + $time = __('yesterday').' '.strftime("%H:%M", $timestamp); |
|
122 | 122 | } else { |
123 | 123 | // yesterday and 18 hours and older |
124 | 124 | $time = strftime("%d.%m.%Y", $timestamp); |
@@ -1,141 +1,141 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - App::uses('AppHelper', 'View/Helper'); |
|
4 | - |
|
5 | - class TimeHHelper extends AppHelper { |
|
6 | - |
|
7 | - public $helpers = array( |
|
8 | - 'Time' |
|
9 | - ); |
|
10 | - |
|
11 | - protected static $_timezoneGroups = array( |
|
12 | - 'UTC' => DateTimeZone::UTC, |
|
13 | - 'Africa' => DateTimeZone::AFRICA, |
|
14 | - 'America' => DateTimeZone::AMERICA, |
|
15 | - 'Antarctica' => DateTimeZone::ANTARCTICA, |
|
16 | - 'Asia' => DateTimeZone::ASIA, |
|
17 | - 'Atlantic' => DateTimeZone::ATLANTIC, |
|
18 | - 'Europe' => DateTimeZone::EUROPE, |
|
19 | - 'Indian' => DateTimeZone::INDIAN, |
|
20 | - 'Pacific' => DateTimeZone::PACIFIC, |
|
21 | - ); |
|
22 | - |
|
23 | - protected $_now = false; |
|
24 | - |
|
25 | - protected $_today = false; |
|
26 | - |
|
27 | - protected $_start = false; |
|
28 | - |
|
29 | - protected $_timeDiffToUtc = 0; |
|
30 | - |
|
31 | - public function beforeRender($viewFile) { |
|
32 | - parent::beforeRender($viewFile); |
|
33 | - $this->_now = time(); |
|
34 | - $this->_today = mktime(0, 0, 0); |
|
35 | - |
|
36 | - // @td reimplement unsing Cake 2.2 CakeTime (?) |
|
37 | - $_timezoneSettings = Configure::read('Saito.Settings.timezone'); |
|
38 | - if (empty($_timezoneSettings)) { |
|
39 | - $_timezoneSettings = 'UTC'; |
|
40 | - } |
|
41 | - $timezone = new DateTimeZone($_timezoneSettings); |
|
42 | - $timeInTimezone = new DateTime('now', $timezone); |
|
43 | - $timeOnServer = new DateTime('now'); |
|
44 | - $this->_timeDiffToUtc = $timeOnServer->getOffset() - $timeInTimezone->getOffset(); |
|
45 | - } |
|
46 | - |
|
47 | - public function timezoneOptions() { |
|
48 | - $options = array( ); |
|
49 | - |
|
50 | - $allTimeZonesValues = DateTimeZone::listIdentifiers(DateTimeZone::ALL); |
|
51 | - |
|
52 | - foreach (self::$_timezoneGroups as $groupTitle => $groupId) : |
|
53 | - $timeZones = DateTimeZone::listIdentifiers($groupId); |
|
54 | - foreach ($timeZones as $timeZoneTitle) : |
|
55 | - $timezone = new DateTimeZone($timeZoneTitle); |
|
56 | - $timeInTimezone = new DateTime('now', $timezone); |
|
57 | - $timeDiffToUtc = $timeInTimezone->getOffset() / 3600; |
|
58 | - $options[$groupTitle][$timeZoneTitle] = |
|
59 | - $timeZoneTitle . |
|
60 | - ' (' . $timeInTimezone->format('H:m') . |
|
61 | - '; ' . $timeDiffToUtc . ')'; |
|
62 | - endforeach; |
|
63 | - endforeach; |
|
64 | - |
|
65 | - return $options; |
|
66 | - } |
|
67 | - |
|
68 | - /** |
|
69 | - * outputs a formatted time string |
|
70 | - * |
|
71 | - * #@td user/admin time zone diff and admin format settings |
|
72 | - * |
|
73 | - * @param $timestamp |
|
74 | - * @param string $format |
|
75 | - * @param array $options |
|
76 | - * @return string |
|
77 | - */ |
|
78 | - public function formatTime($timestamp, $format = 'normal', array $options = []) { |
|
79 | - // Stopwatch::start('formatTime'); |
|
80 | - $options += [ |
|
81 | - 'wrap' => true |
|
82 | - ]; |
|
83 | - |
|
84 | - $timestamp = strtotime($timestamp) - $this->_timeDiffToUtc; |
|
85 | - |
|
86 | - if ($format === 'normal' || empty($format)) { |
|
87 | - $_timeString = $this->_normal($timestamp); |
|
88 | - } elseif ($format === 'short') { |
|
89 | - $_timeString = date('d.m.', $timestamp); |
|
90 | - } elseif ($format === 'eng') { |
|
91 | - $_timeString = strftime('%F %T', $timestamp); |
|
92 | - } else { |
|
93 | - $_timeString = strftime($format, $timestamp); |
|
94 | - } |
|
95 | - |
|
96 | - if ($options['wrap']) { |
|
97 | - $attributes = [ |
|
98 | - 'datetime' => date(DATE_RFC3339, $timestamp), |
|
99 | - 'title' => strftime("%F %T", $timestamp) |
|
100 | - ]; |
|
101 | - if (is_array($options['wrap'])) { |
|
102 | - $attributes += $options['wrap']; |
|
103 | - } |
|
104 | - foreach ($attributes as $attribute => $value) { |
|
105 | - $attributes[$attribute] = "$attribute=\"$value\""; |
|
106 | - } |
|
107 | - $attributes = implode(' ', $attributes); |
|
108 | - $_timeString = "<time $attributes>$_timeString</time>"; |
|
109 | - } |
|
110 | - |
|
111 | - // Stopwatch::stop('formatTime'); |
|
112 | - return $_timeString; |
|
113 | - } |
|
114 | - |
|
115 | - protected function _normal($timestamp) { |
|
116 | - if ($timestamp > $this->_today || $timestamp > ($this->_now - 21600)) { |
|
117 | - // today or in the last 6 hours |
|
118 | - $time = strftime("%H:%M", $timestamp); |
|
119 | - } elseif ($timestamp > ($this->_today - 64800)) { |
|
120 | - // yesterday but in the last 18 hours |
|
121 | - $time = __('yesterday') . ' ' . strftime("%H:%M", $timestamp); |
|
122 | - } else { |
|
123 | - // yesterday and 18 hours and older |
|
124 | - $time = strftime("%d.%m.%Y", $timestamp); |
|
125 | - } |
|
126 | - |
|
127 | - return $time; |
|
128 | - } |
|
129 | - |
|
130 | - public function mysqlTimestampToIso($date) { |
|
131 | - if ($date === null) { |
|
132 | - return null; |
|
133 | - } |
|
134 | - $unixTimeStamp = strtotime($date); |
|
135 | - if ($unixTimeStamp < 0) { |
|
136 | - $unixTimeStamp = 0; |
|
137 | - } |
|
138 | - return date('c', $unixTimeStamp); |
|
139 | - } |
|
140 | - |
|
141 | - } |
|
3 | + App::uses('AppHelper', 'View/Helper'); |
|
4 | + |
|
5 | + class TimeHHelper extends AppHelper { |
|
6 | + |
|
7 | + public $helpers = array( |
|
8 | + 'Time' |
|
9 | + ); |
|
10 | + |
|
11 | + protected static $_timezoneGroups = array( |
|
12 | + 'UTC' => DateTimeZone::UTC, |
|
13 | + 'Africa' => DateTimeZone::AFRICA, |
|
14 | + 'America' => DateTimeZone::AMERICA, |
|
15 | + 'Antarctica' => DateTimeZone::ANTARCTICA, |
|
16 | + 'Asia' => DateTimeZone::ASIA, |
|
17 | + 'Atlantic' => DateTimeZone::ATLANTIC, |
|
18 | + 'Europe' => DateTimeZone::EUROPE, |
|
19 | + 'Indian' => DateTimeZone::INDIAN, |
|
20 | + 'Pacific' => DateTimeZone::PACIFIC, |
|
21 | + ); |
|
22 | + |
|
23 | + protected $_now = false; |
|
24 | + |
|
25 | + protected $_today = false; |
|
26 | + |
|
27 | + protected $_start = false; |
|
28 | + |
|
29 | + protected $_timeDiffToUtc = 0; |
|
30 | + |
|
31 | + public function beforeRender($viewFile) { |
|
32 | + parent::beforeRender($viewFile); |
|
33 | + $this->_now = time(); |
|
34 | + $this->_today = mktime(0, 0, 0); |
|
35 | + |
|
36 | + // @td reimplement unsing Cake 2.2 CakeTime (?) |
|
37 | + $_timezoneSettings = Configure::read('Saito.Settings.timezone'); |
|
38 | + if (empty($_timezoneSettings)) { |
|
39 | + $_timezoneSettings = 'UTC'; |
|
40 | + } |
|
41 | + $timezone = new DateTimeZone($_timezoneSettings); |
|
42 | + $timeInTimezone = new DateTime('now', $timezone); |
|
43 | + $timeOnServer = new DateTime('now'); |
|
44 | + $this->_timeDiffToUtc = $timeOnServer->getOffset() - $timeInTimezone->getOffset(); |
|
45 | + } |
|
46 | + |
|
47 | + public function timezoneOptions() { |
|
48 | + $options = array( ); |
|
49 | + |
|
50 | + $allTimeZonesValues = DateTimeZone::listIdentifiers(DateTimeZone::ALL); |
|
51 | + |
|
52 | + foreach (self::$_timezoneGroups as $groupTitle => $groupId) : |
|
53 | + $timeZones = DateTimeZone::listIdentifiers($groupId); |
|
54 | + foreach ($timeZones as $timeZoneTitle) : |
|
55 | + $timezone = new DateTimeZone($timeZoneTitle); |
|
56 | + $timeInTimezone = new DateTime('now', $timezone); |
|
57 | + $timeDiffToUtc = $timeInTimezone->getOffset() / 3600; |
|
58 | + $options[$groupTitle][$timeZoneTitle] = |
|
59 | + $timeZoneTitle . |
|
60 | + ' (' . $timeInTimezone->format('H:m') . |
|
61 | + '; ' . $timeDiffToUtc . ')'; |
|
62 | + endforeach; |
|
63 | + endforeach; |
|
64 | + |
|
65 | + return $options; |
|
66 | + } |
|
67 | + |
|
68 | + /** |
|
69 | + * outputs a formatted time string |
|
70 | + * |
|
71 | + * #@td user/admin time zone diff and admin format settings |
|
72 | + * |
|
73 | + * @param $timestamp |
|
74 | + * @param string $format |
|
75 | + * @param array $options |
|
76 | + * @return string |
|
77 | + */ |
|
78 | + public function formatTime($timestamp, $format = 'normal', array $options = []) { |
|
79 | + // Stopwatch::start('formatTime'); |
|
80 | + $options += [ |
|
81 | + 'wrap' => true |
|
82 | + ]; |
|
83 | + |
|
84 | + $timestamp = strtotime($timestamp) - $this->_timeDiffToUtc; |
|
85 | + |
|
86 | + if ($format === 'normal' || empty($format)) { |
|
87 | + $_timeString = $this->_normal($timestamp); |
|
88 | + } elseif ($format === 'short') { |
|
89 | + $_timeString = date('d.m.', $timestamp); |
|
90 | + } elseif ($format === 'eng') { |
|
91 | + $_timeString = strftime('%F %T', $timestamp); |
|
92 | + } else { |
|
93 | + $_timeString = strftime($format, $timestamp); |
|
94 | + } |
|
95 | + |
|
96 | + if ($options['wrap']) { |
|
97 | + $attributes = [ |
|
98 | + 'datetime' => date(DATE_RFC3339, $timestamp), |
|
99 | + 'title' => strftime("%F %T", $timestamp) |
|
100 | + ]; |
|
101 | + if (is_array($options['wrap'])) { |
|
102 | + $attributes += $options['wrap']; |
|
103 | + } |
|
104 | + foreach ($attributes as $attribute => $value) { |
|
105 | + $attributes[$attribute] = "$attribute=\"$value\""; |
|
106 | + } |
|
107 | + $attributes = implode(' ', $attributes); |
|
108 | + $_timeString = "<time $attributes>$_timeString</time>"; |
|
109 | + } |
|
110 | + |
|
111 | + // Stopwatch::stop('formatTime'); |
|
112 | + return $_timeString; |
|
113 | + } |
|
114 | + |
|
115 | + protected function _normal($timestamp) { |
|
116 | + if ($timestamp > $this->_today || $timestamp > ($this->_now - 21600)) { |
|
117 | + // today or in the last 6 hours |
|
118 | + $time = strftime("%H:%M", $timestamp); |
|
119 | + } elseif ($timestamp > ($this->_today - 64800)) { |
|
120 | + // yesterday but in the last 18 hours |
|
121 | + $time = __('yesterday') . ' ' . strftime("%H:%M", $timestamp); |
|
122 | + } else { |
|
123 | + // yesterday and 18 hours and older |
|
124 | + $time = strftime("%d.%m.%Y", $timestamp); |
|
125 | + } |
|
126 | + |
|
127 | + return $time; |
|
128 | + } |
|
129 | + |
|
130 | + public function mysqlTimestampToIso($date) { |
|
131 | + if ($date === null) { |
|
132 | + return null; |
|
133 | + } |
|
134 | + $unixTimeStamp = strtotime($date); |
|
135 | + if ($unixTimeStamp < 0) { |
|
136 | + $unixTimeStamp = 0; |
|
137 | + } |
|
138 | + return date('c', $unixTimeStamp); |
|
139 | + } |
|
140 | + |
|
141 | + } |
@@ -60,7 +60,7 @@ |
||
60 | 60 | * Translates user types |
61 | 61 | * |
62 | 62 | * @param $type |
63 | - * @return mixed |
|
63 | + * @return null|string |
|
64 | 64 | */ |
65 | 65 | public function type($type) { |
66 | 66 | // write out all __() strings for l10n |
@@ -53,7 +53,7 @@ discard block |
||
53 | 53 | } |
54 | 54 | } |
55 | 55 | |
56 | - return '<style type="text/css">' . implode(" ", $_styles) . '</style>'; |
|
56 | + return '<style type="text/css">'.implode(" ", $_styles).'</style>'; |
|
57 | 57 | } |
58 | 58 | |
59 | 59 | /** |
@@ -100,7 +100,7 @@ discard block |
||
100 | 100 | $out = $url; |
101 | 101 | if (is_string($url)) { |
102 | 102 | if (substr($url, 0, 4) == 'www.') { |
103 | - $url = 'http://' . $url; |
|
103 | + $url = 'http://'.$url; |
|
104 | 104 | } |
105 | 105 | if (substr($url, 0, 4) == 'http') { |
106 | 106 | $out = $this->Html->link( |
@@ -1,60 +1,60 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | |
3 | - use Saito\User\SaitoUser; |
|
4 | - |
|
5 | - App::uses('AppHelper', 'View/Helper'); |
|
6 | - |
|
7 | - class UserHHelper extends AppHelper { |
|
8 | - |
|
9 | - protected $_SaitoUser = null; |
|
10 | - |
|
11 | - public $helpers = array( |
|
12 | - 'Html', |
|
13 | - 'Session', |
|
14 | - ); |
|
15 | - |
|
16 | - public function beforeRender($viewFile) { |
|
17 | - parent::beforeRender($viewFile); |
|
18 | - $this->_SaitoUser = new SaitoUser(); |
|
19 | - } |
|
20 | - |
|
21 | - public function banned($isBanned) { |
|
22 | - $out = ''; |
|
23 | - if ($isBanned) : |
|
24 | - $out = '<i class="fa fa-ban fa-lg"></i>'; |
|
25 | - endif; |
|
26 | - return $out; |
|
27 | - } |
|
28 | - |
|
29 | - /** |
|
30 | - * generates CSS from user-preferences |
|
31 | - * |
|
32 | - * @param array $User |
|
33 | - * @return string |
|
34 | - */ |
|
35 | - public function generateCss(array $User) { |
|
36 | - $_styles = []; |
|
37 | - |
|
38 | - // colors |
|
39 | - $_cNew = $User['user_color_new_postings']; |
|
40 | - $_cOld = $User['user_color_old_postings']; |
|
41 | - $_cAct = $User['user_color_actual_posting']; |
|
42 | - |
|
43 | - $_aMetatags = ['', ':link', ':visited', ':hover', ':active']; |
|
44 | - foreach ($_aMetatags as $_aMetatag) { |
|
45 | - if (!empty($_cOld) && $_cOld !== '#') { |
|
46 | - $_styles[] = ".et-root .et$_aMetatag, .et-reply .et$_aMetatag { color: $_cOld; }"; |
|
47 | - } |
|
48 | - if (!empty($_cNew) && $_cNew !== '#') { |
|
49 | - $_styles[] = ".et-new .et$_aMetatag { color: $_cNew; }"; |
|
50 | - } |
|
51 | - if (!empty($_cAct) && $_cAct !== '#') { |
|
52 | - $_styles[] = ".et-current .et$_aMetatag { color: $_cAct; }"; |
|
53 | - } |
|
54 | - } |
|
55 | - |
|
56 | - return '<style type="text/css">' . implode(" ", $_styles) . '</style>'; |
|
57 | - } |
|
3 | + use Saito\User\SaitoUser; |
|
4 | + |
|
5 | + App::uses('AppHelper', 'View/Helper'); |
|
6 | + |
|
7 | + class UserHHelper extends AppHelper { |
|
8 | + |
|
9 | + protected $_SaitoUser = null; |
|
10 | + |
|
11 | + public $helpers = array( |
|
12 | + 'Html', |
|
13 | + 'Session', |
|
14 | + ); |
|
15 | + |
|
16 | + public function beforeRender($viewFile) { |
|
17 | + parent::beforeRender($viewFile); |
|
18 | + $this->_SaitoUser = new SaitoUser(); |
|
19 | + } |
|
20 | + |
|
21 | + public function banned($isBanned) { |
|
22 | + $out = ''; |
|
23 | + if ($isBanned) : |
|
24 | + $out = '<i class="fa fa-ban fa-lg"></i>'; |
|
25 | + endif; |
|
26 | + return $out; |
|
27 | + } |
|
28 | + |
|
29 | + /** |
|
30 | + * generates CSS from user-preferences |
|
31 | + * |
|
32 | + * @param array $User |
|
33 | + * @return string |
|
34 | + */ |
|
35 | + public function generateCss(array $User) { |
|
36 | + $_styles = []; |
|
37 | + |
|
38 | + // colors |
|
39 | + $_cNew = $User['user_color_new_postings']; |
|
40 | + $_cOld = $User['user_color_old_postings']; |
|
41 | + $_cAct = $User['user_color_actual_posting']; |
|
42 | + |
|
43 | + $_aMetatags = ['', ':link', ':visited', ':hover', ':active']; |
|
44 | + foreach ($_aMetatags as $_aMetatag) { |
|
45 | + if (!empty($_cOld) && $_cOld !== '#') { |
|
46 | + $_styles[] = ".et-root .et$_aMetatag, .et-reply .et$_aMetatag { color: $_cOld; }"; |
|
47 | + } |
|
48 | + if (!empty($_cNew) && $_cNew !== '#') { |
|
49 | + $_styles[] = ".et-new .et$_aMetatag { color: $_cNew; }"; |
|
50 | + } |
|
51 | + if (!empty($_cAct) && $_cAct !== '#') { |
|
52 | + $_styles[] = ".et-current .et$_aMetatag { color: $_cAct; }"; |
|
53 | + } |
|
54 | + } |
|
55 | + |
|
56 | + return '<style type="text/css">' . implode(" ", $_styles) . '</style>'; |
|
57 | + } |
|
58 | 58 | |
59 | 59 | /** |
60 | 60 | * Translates user types |
@@ -62,66 +62,66 @@ discard block |
||
62 | 62 | * @param $type |
63 | 63 | * @return mixed |
64 | 64 | */ |
65 | - public function type($type) { |
|
66 | - // write out all __() strings for l10n |
|
67 | - switch ($type): |
|
68 | - case 'user': |
|
69 | - return __('user.type.user'); |
|
70 | - case 'mod': |
|
71 | - return __('user.type.mod'); |
|
72 | - case 'admin': |
|
73 | - return __('user.type.admin'); |
|
74 | - endswitch; |
|
75 | - } |
|
76 | - |
|
77 | - /** |
|
78 | - * Creates link to user contact page with image |
|
79 | - * |
|
80 | - * @param $user |
|
81 | - * @return string |
|
82 | - */ |
|
83 | - public function contact($user) { |
|
84 | - $out = ''; |
|
85 | - if ($user['personal_messages'] && is_string($user['user_email'])) { |
|
86 | - $out = $this->Html->link( |
|
87 | - '<i class="fa fa-envelope-o fa-lg"></i>', |
|
88 | - ['controller' => 'contacts', 'action' => 'user', $user['id']], |
|
89 | - ['escape' => false]); |
|
90 | - } |
|
91 | - return $out; |
|
92 | - } |
|
65 | + public function type($type) { |
|
66 | + // write out all __() strings for l10n |
|
67 | + switch ($type): |
|
68 | + case 'user': |
|
69 | + return __('user.type.user'); |
|
70 | + case 'mod': |
|
71 | + return __('user.type.mod'); |
|
72 | + case 'admin': |
|
73 | + return __('user.type.admin'); |
|
74 | + endswitch; |
|
75 | + } |
|
76 | + |
|
77 | + /** |
|
78 | + * Creates link to user contact page with image |
|
79 | + * |
|
80 | + * @param $user |
|
81 | + * @return string |
|
82 | + */ |
|
83 | + public function contact($user) { |
|
84 | + $out = ''; |
|
85 | + if ($user['personal_messages'] && is_string($user['user_email'])) { |
|
86 | + $out = $this->Html->link( |
|
87 | + '<i class="fa fa-envelope-o fa-lg"></i>', |
|
88 | + ['controller' => 'contacts', 'action' => 'user', $user['id']], |
|
89 | + ['escape' => false]); |
|
90 | + } |
|
91 | + return $out; |
|
92 | + } |
|
93 | 93 | |
94 | 94 | /** |
95 | 95 | * Creates Homepage Links with Image from Url |
96 | 96 | * @param <type> $url |
97 | 97 | * @return <type> |
98 | 98 | */ |
99 | - public function homepage($url) { |
|
100 | - $out = $url; |
|
101 | - if (is_string($url)) { |
|
102 | - if (substr($url, 0, 4) == 'www.') { |
|
103 | - $url = 'http://' . $url; |
|
104 | - } |
|
105 | - if (substr($url, 0, 4) == 'http') { |
|
106 | - $out = $this->Html->link( |
|
107 | - '<i class="fa fa-home fa-lg"></i>', |
|
108 | - $url, |
|
109 | - array('escape' => false)); |
|
110 | - } else { |
|
111 | - $out = h($url); |
|
112 | - } |
|
113 | - } |
|
114 | - return $out; |
|
115 | - } |
|
116 | - |
|
117 | - public function isMod($user) { |
|
118 | - $this->_SaitoUser->setSettings($user); |
|
119 | - return $this->_SaitoUser->isMod($user); |
|
120 | - } |
|
121 | - |
|
122 | - public function isAdmin($user) { |
|
123 | - $this->_SaitoUser->setSettings($user); |
|
124 | - return $this->_SaitoUser->isAdmin($user); |
|
125 | - } |
|
126 | - |
|
127 | - } |
|
99 | + public function homepage($url) { |
|
100 | + $out = $url; |
|
101 | + if (is_string($url)) { |
|
102 | + if (substr($url, 0, 4) == 'www.') { |
|
103 | + $url = 'http://' . $url; |
|
104 | + } |
|
105 | + if (substr($url, 0, 4) == 'http') { |
|
106 | + $out = $this->Html->link( |
|
107 | + '<i class="fa fa-home fa-lg"></i>', |
|
108 | + $url, |
|
109 | + array('escape' => false)); |
|
110 | + } else { |
|
111 | + $out = h($url); |
|
112 | + } |
|
113 | + } |
|
114 | + return $out; |
|
115 | + } |
|
116 | + |
|
117 | + public function isMod($user) { |
|
118 | + $this->_SaitoUser->setSettings($user); |
|
119 | + return $this->_SaitoUser->isMod($user); |
|
120 | + } |
|
121 | + |
|
122 | + public function isAdmin($user) { |
|
123 | + $this->_SaitoUser->setSettings($user); |
|
124 | + return $this->_SaitoUser->isAdmin($user); |
|
125 | + } |
|
126 | + |
|
127 | + } |