This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace BootPress\Page; |
||
4 | |||
5 | use Symfony\Component\HttpFoundation\Request; |
||
6 | use Symfony\Component\HttpFoundation\Response; |
||
7 | use Symfony\Component\HttpFoundation\JsonResponse; |
||
8 | use Symfony\Component\HttpFoundation\RedirectResponse; |
||
9 | use Symfony\Component\HttpFoundation\Session\Session; |
||
10 | use Spartz\TextFormatter\TextFormatter; |
||
11 | use ParsedownExtra; // erusev/parsedown-extra |
||
12 | use URLify; // jbroadway/urlify |
||
13 | use AltoRouter; |
||
14 | |||
15 | class Component |
||
16 | { |
||
17 | |||
18 | private $request; |
||
19 | private $dir = array(); |
||
20 | private $url = array(); |
||
21 | private $html = array(); |
||
22 | private $data = array(); // meta, ico, apple, css, style, other, js, jquery, script |
||
23 | private $saved = array(); // managed in $this->save($name), and retrieved in $this->info($name) - for filters mainly |
||
24 | private $filters = array(); // managed in $this->filter() (public), and retrieved in $this->process() (private) |
||
25 | private $testing = false; // $this->send() exit's a Symfony Response if this is false |
||
26 | private static $instance; |
||
27 | private static $session; |
||
28 | |||
29 | /** |
||
30 | * This returns a singleton instance of the Page class so that you can access it anywhere. Passing parameters will only make a difference when calling it for the first time, unless you $overthrow it. |
||
31 | * |
||
32 | * @param array $url What you want your website's url to look like, and point to. |
||
33 | * |
||
34 | * - '**dir**' - The base directory your website exists in. We recommend that this be a root folder so that it is not publically accessible, but it can be if you're crazy. |
||
35 | * - '**base**' - The root url. If you specify this, then we will enforce it. If it starts with https (secured), then your website will be inaccessible via http (insecure). If you include a subdomain (eg. www) or not, it will be enforced. This way you don't have duplicate content issues, and know exactly how your website will be accessed. |
||
36 | * - '**suffix**' - What you want to come after all of your url (html) paths. The options are: '', '**\/**', '**.htm**', '**.html**', '**.shtml**', '**.phtml**', '**.php**', '**.asp**', '**.jsp**', '**.cgi**', '**.cfm**', and '**.pl**'. |
||
37 | * - '**chars**' - This lets you specify which characters are permitted within your URLs. You should restrict this to as few characters as possible. The default is '**a-z0-9~%.:_-**'. |
||
38 | * - '**testing**' - If you include and set this to anything, then any calls to ``$page->send()`` will not ``exit``. This enables us to unit test responses and not halt the script. |
||
39 | * |
||
40 | * @param object $request A Symfony Request object. |
||
41 | * @param false|mixed $overthrow If anything but false, then the parameters you pass will overthrow the previous ones submitted. This is especially useful when unit testing. |
||
42 | * |
||
43 | * @return object A singleton Page instance. |
||
44 | */ |
||
45 | 139 | public static function html(array $url = array(), Request $request = null, $overthrow = false) |
|
46 | { |
||
47 | 139 | if ($overthrow || null === static::$instance) { |
|
0 ignored issues
–
show
|
|||
48 | 39 | static::$instance = static::isolated($url, $request); |
|
0 ignored issues
–
show
Since
$instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $instance to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
49 | 39 | } |
|
50 | |||
51 | 139 | return static::$instance; |
|
0 ignored issues
–
show
Since
$instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $instance to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
52 | } |
||
53 | |||
54 | /** |
||
55 | * This returns an isolated instance of the Page class so you can use it for whatever. |
||
56 | * |
||
57 | * @param array $url The same as above. |
||
58 | * @param object $request A Symfony Request object. |
||
59 | * |
||
60 | * @return object An isolated instance of the Page class. |
||
61 | */ |
||
62 | 42 | public static function isolated(array $url = array(), Request $request = null) |
|
63 | { |
||
64 | 42 | extract(array_merge(array( |
|
0 ignored issues
–
show
|
|||
65 | 42 | 'dir' => null, |
|
66 | 42 | 'base' => null, |
|
67 | 42 | 'suffix' => null, |
|
68 | 42 | 'chars' => 'a-z0-9~%.:_-', |
|
69 | 42 | ), $url), EXTR_SKIP); |
|
70 | 42 | $enforce = (is_string($base)) ? true : false; |
|
71 | 42 | $page = new static(); |
|
72 | 42 | if (isset($testing)) $page->testing = $testing; // ie. $this->testing = $testing |
|
73 | 42 | $page->request = (is_null($request)) ? Request::createFromGlobals() : $request; |
|
74 | 42 | if (false === $folder = realpath($dir)) { |
|
75 | 1 | $folders = array(); |
|
76 | 1 | $base = realpath(''); |
|
77 | 1 | $dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $dir); |
|
78 | 1 | if (strstr($base, DIRECTORY_SEPARATOR, true) !== strstr($dir, DIRECTORY_SEPARATOR, true)) { |
|
79 | 1 | $dir = $base.DIRECTORY_SEPARATOR.$dir; |
|
80 | 1 | } |
|
81 | 1 | foreach (array_filter(explode(DIRECTORY_SEPARATOR, $dir), 'strlen') as $folder) { |
|
82 | 1 | if ($folder == '..') { |
|
83 | 1 | array_pop($folders); |
|
84 | 1 | } elseif ($folder != '.') { |
|
85 | 1 | $folders[] = $folder; |
|
86 | 1 | } |
|
87 | 1 | } |
|
88 | 1 | $folder = implode(DIRECTORY_SEPARATOR, $folders); |
|
89 | 1 | } |
|
90 | 42 | $page->dir('set', 'base', $folder); |
|
91 | 42 | $page->dir('set', 'page', $folder); |
|
92 | 42 | $page->url['full'] = ''; |
|
93 | 42 | $page->url['base'] = (!empty($base)) ? trim($base, '/').'/' : $page->request->getUriForPath('/'); |
|
94 | 42 | if (parse_url($page->url['base'], PHP_URL_SCHEME) === null) { |
|
95 | 1 | $page->url['base'] = 'http://'.$page->url['base']; |
|
96 | 1 | } |
|
97 | 42 | $page->url['path'] = trim($page->request->getPathInfo(), '/'); // excludes leading and trailing slashes |
|
98 | 42 | if ($page->url['suffix'] = pathinfo($page->url['path'], PATHINFO_EXTENSION)) { |
|
99 | 34 | $page->url['suffix'] = '.'.$page->url['suffix']; // includes leading dot |
|
100 | 34 | $page->url['path'] = substr($page->url['path'], 0, -strlen($page->url['suffix'])); // remove suffix from path |
|
101 | 34 | } |
|
102 | 42 | $page->url['query'] = (null !== $qs = $page->request->getQueryString()) ? '?'.$qs : ''; |
|
103 | 42 | $page->url['preg'] = preg_quote($page->url['base'], '/'); |
|
104 | 42 | $page->url['chars'] = 'a-z0-9'.preg_quote(str_replace(array('a-z', '0-9', '.', '/', '\\', '?', '#'), '', $chars), '/'); |
|
105 | 42 | $page->url['html'] = array('', '/', '.htm', '.html', '.shtml', '.phtml', '.php', '.asp', '.jsp', '.cgi', '.cfm', '.pl'); |
|
106 | 42 | if (empty($page->url['suffix']) || in_array($page->url['suffix'], $page->url['html'])) { |
|
107 | 34 | $page->url['format'] = 'html'; |
|
108 | 34 | } else { |
|
109 | 11 | $page->url['format'] = substr($page->url['suffix'], 1); |
|
110 | 11 | $page->url['path'] .= $page->url['suffix']; // put it back on since it is relevant now |
|
111 | } |
||
112 | 42 | $page->url['method'] = $page->request->getMethod(); // eg. GET|POST |
|
113 | 42 | $page->url['route'] = '/'.$page->url['path']; // includes leading slash and unfiltered path (below) |
|
114 | 42 | $page->url('set', 'base', $page->url['base']); |
|
115 | 42 | $page->url('set', 'dir', $page->url['base'].'page/'); |
|
116 | 42 | $page->url['path'] = preg_replace('/[^'.$page->url['chars'].'.\/]/i', '', $page->url['path']); |
|
117 | 42 | $page->url['suffix'] = (!empty($suffix) && in_array($suffix, $page->url['html'])) ? $suffix : ''; |
|
118 | 42 | $page->url['full'] = $page->formatLocalPath($page->url['base'].$page->url['path'].$page->url['query']); |
|
119 | 42 | if ($enforce && strcmp($page->url['full'], $page->request->getUri()) !== 0) { |
|
120 | 1 | $page->eject($page->url['full'], 301); |
|
121 | 1 | } |
|
122 | 42 | $page->set(array(), 'reset'); |
|
123 | 42 | return $page; |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * Allows you to set HTML Page properties. |
||
128 | * |
||
129 | * @param string|array $name The ``$page->$name`` you would like to set. You can do this one at a time, or make this an array and set everything at once. |
||
130 | * @param mixed $value The value if the $name (above) is a string. |
||
131 | * |
||
132 | * ```php |
||
133 | * $page->set(array( |
||
134 | * 'title' => 'Sample Page', |
||
135 | * 'description' => 'Snippet of information', |
||
136 | * 'keywords' => 'Comma, Spearated, Tags', |
||
137 | * 'thumb' => $page->url('base', 'image.jpg'), |
||
138 | * 'author' => 'Full Name', |
||
139 | * 'published' => 'Feb 7, 2015', |
||
140 | * )); |
||
141 | * ``` |
||
142 | */ |
||
143 | 43 | public function set($name, $value = '') |
|
144 | { |
||
145 | 43 | $html = (is_array($name)) ? $name : array($name => $value); |
|
146 | 43 | if (is_array($name) && $value == 'reset') { |
|
147 | 43 | $this->html = array( |
|
148 | 43 | 'doctype' => '<!doctype html>', |
|
149 | 43 | 'language' => 'en', |
|
150 | 43 | 'charset' => 'utf-8', |
|
151 | 43 | 'title' => '', |
|
152 | 43 | 'description' => '', |
|
153 | 43 | 'keywords' => '', |
|
154 | 43 | 'robots' => true, |
|
155 | 43 | 'body' => '', |
|
156 | ); |
||
157 | 43 | } |
|
158 | 43 | foreach ($html as $name => $value) { |
|
159 | 23 | $this->html[strtolower($name)] = $value; |
|
160 | 43 | } |
|
161 | 43 | } |
|
162 | |||
163 | /** |
||
164 | * This is so that we can use multi-dimensional arrays with HTML Page properties. |
||
165 | * |
||
166 | * @param string $name |
||
167 | * |
||
168 | * @return bool |
||
169 | */ |
||
170 | 23 | public function __isset($name) |
|
171 | { |
||
172 | 23 | return isset($this->html[$name]); |
|
173 | } |
||
174 | |||
175 | /** |
||
176 | * Enables you to set HTML Page properties directly. |
||
177 | * |
||
178 | * @param string $name The ``$page->$name`` you would like to set. |
||
179 | * @param mixed $value Of the ``$page->$name``. |
||
180 | */ |
||
181 | 14 | public function __set($name, $value) |
|
182 | { |
||
183 | 14 | $name = strtolower($name); |
|
184 | 14 | if (is_null($value)) { |
|
185 | 10 | unset($this->html[$name]); |
|
186 | 10 | } else { |
|
187 | 5 | $this->html[$name] = $value; |
|
188 | } |
||
189 | 14 | } |
|
190 | |||
191 | /** |
||
192 | * A magic getter for our private properties: |
||
193 | * |
||
194 | * - '**session**' - The Symfony Session object. |
||
195 | * - '**request**' - The Symfony Request object. |
||
196 | * - '**plugin**' - A PHP callable that you have set up. |
||
197 | * - '**dir**' - An array of dirs with the following keys: |
||
198 | * - '**base**' - The common dir among all that follow - don't ever rely on this to be anything in particular. |
||
199 | * - '**page**' - The submitted ``$url['dir']`` when this class was instantiated. |
||
200 | * - '**$name**' - The directory of the ``$name = $page->dirname(__CLASS__)``. |
||
201 | * - '**...**' - Whatever other classes you have ``$page->dirname()``ed. |
||
202 | * - '**url**' - Information about your urls that may come in handy: |
||
203 | * - '**full**' - The complete url base, path, and query as presently constituted. |
||
204 | * - '**base**' - The base url. |
||
205 | * - '**path**' - The url path that comes after the base, and before the query. If this is an html page then it does not include the url suffix - whatever you have set it to. |
||
206 | * - '**suffix**' - Either the currently constituted url suffix, or the desired ``$url['suffix']`` that was set when this class was instantiated. Includes the leading dot. If this is not an html page (eg. .pdf, .jpg, etc.), then this will be empty. |
||
207 | * - '**query**' - A string beginning with '**?**' if there are any url params, or blank if not. |
||
208 | * - '**preg**' - The url base ``preg_quote()``ed, and ready to go. |
||
209 | * - '**chars**' - The submitted ``$url['chars']`` when this class was instantiated, ``preg_quote()``ed, but with dot, slashes, question mark and hash tag removed so that we can include them as desired. |
||
210 | * - '**html**' - The array of acceptable ``$url['suffix']``'s that correspont to html pages. |
||
211 | * - '**format**' - The type of page you are currently working with. Either '**html**' if the ``$page->url['suffix']`` is empty, or the ``$page->url['suffix']`` without the leading dot eg. pdf, jpg, etc. |
||
212 | * - '**method**' - How the page is being called eg. GET or POST |
||
213 | * - '**route**' - The ``$page->url['path']`` with a leading slash ie. ``'/'.$page->url['path']`` |
||
214 | * - '**set**' - An ``array($name => $path, ...)`` of the ``$page->url('set', $name, $path)``'s you (and we) have set. |
||
215 | * - '**html**' - The private propery from which every other $name will be retrieved. You can access and modify these at any time. The default ones are: |
||
216 | * - '**doctype**' => '<!doctype html>' - Goes at the top of your HTML page. |
||
217 | * - '**language**' => 'en' - Gets inserted just beneath the doctype in the html tag. If your page no speaka any english, then you can change it to ``$page->language = 'sp';``, or any other [two-letter language abbreviation](http://www.loc.gov/standards/iso639-2/langcodes.html). |
||
218 | * - '**charset**' => 'utf-8' - This is the first meta tag that we insert just before the title ie. ``<meta charset="utf-8">`` |
||
219 | * - '**title**' => '' - Defines the title of the page, and is inserted into the ``<head>`` section within ``<title>`` tags. |
||
220 | * - '**description**' => '' - Gets inserted into the meta description tag (if it is not empty) where you can give search engines and potential visitors a brief description of the content of your page ie. ``<meta name="description" content="...">`` |
||
221 | * - '**keywords**' => '' - A comma-separated list of keywords that you think are relevant to the page at hand. If it is not empty we put it in a meta keywords tag ie. ``<meta name="keywords" content="...">`` |
||
222 | * - '**robots**' => true - If left alone this property does nothing, but if you set ``$page->robots = false;`` then we'll put ``<meta name="robots" content="noindex, nofollow">`` which tells the search engines (robots): "Don't add this page to your index" (noindex), and "Don't follow any links that may be here" (nofollow) either. If you want one or the other, then just leave this property alone and you can spell it all out for them in ``$page->meta('name="robots" content="noindex"');`` |
||
223 | * - '**body**' => '' - This used to be useful for Google Maps, and other ugly hacks before the advent of jQuery. There are better ways to go about this, but it makes for a handy onload handler or to insert css styles for the body. Whatever you set here will go inside the ``<body>`` tag. |
||
224 | * |
||
225 | * @param string $name The ``$page->$name`` whose value you are looking for. |
||
226 | * |
||
227 | * @return mixed |
||
228 | */ |
||
229 | |||
230 | 76 | public function &__get($name) |
|
231 | { |
||
232 | // This method must return a reference and not use ternary operators for __set()ing multi-dimensional arrays |
||
233 | // http://stackoverflow.com/questions/4310473/using-set-with-arrays-solved-but-why |
||
234 | // http://stackoverflow.com/questions/5966918/return-null-by-reference-via-get |
||
235 | switch ($name) { |
||
236 | 76 | case 'session': |
|
237 | 11 | if (is_null(static::$session)) { |
|
0 ignored issues
–
show
Since
$session is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $session to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
238 | 1 | static::$session = ($this->request->hasSession()) ? $this->request->getSession() : new Session(); |
|
0 ignored issues
–
show
Since
$session is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $session to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
239 | 1 | if (!static::$session->isStarted()) { |
|
0 ignored issues
–
show
Since
$session is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $session to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
240 | 1 | static::$session->start(); |
|
0 ignored issues
–
show
Since
$session is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $session to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
241 | 1 | } |
|
242 | 2 | if (!$this->request->hasSession()) { |
|
243 | 2 | $this->request->setSession(static::$session); |
|
0 ignored issues
–
show
Since
$session is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $session to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
244 | 2 | } |
|
245 | 2 | } |
|
246 | |||
247 | 11 | return static::$session; |
|
0 ignored issues
–
show
Since
$session is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $session to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
248 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
249 | 76 | case 'plugin': |
|
250 | 76 | case 'request': |
|
251 | 76 | case 'dir': |
|
252 | 76 | case 'url': |
|
253 | 76 | case 'html': |
|
254 | 69 | return $this->$name; |
|
255 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
256 | 38 | default: |
|
257 | 38 | return $this->html[strtolower($name)]; |
|
258 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
259 | 38 | } |
|
260 | } |
||
261 | |||
262 | /** |
||
263 | * If one of your visitors gets lost, or you need to redirect them (eg. after a form has been submitted), the this method will eject theme for you. |
||
264 | * |
||
265 | * @param string $url Either the full url, or just the path. |
||
266 | * @param integer $http_response_code The status code (302 by default). |
||
267 | * |
||
268 | * ```php |
||
269 | * $page->eject('users'); |
||
270 | * ``` |
||
271 | */ |
||
272 | 6 | public function eject($url = '', $http_response_code = 302) |
|
273 | { |
||
274 | 5 | $url = (!empty($url)) ? $this->formatLocalPath($url) : $this->url['base']; |
|
275 | |||
276 | 6 | return $this->send(RedirectResponse::create(htmlspecialchars_decode($url), $http_response_code)); |
|
277 | } |
||
278 | |||
279 | /** |
||
280 | * This will ensure that the $url path you want to enforce matches the current path. |
||
281 | * |
||
282 | * @param string $url Either the full url, or just the path. |
||
283 | * @param integer $redirect The status code (301 by default). |
||
284 | * |
||
285 | * ```php |
||
286 | * echo $page->url['path']; // 'details/former-title-1' |
||
287 | * $page->enforce('details/current-title-1'); |
||
288 | * echo $page->url['path']; // 'details/current-title-1' |
||
289 | * ``` |
||
290 | */ |
||
291 | 23 | public function enforce($url, $redirect = 301) |
|
292 | { |
||
293 | 23 | list($url, $path, $suffix, $query) = $this->formatLocalPath($url, 'array'); |
|
0 ignored issues
–
show
'array' is of type string , but the function expects a boolean .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() The assignment to
$query is unused. Consider omitting it like so list($first,,$third) .
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
![]() |
|||
294 | 23 | $compare = $this->url['path']; |
|
295 | 23 | if (!empty($path)) { |
|
296 | 21 | $compare .= $this->url['suffix']; // to redirect 'index' to '' |
|
297 | 22 | } |
|
298 | 23 | if (!in_array($suffix, $this->url['html'])) { // images, css files, etc. |
|
299 | 4 | if ($path.$suffix != $this->url['path']) { |
|
300 | 1 | return $this->eject($this->url['base'].$path.$suffix, $redirect); |
|
301 | } |
||
302 | 23 | } elseif ($path.$suffix != $compare) { |
|
303 | 1 | if (strpos($url, $this->url['base']) === 0) { |
|
304 | 1 | return $this->eject($this->url['base'].$path.$suffix.$this->url['query'], $redirect); |
|
305 | } |
||
306 | 1 | } |
|
307 | 23 | } |
|
308 | |||
309 | /** |
||
310 | * This takes a class and determines the directory it resides in so that you can refer to it in ``$page->dir()`` and ``$page->url()``. |
||
311 | * |
||
312 | * @param string $class The class you want to reference. |
||
313 | * |
||
314 | * @return string A slightly modified string of the $class for you to reference. |
||
315 | * |
||
316 | * ```php |
||
317 | * $name = $page->dirname(__CLASS__); |
||
318 | * echo $page->dir($name); // The directory this file resides in |
||
319 | * ``` |
||
320 | */ |
||
321 | 23 | public function dirname($class) |
|
322 | { |
||
323 | 23 | $class = trim(str_replace('/', '\\', $class), '\\'); |
|
324 | 23 | $name = str_replace('\\', '-', strtolower($class)); |
|
325 | 23 | if (!isset($this->dir[$name]) && class_exists($class)) { |
|
326 | 23 | $ref = new \ReflectionClass($class); |
|
327 | 23 | $this->dir('set', $name, dirname($ref->getFileName())); |
|
328 | 23 | unset($ref); |
|
329 | 23 | } |
|
330 | |||
331 | 23 | return (isset($this->dir[$name])) ? $name : null; |
|
332 | } |
||
333 | |||
334 | /** |
||
335 | * @param string $folder The path after ``$this->dir['page']``. Every arg you include in the method will be another folder path. If you want the directory to be relative to ``$name = $page->dirname(__CLASS__)``, then set the first parameter to $name, and the subsequent arguments (folders) relative to it. Any empty args will be ignored. |
||
336 | * |
||
337 | * @return string The directory path, and ensures it has a trailing slash. |
||
338 | * |
||
339 | * ```php |
||
340 | * $page->dir(); // returns $page->dir['page'] - the one where your website resides |
||
341 | * $page->dir('folder', 'path'); // $page->dir['page'].'folder/path/' |
||
342 | * $page->dir('folder', '', 'path'); // $page->dir['page'].'folder/path/' |
||
343 | * $page->dir('folder/path'); // $page->dir['page'].'folder/path/' |
||
344 | * $page->dir('/folder//path///'); // $page->dir['page'].'folder/path/' |
||
345 | * $page->dir($page->dir['page'].'folder/path'); // $page->dir['page'].'folder/path/' |
||
346 | * $page->dir($page->dir['page'], '/folder/path/'); // $page->dir['page'].'folder/path/' |
||
347 | * $page->dir('page', '/folder', '/path/'); // $page->dir['page'].'folder/path/' |
||
348 | * $page->dir('base', 'folder/path'); // $page->dir['page'].'folder/path/' - 'base' is an alias for 'page' |
||
349 | * |
||
350 | * $name = $page->dirname(__CLASS__); // $page->dir[$name] is now the directory where the __CLASS__ resides |
||
351 | * $page->dir($name, 'folder'); // the 'folder' relative to __CLASS__ (with trailing slash) |
||
352 | * ``` |
||
353 | */ |
||
354 | 65 | public function dir($folder = null) |
|
355 | { |
||
356 | 65 | $folders = func_get_args(); |
|
357 | 65 | if ($folder == 'set') { |
|
358 | 43 | list($folder, $name, $dir) = $folders; |
|
0 ignored issues
–
show
The assignment to
$folder is unused. Consider omitting it like so list($first,,$third) .
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
![]() |
|||
359 | 43 | $this->dir[$name] = rtrim(str_replace('\\', '/', $dir), '/').'/'; |
|
360 | 43 | if (strpos($this->dir[$name], $this->dir['base']) !== 0) { |
|
361 | 23 | $this->dir['base'] = $this->commonDir(array($this->dir[$name], $this->dir['base'])); |
|
362 | 23 | } |
|
363 | |||
364 | 43 | return $this->dir[$name]; // all nicely formatted |
|
365 | } |
||
366 | 59 | $dir = $this->dir['page']; |
|
367 | 59 | if ($folder == 'base') { |
|
368 | 1 | array_shift($folders); |
|
369 | 59 | } elseif (isset($this->dir[$folder])) { |
|
370 | 23 | $dir = $this->dir[array_shift($folders)]; |
|
371 | 59 | } elseif (strpos($folder, $this->dir['base']) === 0) { |
|
372 | 33 | $dir = rtrim(array_shift($folders), '/').'/'; |
|
373 | 33 | } |
|
374 | 59 | if (empty($folders)) { |
|
375 | 33 | return $dir; |
|
376 | } |
||
377 | $folders = array_filter(array_map(function($path){ |
||
378 | 59 | return trim($path, '/'); |
|
379 | 59 | }, $folders)); |
|
380 | |||
381 | 59 | return $dir.implode('/', $folders).'/'; |
|
382 | } |
||
383 | |||
384 | /** |
||
385 | * @param string $name Of the folder(s) and file. Can span multiple arguments. |
||
386 | * |
||
387 | * @return string The file path. Works exactly the same as ``$page->dir(...)``, but this method doesn't include the trailing slash because it should be pointing to a file. |
||
388 | */ |
||
389 | 58 | public function file($name) |
|
0 ignored issues
–
show
|
|||
390 | { |
||
391 | 58 | return rtrim(call_user_func_array(array($this, 'dir'), func_get_args()), '/'); |
|
392 | } |
||
393 | |||
394 | /** |
||
395 | * Creates a url path (with trailing slash) that you can add to and work with, as opposed to ``$page->url()`` that always returns the ``$page->url['suffix']`` with it. |
||
396 | * |
||
397 | * @param string $url Every argument given becomes part of the path, the same as ``$page->dir()`` only with a url. The first argument can include the base url, be a ``$page->dirname()``, a reference that you ``$page->url('set', ...)``ed, or just be relative to ``$page->url['base']``. |
||
398 | * |
||
399 | * @return string A url path with trailing slash - no suffix! |
||
400 | * |
||
401 | * ```php |
||
402 | * $page->path('folder'); // $page->url['base'].'folder/' |
||
403 | * $page->path('base', 'folder'); // $page->url['base'].'folder/' |
||
404 | * $page->path('page', 'folder'); // $page->url['base'].'page/folder/' |
||
405 | * $page->path($page->url['base'], 'folder'); // $page->url['base'].'folder/' |
||
406 | * ``` |
||
407 | */ |
||
408 | 1 | public function path($url = null) |
|
409 | { |
||
410 | 1 | $paths = func_get_args(); |
|
411 | 1 | $base_url = $this->url['base']; |
|
412 | 1 | if ($url == 'base') { |
|
413 | 1 | array_shift($paths); |
|
414 | 1 | } elseif (isset($this->url['set'][$url])) { |
|
415 | 1 | $base_url = $this->url['set'][array_shift($paths)]; |
|
416 | 1 | } elseif (strpos($url, $this->url['base']) === 0) { |
|
417 | 1 | $base_url = rtrim(array_shift($paths), '/').'/'; |
|
418 | 1 | } |
|
419 | 1 | if (empty($paths)) { |
|
420 | 1 | return $base_url; |
|
421 | } |
||
422 | $paths = array_filter(array_map(function($path){ |
||
423 | 1 | return trim($path, '/'); |
|
424 | 1 | }, $paths)); |
|
425 | |||
426 | 1 | return $base_url.implode('/', $paths).'/'; |
|
427 | } |
||
428 | |||
429 | /** |
||
430 | * Allows you to either create a url, or manipulate it's query string and fragment. |
||
431 | * |
||
432 | * @param string $action What you want this method to do. The options are: |
||
433 | * |
||
434 | * - '' (blank) - |
||
435 | * - '**params**' - To get an associative array of the ``$url`` query string. |
||
436 | * - '**delete**' - To remove a param (or more) from the ``$url`` query string. |
||
437 | * - '**add**' - To add a param (or more) to the ``$url`` query string. |
||
438 | * - '**set**' - To ``$page->url['set'][$url] = $value`` that can be referred to here, and in ``$page->path()``. |
||
439 | * - '**...**' - Anything else you do will create a url string in the same manner as ``$page->path()`` only with the ``$page->url['suffix']`` included. |
||
440 | * |
||
441 | * @param string $url If empty then the ``$page->url['base']`` will be used. |
||
442 | * @param string|array $key What you would like to add to or take from the ``$url``. This can be a query string parameter, a '**#**', a '**?**', or an array depending on the type of ``$action`` you are looking for. |
||
443 | * @param string $value If ``$action`` equals '**add**', and ``$key`` is not an array, then this is the ``$key``'s value. Otherwise this argument means nothing. |
||
444 | * |
||
445 | * @return string|array The url string if you are creating one, or else: |
||
446 | * |
||
447 | * - If ``$action`` equals '**params**' then the ``$url`` query string is returned as an associative array. Otherwise this method always returns a ``$url`` that has been ampified and is ready to be inserted into your html. |
||
448 | * - If ``$action`` equals '**add** or '**delete**': |
||
449 | * - The ``$key``'s will be added to or deleted from the ``$url``'s query string or fragment if ``$key`` equals '#'. |
||
450 | * - If ``$key`` is an array, then foreach key and value, the ``$url`` will be added to or deleted from accordingly. |
||
451 | * - If ``$action`` equals '**delete**' and ``$key`` equals '**?**' then the ``$url`` will be returned without any query string at all. |
||
452 | * - If no parameters are given then the ``$page->url['full']`` is returned. |
||
453 | */ |
||
454 | 75 | public function url($action = '', $url = '', $key = '', $value = null) |
|
455 | { |
||
456 | 75 | if (empty($action)) { |
|
457 | 41 | return htmlspecialchars($this->url['full']); |
|
458 | 74 | } elseif ($action == 'set') { |
|
459 | 46 | return $this->url['set'][$url] = $key; |
|
460 | 54 | } elseif (!in_array($action, array('params', 'add', 'delete'))) { |
|
461 | 29 | $base_url = (is_array($action) && isset($action['url'])) ? $action['url'] : implode('/', (array) $action); |
|
462 | 29 | if (isset($this->url['set'][$base_url])) { |
|
463 | 29 | $base_url = $this->url['set'][$base_url]; |
|
464 | 29 | } elseif (isset($this->dir[$base_url])) { |
|
465 | 2 | $base_url = $this->url['base'].$base_url.'/'; |
|
466 | 2 | } |
|
467 | // get an array of all url $segments after the $base_url |
||
468 | 29 | $segments = array_filter(array_slice(func_get_args(), 1)); |
|
469 | 29 | if (($num = count($segments)) > 0) { |
|
470 | // trim each $segments slashes |
||
471 | 29 | $segments = array_map('trim', $segments, array_fill(0, $num, '/')); |
|
472 | 29 | } |
|
473 | 29 | array_unshift($segments, rtrim($base_url, '/\\')); |
|
474 | |||
475 | 29 | return htmlspecialchars($this->formatLocalPath(htmlspecialchars_decode(implode('/', $segments)))); |
|
476 | } |
||
477 | 39 | $url = (!empty($url)) ? htmlspecialchars_decode($url) : $this->url['full']; |
|
478 | 39 | $base = preg_replace('/[\?#].*$/', '', $url); // just the url and path |
|
479 | 39 | $url = parse_url($url); |
|
480 | 39 | if (!isset($url['query'])) { |
|
481 | 16 | $params = array(); |
|
482 | 16 | } else { |
|
483 | 27 | parse_str($url['query'], $params); |
|
484 | } |
||
485 | 39 | $fragment = (!empty($url['fragment'])) ? '#'.$url['fragment'] : ''; |
|
486 | switch ($action) { |
||
487 | 39 | case 'params': |
|
488 | 25 | return $params; |
|
489 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
490 | 27 | case 'add': |
|
491 | 24 | if ($key == '#') { |
|
492 | 1 | $fragment = '#'.urlencode($value); |
|
493 | 1 | } else { |
|
494 | 24 | $params = array_merge($params, (is_array($key) ? $key : array($key => $value))); |
|
495 | } |
||
496 | 24 | break; |
|
497 | 24 | case 'delete': |
|
498 | 24 | if ($key == '?') { |
|
499 | 5 | $params = array(); |
|
500 | 24 | } elseif ($key == '#') { |
|
501 | 1 | $fragment = ''; |
|
502 | 1 | } else { |
|
503 | 21 | foreach ((array) $key as $value) { |
|
504 | 21 | unset($params[$value]); |
|
505 | 21 | } |
|
506 | } |
||
507 | 24 | break; |
|
508 | } |
||
509 | 27 | $query = (!empty($params)) ? '?'.http_build_query($params) : ''; |
|
510 | |||
511 | 27 | return htmlspecialchars($this->formatLocalPath($base.$query.$fragment)); |
|
512 | } |
||
513 | |||
514 | /** |
||
515 | * A shortcut for ``$page->request->query->get($key, $default)``. |
||
516 | * |
||
517 | * @param string $key The $_GET[$key]. |
||
518 | * @param mixed $default The default value to return if the $_GET[$key] doesn't exits. |
||
519 | * |
||
520 | * @return mixed |
||
521 | */ |
||
522 | 2 | public function get($key, $default = null) |
|
523 | { |
||
524 | 2 | return $this->request->query->get($key, $default); |
|
525 | } |
||
526 | |||
527 | /** |
||
528 | * A shortcut for ``$page->request->request->get($key, $default)``. |
||
529 | * |
||
530 | * @param string $key The $_POST[$key]. |
||
531 | * @param mixed $default The default value to return if the $_POST[$key] doesn't exits. |
||
532 | * |
||
533 | * @return mixed |
||
534 | */ |
||
535 | 1 | public function post($key, $default = null) |
|
536 | { |
||
537 | 1 | return $this->request->request->get($key, $default); |
|
538 | } |
||
539 | |||
540 | /** |
||
541 | * Takes the current (or custom) ``$page->url['method']``, and maps it to the paths you provide using the (AltoRouter)[http://altorouter.com/]. |
||
542 | * |
||
543 | * @param array $map An ``array($route => $target, ...)`` or just ``array($route, ...)``, or any combination thereof. The $target could be a php file, a method name, or whatever you want that will help you to determine what comes next. A $route is what you are expecting your uri to look like, and mapping them to variables that you can actually work with. |
||
544 | * |
||
545 | * - **folder** will match 'folder' |
||
546 | * - **users/[register|sign_in|forgot_password:action]** will match 'users/sign_in' with ``$params['action'] = 'sign_in'`` |
||
547 | * - **users/[i:id]** will match 'users/12' with ``$params['id'] = 12`` |
||
548 | * |
||
549 | * Notice that the '**i**' in '**[i:id]**' will match an integer and assign the paramter '**id**' to the value of '**i**'. You can set or override these shortcuts in **$types** below. The defaults are: |
||
550 | * |
||
551 | * - __*__ - Match all request URIs |
||
552 | * - __[i]__ - Match an integer |
||
553 | * - __[i:id]__ - Match an integer as 'id' |
||
554 | * - __[a:action]__ - Match alphanumeric characters as 'action' |
||
555 | * - __[h:key]__ - Match hexadecimal characters as 'key' |
||
556 | * - __[:action]__ - Match anything up to the next '__/__', or end of the URI as 'action' |
||
557 | * - __[create|edit:action]__ - Match either 'create' or 'edit' as 'action' |
||
558 | * - __[*]__ - Catch all (lazy) |
||
559 | * - __[*:trailing]__ - Catch all as 'trailing' (lazy) |
||
560 | * - __[**:trailing]__ - Catch all (possessive - will match the rest of the URI) |
||
561 | * - __.[:format]?__ - Match an optional parameter as 'format' |
||
562 | * - When you put a '__?__' after the block (making it optional), a '__/__' or '__.__' before the block is also optional |
||
563 | * |
||
564 | * A few more examples for the road: |
||
565 | * |
||
566 | * - __posts/[*:title]-[i:id]__ - Matches 'posts/this-is-a-title-123' |
||
567 | * - __posts/[create|edit:action]?/[i:id]?__ - Matches 'posts', 'posts/123', 'posts/create', and 'posts/edit/123' |
||
568 | * - __output.[xml|json:format]?__ - Matches 'output', 'output.xml', 'output.json' |
||
569 | * - __@\.(json|csv)$__ - Matches all requests that end with '.json' or '.csv' |
||
570 | * - __!@^admin/__ - Matches all requests that _don't_ start with admin/ |
||
571 | * - __api/[*:key]/[*:name]__ - Matches 'api/123/456/gadd' where name = '456/gadd' |
||
572 | * - __[:controller]?/[:action]?__ - Matches the typical controller/action format |
||
573 | * - __[:controller]?/[:method]?/[**:uri]?__ - There's nothing that this won't cover |
||
574 | * |
||
575 | * @param mixed $route If your don't want to use ``$page->url['method']``, then set this value to the path you want to match against. |
||
576 | * @param array $types If you want to add to (or override) the shortcut regex's, then you can add them here. The defaults are: |
||
577 | * |
||
578 | * ```php |
||
579 | * $types = array( |
||
580 | * 'i' => '[0-9]++', // integer |
||
581 | * 'a' => '[0-9A-Za-z]++', // alphanumeric |
||
582 | * 'h' => '[0-9A-Fa-f]++', // hexadecimal |
||
583 | * '*' => '.+?', // anything (lazy) |
||
584 | * '**' => '.++', // anything (possessive) |
||
585 | * '' => '[^/\.]++' // not a slash (/) or period (.) |
||
586 | * ); |
||
587 | * ``` |
||
588 | * |
||
589 | * @return mixed False if nothing matches in which case you should ``show_404()``, or an array of information with the following keys: |
||
590 | * |
||
591 | * - '**target**' - The route we successfully matched. If the route is a key, then this is it's value. Otherwise it is the route itself. |
||
592 | * - '**params**' - All of the params we matched to the successful route. |
||
593 | * - '**method**' - Either '**POST**' or '**GET**'. |
||
594 | * |
||
595 | * ```php |
||
596 | * $routes = array( |
||
597 | * '' => 'index.php', |
||
598 | * 'listings' => 'listings.php', |
||
599 | * 'details/[*:title]-[i:id]' => 'details.php', |
||
600 | * ); |
||
601 | * if (is_admin()) $routes['admin/[:action]'] = 'admin.php'; |
||
602 | * |
||
603 | * if ($route = $page->routes($routes)) { |
||
604 | * include $route['target']; |
||
605 | * } else { |
||
606 | * $page->send(404); |
||
607 | * } |
||
608 | * ``` |
||
609 | */ |
||
610 | 16 | public function routes(array $map, $route = null, array $types = array()) |
|
611 | { |
||
612 | 16 | $path = (is_null($route)) ? $this->url['route'] : $route; |
|
613 | 16 | $routes = array(); |
|
614 | 16 | foreach ($map as $route => $target) { |
|
615 | 16 | if (is_numeric($route)) { |
|
616 | 16 | $route = $target; |
|
617 | 16 | } |
|
618 | 16 | $routes[] = array($this->url['method'], ltrim($route, '/'), $target); |
|
619 | 16 | } |
|
620 | 16 | $router = new AltoRouter($routes, '', $types); |
|
621 | 16 | if ($match = $router->match(ltrim($path, '/'), $this->url['method'])) { |
|
622 | 16 | unset($match['name']); |
|
623 | 16 | } |
|
624 | |||
625 | 16 | return $match; |
|
626 | } |
||
627 | |||
628 | /** |
||
629 | * Generates an html tag programatically. |
||
630 | * |
||
631 | * @param string $name The tag's name eg. 'div' |
||
632 | * @param array $attributes An ``array($key => $value, ...)`` of attributes. If $value is an array (a good idea for classes) then we remove any duplicate or empty values, and implode them with a space in beween. If the $value is an empty string we ignore the attribute entirely. If the $key is numeric (ie. not set) then the attribute is it's $value (eg. '**multiple**' or '**selected**'), and we'll delete any $key of the same name (eg. multiple="multiple" or selected="selected"). If you want an empty attribute to be included, then set the $value to null. |
||
633 | * @param string $content All args supplied after the $attributes are stripped of any empty values, and ``implode(' ', ...)``ed. |
||
634 | * |
||
635 | * @return string An opening html tag with attributes. If $content is supplied then we add that, and a closing html tag. |
||
636 | * |
||
637 | * ```php |
||
638 | * echo $page->tag('meta', array('name'=>'description', 'content'=>'')); // <meta name="description"> |
||
639 | * |
||
640 | * echo $page->tag('p', array('class'=>'lead'), 'Content', 'Coming'); // <p class="lead">Content Coming</p> |
||
641 | * ``` |
||
642 | */ |
||
643 | 33 | public function tag($name, array $attributes, $content = null) |
|
0 ignored issues
–
show
|
|||
644 | { |
||
645 | 33 | $args = func_get_args(); |
|
646 | 33 | $tag = array_shift($args); |
|
647 | 33 | $attributes = array_shift($args); |
|
648 | 33 | foreach ($attributes as $key => $value) { |
|
649 | 33 | if (is_array($value)) { |
|
650 | 2 | $value = implode(' ', array_unique(array_filter($value))); |
|
651 | 2 | } |
|
652 | 33 | if ($value === '') { |
|
653 | 7 | unset($attributes[$key]); |
|
654 | 33 | } elseif (!is_numeric($key)) { |
|
655 | 32 | $attributes[$key] = $key.'="'.$value.'"'; |
|
656 | 32 | } elseif (isset($attributes[$value])) { |
|
657 | 1 | unset($attributes[$key]); |
|
658 | 1 | } |
|
659 | 33 | } |
|
660 | 33 | $attributes = (!empty($attributes)) ? ' '.implode(' ', $attributes) : ''; |
|
661 | 33 | $html = '<'.$tag.$attributes.'>'; |
|
662 | 33 | if (!empty($args)) { |
|
663 | 24 | $html .= implode(' ', array_filter($args)); |
|
664 | 24 | $html .= '</'.strstr($tag.' ', ' ', true).'>'; |
|
665 | 24 | } |
|
666 | |||
667 | 33 | return $html; |
|
668 | } |
||
669 | |||
670 | /** |
||
671 | * Some handy formatters that always come in handy. |
||
672 | * |
||
673 | * @param string $type The type of string you are formatting: Either '**url**', '**markdown**', or '**title**'. |
||
674 | * @param string $string What you would like to format |
||
675 | * @param false|mixed $slashes If anything but false, it will allow your url to have slashes. |
||
676 | * |
||
677 | * @return string Depending on $type |
||
678 | */ |
||
679 | 8 | public function format($type, $string, $slashes = false) |
|
680 | { |
||
681 | switch ($type) { |
||
682 | 8 | case 'url': |
|
683 | 6 | $url = ($slashes !== false) ? explode('/', $string) : array($string); |
|
684 | 6 | foreach ($url as $key => $value) { |
|
685 | 6 | $url[$key] = URLify::filter($value); |
|
686 | 6 | } |
|
687 | 6 | $string = implode('/', $url); |
|
688 | 6 | break; |
|
689 | 6 | case 'markdown': |
|
690 | 6 | $parser = new ParsedownExtra(); |
|
691 | 6 | $string = $parser->text($string); |
|
692 | 6 | break; |
|
693 | 1 | case 'title': |
|
694 | 1 | $string = explode(' ', $string); |
|
695 | 1 | foreach ($string as $key => $value) { |
|
696 | 1 | if (!empty($value) && mb_strtoupper($value) == $value) { |
|
697 | 1 | $string[$key] = mb_strtolower($value); |
|
698 | 1 | } |
|
699 | 1 | } |
|
700 | 1 | $string = TextFormatter::titleCase(implode(' ', $string)); |
|
701 | 1 | break; |
|
702 | } |
||
703 | |||
704 | 8 | return $string; |
|
705 | } |
||
706 | |||
707 | /** |
||
708 | * Allows you to insert any meta tags (at any time) into the head section of your page. We already take care of the description, keywords, and robots tags. If there are any more you would like to add, then you may do so here. You can only enter one meta tag at a time with this method. |
||
709 | * |
||
710 | * @param mixed $args If ``$args`` is a string, then we just include the meta tag as is. If it is an array then we use the key and value pairs to build the meta tag's attributes. |
||
711 | * |
||
712 | * ```php |
||
713 | * $page->meta('name="author" content="name"'); // or ... |
||
714 | * |
||
715 | * $page->meta(array('name'=>'author', 'content'=>'name')); |
||
716 | * ``` |
||
717 | */ |
||
718 | 1 | public function meta($args) |
|
719 | { |
||
720 | 1 | if (is_string($args)) { |
|
721 | 1 | $this->data('meta', $args, false); |
|
722 | 1 | } else { |
|
723 | 1 | foreach ($args as $key => $value) { |
|
0 ignored issues
–
show
The expression
$args of type object|integer|double|array|boolean|null is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
724 | 1 | $args[$key] = $key.'="'.$value.'"'; |
|
725 | 1 | } |
|
726 | 1 | $this->data('meta', implode(' ', $args), false); |
|
727 | } |
||
728 | 1 | } |
|
729 | |||
730 | /** |
||
731 | * @param mixed $link This can be a string, or an array of javascript, css, and / or icon resources that will be added to the head section of your page. |
||
732 | * @param mixed $prepend If this value is anything other than false (I like to use 'prepend'), then all of the ``$link``'s that you just included will be prepended to the stack, as opposed to being inserted after all of the other links you have included. |
||
733 | * |
||
734 | * ```php |
||
735 | * $page->link(array( |
||
736 | * $page->url('images/favicon.ico'), |
||
737 | * $page->url('css/stylesheet.css'), |
||
738 | * $page->url('js/functions.js'), |
||
739 | * )); |
||
740 | * ``` |
||
741 | */ |
||
742 | 10 | public function link($link, $prepend = false) |
|
743 | { |
||
744 | 10 | $link = (array) $link; |
|
745 | 10 | if ($prepend !== false) { |
|
746 | 5 | $link = array_reverse($link); // so they are added in the correct order |
|
747 | 5 | } |
|
748 | 10 | foreach ($link as $file) { |
|
749 | 10 | $frag = (strpos($file, '<') === false) ? strstr($file, '#') : ''; |
|
750 | 10 | if (!empty($frag)) { |
|
751 | 2 | $file = substr($file, 0, -strlen($frag)); |
|
752 | 2 | } |
|
753 | 10 | if (preg_match('/\.(js|css|ico|apple)$/i', $file)) { |
|
754 | 8 | $split = strrpos($file, '.'); |
|
755 | 8 | $ext = substr($file, $split + 1); |
|
756 | 8 | $name = substr($file, 0, $split); |
|
757 | switch ($ext) { |
||
758 | 8 | case 'js': |
|
759 | 8 | $this->data('js', $file.$frag, $prepend); |
|
760 | 8 | break; |
|
761 | 3 | case 'css': |
|
762 | 3 | $this->data('css', $file.$frag, $prepend); |
|
763 | 3 | break; |
|
764 | 1 | case 'ico': |
|
765 | 1 | $this->data['ico'] = $file.$frag; |
|
766 | 1 | break; |
|
767 | 1 | case 'apple': |
|
768 | 1 | $this->data['apple'] = $name.'.png'; |
|
769 | 1 | break; |
|
770 | } |
||
771 | 10 | } elseif (substr($file, 1, 5) == 'style') { |
|
772 | 2 | $this->data('style', $file, $prepend); |
|
773 | 7 | } elseif (substr($file, 1, 6) == 'script') { |
|
774 | 6 | $this->data('script', $file, $prepend); |
|
775 | 6 | } else { |
|
776 | 1 | $this->data('other', $file, $prepend); |
|
777 | } |
||
778 | 10 | } |
|
779 | 10 | } |
|
780 | |||
781 | /** |
||
782 | * This will enclose the $css within ``<script>`` tags and place it in the ``<head>`` of your page. |
||
783 | * |
||
784 | * @param string $code Your custom css code. |
||
785 | * |
||
786 | * ```php |
||
787 | * $page->script('body { background-color:red; }'); |
||
788 | * ``` |
||
789 | */ |
||
790 | 1 | public function style($code) |
|
791 | { |
||
792 | 1 | if (is_array($code)) { |
|
793 | 1 | foreach ($code as $css => $rules) { |
|
794 | 1 | if (is_array($rules)) { |
|
795 | 1 | $code[$css] = $css.' { '.implode(' ', $rules).' }'; |
|
796 | 1 | } elseif (!is_numeric($css)) { |
|
797 | 1 | $code[$css] = $css.' { '.$rules.' }'; |
|
798 | 1 | } |
|
799 | 1 | } |
|
800 | 1 | $code = implode("\n", $code); |
|
801 | 1 | } |
|
802 | 1 | $this->link('<style>'.(strpos($code, "\n") ? "\n".$this->indent($code)."\n\t" : trim($code)).'</style>'); |
|
803 | 1 | } |
|
804 | |||
805 | /** |
||
806 | * This will enclose the $javascript within ``<style>`` tags and place it at the bottom of your page. |
||
807 | * |
||
808 | * @param string $code Your custom javascript code. |
||
809 | * |
||
810 | * ```php |
||
811 | * $page->script('alert("Hello World");'); |
||
812 | * ``` |
||
813 | */ |
||
814 | 5 | public function script($code) |
|
815 | { |
||
816 | 5 | if (is_array($code)) { |
|
817 | 1 | $code = implode("\n", $code); |
|
818 | 1 | } |
|
819 | 5 | $this->link('<script>'.(strpos($code, "\n") ? "\n".$this->indent($code)."\n\t" : trim($code)).'</script>'); |
|
820 | 5 | } |
|
821 | |||
822 | /** |
||
823 | * jQuery itself is included automatically if you ever call this method, and is placed before any other included scripts on the page. The default version is currently v.1.11.4, but you can change that by setting ``$page->jquery`` to the file you want to use. To include the jQuery UI right after that then call ``$page->jquery('ui', $file)``, and if you leave out the $file then we will use v.1.12.3. |
||
824 | * |
||
825 | * @param string|array $code A string of jQuery. All of the included code is compiled at the end of the page and placed into one ``$(document).ready(function(){...})``. If this is a file or files (array), then they will be included via ``$page->link()``. |
||
826 | * @param mixed $prepend Passed to ``$page->link()`` if including files. |
||
827 | * |
||
828 | * ```php |
||
829 | * $page->jquery('$("button.continue").html("Next Step...");'); |
||
830 | * ``` |
||
831 | */ |
||
832 | 6 | public function jquery($code, $prepend = false) |
|
833 | { |
||
834 | 6 | if ($code == 'ui') { |
|
835 | 1 | if (!isset($this->data['jquery']['ui'])) { |
|
836 | 1 | $this->data['jquery']['ui'] = false; |
|
837 | 1 | } |
|
838 | 1 | if (!empty($prepend)) { |
|
839 | 1 | $this->data['jquery']['ui'] = $prepend; |
|
840 | 1 | } |
|
841 | |||
842 | 1 | return; |
|
843 | } |
||
844 | 6 | foreach ((array) $code as $value) { |
|
845 | 6 | if (!is_string($value) || strpos($value, 'http') !== 0) { |
|
846 | 6 | $this->data['jquery'][] = $code; |
|
847 | |||
848 | 6 | return; |
|
849 | } |
||
850 | 1 | } |
|
851 | 1 | $this->link($code, $prepend); |
|
852 | 1 | $this->data['jquery'][] = ''; |
|
853 | 1 | } |
|
854 | |||
855 | /** |
||
856 | * We use this in the Form component to avoid input name collisions. We use it in the Bootstrap component for accordions, carousels, and the like. The problem with just incrementing a number and adding it onto something else is that css and jQuery don't like numbered id's, and so we use roman numerals instead and that solves the problem for us. |
||
857 | * |
||
858 | * @param string $prefix What you would like to come before the roman numeral. This is not really needed, but when you are looking at your source code, it helps to know what you are looking at. |
||
859 | * |
||
860 | * @return string A unique id. |
||
861 | * |
||
862 | * ```php |
||
863 | * // Assuming this method has not been called before: |
||
864 | * echo $page->id('name'); // nameI |
||
865 | * echo $page->id('unique'); // uniqueII |
||
866 | * echo $page->id('unique'); // uniqueIII |
||
867 | * ``` |
||
868 | */ |
||
869 | 13 | public function id($prefix = '') |
|
870 | { |
||
871 | 13 | static $id = 0; |
|
872 | 13 | ++$id; |
|
873 | 13 | $result = ''; |
|
874 | 13 | $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1); |
|
875 | 13 | $number = $id; |
|
876 | 13 | if ($number < 100) { |
|
877 | 13 | $lookup = array_slice($lookup, 4); |
|
878 | 13 | } |
|
879 | 13 | foreach ($lookup as $roman => $value) { |
|
880 | 13 | $matches = intval($number / $value); |
|
881 | 13 | $result .= str_repeat($roman, $matches); |
|
882 | 13 | $number = $number % $value; |
|
883 | 13 | } |
|
884 | |||
885 | 13 | return $prefix.$result; |
|
886 | } |
||
887 | |||
888 | /** |
||
889 | * This allows you to map a $path to a folder and $file in $dir so that you can ``$page->load()`` it. This will essentially make your $file a controller (following the MVC pattern if that means anything to you). |
||
890 | * |
||
891 | * @param string $dir The base directory whose folders you want to map to a $path. |
||
892 | * @param string $path The ``$page->url['path']`` or whatever else you want to use. |
||
893 | * @param string $file The filename that must be in the folder to make a match. |
||
894 | * |
||
895 | * @return array|null If we have a match then we will return an array with the following info: |
||
896 | * |
||
897 | * - '**file**' - The file path for which we made a match. |
||
898 | * - '**dir**' - The dir in which the file resides (with trailing slash). |
||
899 | * - '**assets**' - The url path (with trailing slash) that corresponds to the dir for including images and other files. |
||
900 | * - '**url**' - The url path for linking to other pages that are relative to this dir. |
||
901 | * - '**folder**' - The portion of your $path that got us to your $file. |
||
902 | * - '**route**' - The remaining portion of your $path that your $file will have to figure out what to do with next. |
||
903 | * |
||
904 | * ```php |
||
905 | * // Assuming ``$dir = $page->dir('folders')``, and you have a $dir.'users/index.php' file: |
||
906 | * if ($params = $page->folder($dir, 'users/sign_in')) { |
||
907 | * $html = $page->load($params['file'], $params); |
||
908 | * // $params = array( |
||
909 | * // 'file' => $dir.'users/index.php', |
||
910 | * // 'dir' => $dir.'users/', |
||
911 | * // 'assets' => $page->url['base'].'page/folders/users/', |
||
912 | * // 'url' => $page->url['base'].'folders/users/', |
||
913 | * // 'folder' => 'users/', |
||
914 | * // 'route' => '/sign_in', |
||
915 | * // ); |
||
916 | * } |
||
917 | * ``` |
||
918 | */ |
||
919 | 23 | public function folder($dir, $path, $file = 'index.php') |
|
920 | { |
||
921 | 23 | $dir = $this->dir($dir); |
|
922 | 23 | if (strpos($dir, $this->dir['page']) === 0 && is_dir($dir)) { |
|
923 | 23 | $folder = substr($dir, strlen($this->dir['page'])); |
|
924 | 23 | $paths = array(); |
|
925 | 23 | $path = preg_replace('/[^'.$this->url['chars'].'\.\/]/', '', strtolower($path)); |
|
926 | 23 | foreach (explode('/', $path) as $dir) { |
|
927 | 23 | if (false !== $extension = strstr($dir, '.')) { |
|
928 | 1 | $dir = substr($dir, 0, -strlen($extension)); // remove file extension |
|
929 | 1 | } |
|
930 | 23 | if (!empty($dir)) { |
|
931 | 3 | $paths[] = $dir; // remove empty $paths |
|
932 | 3 | } |
|
933 | 23 | } |
|
934 | 23 | $paths = array_diff($paths, array('index')); // remove any reference to 'index' |
|
935 | 23 | $path = '/'.implode('/', $paths); // includes leading slash and corresponds with $paths |
|
936 | 23 | if ($extension) { |
|
937 | 1 | $path .= $extension; |
|
0 ignored issues
–
show
The variable
$extension does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
938 | 1 | } |
|
939 | 23 | while (!empty($paths)) { |
|
940 | 3 | $route = implode('/', $paths).'/'; // includes trailing slash |
|
941 | 3 | if (is_file($this->file($folder, $route, $file))) { |
|
942 | return array( |
||
943 | 2 | 'file' => $this->file($folder, $route, $file), |
|
944 | 2 | 'dir' => $this->dir($folder, $route), |
|
945 | 2 | 'assets' => $this->url['base'].'page/'.$folder.$route, |
|
946 | 2 | 'url' => $this->url['base'].$folder.$route, |
|
947 | 2 | 'folder' => substr($path, 1, strlen($route)), // remove leading slash |
|
948 | 2 | 'route' => substr($path, strlen($route)), // remove trailing slash |
|
949 | 2 | ); |
|
950 | } |
||
951 | 2 | array_pop($paths); |
|
952 | 2 | } |
|
953 | 23 | if (is_file($this->file($folder, $file))) { |
|
954 | return array( |
||
955 | 23 | 'file' => $this->file($folder, $file), |
|
956 | 23 | 'dir' => $this->dir($folder), |
|
957 | 23 | 'assets' => $this->url['base'].'page/'.$folder, |
|
958 | 23 | 'url' => $this->url['base'].$folder, |
|
959 | 23 | 'folder' => '', |
|
960 | 23 | 'route' => $path, |
|
961 | 23 | ); |
|
962 | } |
||
963 | 2 | } |
|
964 | |||
965 | 2 | return; |
|
966 | } |
||
967 | |||
968 | /** |
||
969 | * Passes $params to a $file, and returns the output. |
||
970 | * |
||
971 | * @param string $file The file you want to ``include``. |
||
972 | * @param array $params Variables you would like your file to receive. |
||
973 | * |
||
974 | * @return mixed Whatever you ``$export``ed (could be anything), or a string of all that you ``echo``ed. |
||
975 | * |
||
976 | * ```php |
||
977 | * $file = $page->file('folders/users/index.php'); |
||
978 | * |
||
979 | * // Assuming $file has the following code: |
||
980 | * |
||
981 | * <?php |
||
982 | * extract($params); |
||
983 | * $export = $action.' Users'; |
||
984 | * |
||
985 | * // Loading it like this would return 'Sign In Users' |
||
986 | * |
||
987 | * echo $page->load($file, array('action'=>'Sign In')); |
||
988 | * ``` |
||
989 | */ |
||
990 | 2 | public function load($file, array $params = array()) |
|
991 | { |
||
992 | 2 | if (!is_file($file)) { |
|
993 | 1 | return; |
|
994 | } |
||
995 | 2 | foreach ($params as $key => $value) { |
|
996 | 2 | if (is_numeric($key) && is_string($value)) { |
|
997 | 1 | $params[$value] = true; // makes it possible to extract(), and easier to check if isset() |
|
998 | 1 | unset($params[$key]); |
|
999 | 1 | } |
|
1000 | 2 | } |
|
1001 | 2 | $export = ''; |
|
1002 | 2 | ob_start(); |
|
1003 | 2 | include $file; |
|
1004 | 2 | $html = ob_get_clean(); |
|
1005 | |||
1006 | 2 | return ($export !== '') ? $export : $html; |
|
1007 | } |
||
1008 | |||
1009 | /** |
||
1010 | * This method exists mainly for plugins. It allows them to save some information for future use. The saved information can be retrieved later by calling ``$page->info()``. |
||
1011 | * |
||
1012 | * @param string $name There is a potential for collision here. I recommend using the ``$page->dirname(__CLASS__)`` exclusively. |
||
1013 | * @param mixed $key If you don't indicate a ``$value``, then this will be added to the ``$name``'s array which can be retrieved at ``$page->info($name)``. |
||
1014 | * @param mixed $value if ``$key`` is a specific value that you want to save then this will be it's value, and it will override any value previously set. It can be retrieved at ``$page->info($name, $key)``. |
||
1015 | * |
||
1016 | * ```php |
||
1017 | * $name = $page->dirname(__CLASS__); |
||
1018 | * $page->save($name, 'one'); |
||
1019 | * $page->save($name, 'two'); |
||
1020 | * $page->save($name, 'skip', 'few'); |
||
1021 | * ``` |
||
1022 | */ |
||
1023 | 1 | public function save($name, $key, $value = null) |
|
1024 | { |
||
1025 | 1 | if (func_num_args() == 2 || is_array($key)) { |
|
1026 | 1 | $this->saved[$name][] = $key; |
|
1027 | 1 | } else { |
|
1028 | 1 | $this->saved[$name][$key] = $value; |
|
1029 | } |
||
1030 | 1 | } |
|
1031 | |||
1032 | /** |
||
1033 | * Returns the info saved in ``$page->save($name)``. |
||
1034 | * |
||
1035 | * @param string $name The one you indicated in ``$page->save($name)``. |
||
1036 | * @param string $key The specific value you ``$page->save($name, $key)``ed previously and now want to retrieve. |
||
1037 | * |
||
1038 | * @return mixed If you indicate a ``$key`` then we will return the value if it exists, or null if it does not. Otherwise we will return the whole array of info saved for ``$name`` (if any), or an empty array if not. |
||
1039 | * |
||
1040 | * ```php |
||
1041 | * $name = $page->dirname(__CLASS__); |
||
1042 | * |
||
1043 | * $page->info($name); // returns array(); |
||
1044 | * |
||
1045 | * $page->save($name, 'one'); |
||
1046 | * $page->save($name, 'two'); |
||
1047 | * $page->save($name, 'skip', 'few'); |
||
1048 | * |
||
1049 | * $page->info($name); // returns array('one', 'two'); |
||
1050 | * $page->info($name, 'skip'); // returns 'few'; |
||
1051 | * $page->info($name, 'set'); // returns null; |
||
1052 | * ``` |
||
1053 | */ |
||
1054 | 1 | public function info($name, $key = null) |
|
1055 | { |
||
1056 | 1 | if (!is_null($key)) { |
|
1057 | 1 | return (isset($this->saved[$name][$key])) ? $this->saved[$name][$key] : null; |
|
1058 | } |
||
1059 | 1 | $info = (isset($this->saved[$name])) ? $this->saved[$name] : array(); |
|
1060 | 1 | foreach ($info as $key => $value) { |
|
1061 | 1 | if (!is_numeric($key)) { |
|
1062 | 1 | unset($info[$key]); |
|
1063 | 1 | } |
|
1064 | 1 | } |
|
1065 | |||
1066 | 1 | return $info; |
|
1067 | } |
||
1068 | |||
1069 | /** |
||
1070 | * Enables you to prepend, append, or modify just about anything throughout the creation process of your page. |
||
1071 | * |
||
1072 | * @param string $section Must be one of (in the order we process them at ``$page->display()``): |
||
1073 | * |
||
1074 | * - '**content**' - This comes first before all. Presumably, it is the reason you are creating a website. We create / process the content first, then we put the rest of the page together, which all revolves around the content. If you have anything else to add (or edit), you may do so now. |
||
1075 | * - '**metadata**' - This contains the title tag and metadata, just before we start inserting all of your css stylesheets. |
||
1076 | * - '**css**' - After we insert any icon image links, we hand over the array of stylesheets we want to include for further processing (if any). |
||
1077 | * - '**styles**' - After all the stylesheets are up, then we check for anything else you would like to add just before the ``</head><body>`` tags. |
||
1078 | * - '**javascript**' - After your content we include jquery first, then all of your javascript files. |
||
1079 | * - '**scripts**' - After listing all of your javascript src files, then we include any scripts, and place the jQuery code last. |
||
1080 | * - '**head**' - Everything between the ``<head>`` ... ``</head>`` tags. |
||
1081 | * - '**body**' - Everything between the ``<body>`` ... ``</body>`` tags. |
||
1082 | * - '**page**' - The entire page from top to bottom. |
||
1083 | * - '**response**' - The final Symfony Response object if you ``$page->send()`` it. |
||
1084 | * |
||
1085 | * @param mixed $function Can be either '**prepend**', '**append**', or a callable function or method. If filtering the '**response**' then we'll pass the ``$page`` (this class instance), ``$response`` (what you are filtering), and ``$type`` ('html', 'json', 'redirect', or ``$page->url['format']``) of content that you are dealing with. |
||
1086 | * |
||
1087 | * @param mixed $params |
||
1088 | * - If ``$section`` equals '**response**' |
||
1089 | * - These are the page *type* and response *code* conditions that the response must meet in order to be processed. It can be an array or string. |
||
1090 | * - Elseif ``$function`` equals '**prepend**' or '**append**' then this must be a string. |
||
1091 | * - Elseif ``$function`` is a callable function or method: |
||
1092 | * - ``$params`` must be an array of arguments which are passed to the function or method. |
||
1093 | * - '**this**' must be listed as one of the ``$params``. |
||
1094 | * - If '**this**' is the only ``$param``, then instead of an array you can just pass the string '**this**'. |
||
1095 | * - '**this**' is the ``$section`` as currently constituted, and for which your filter would like to operate on. If you don't return anything, then that section will magically disappear. |
||
1096 | * |
||
1097 | * @param integer $order The level of importance (or priority) that this filter should receive. The default is 10. All filters are called in the order specified here. |
||
1098 | * |
||
1099 | * ```php |
||
1100 | * $page->filter('response', function ($page, $response, $type) { |
||
1101 | * return $response->setContent($type); |
||
1102 | * }, array('html', 200)); |
||
1103 | * |
||
1104 | * $page->filter('response', function ($page, $response) { |
||
1105 | * return $response->setContent('json'); |
||
1106 | * }, 'json'); |
||
1107 | * |
||
1108 | * $page->filter('response', function ($page, $response) { |
||
1109 | * return $response->setContent(404); |
||
1110 | * }, 404); |
||
1111 | * |
||
1112 | * function prepend_facebook_like_button ($content) { |
||
1113 | * return 'facebook_like_button '.$content; |
||
1114 | * } |
||
1115 | * |
||
1116 | * $page->filter('content', 'prepend_facebook_like_button', array('this')); // or ... |
||
1117 | * |
||
1118 | * $page->filter('content', 'prepend_facebook_like_button', 'this'); // or ... |
||
1119 | * |
||
1120 | * $page->filter('content', 'prepend', 'facebook_like_button '); |
||
1121 | * ``` |
||
1122 | * |
||
1123 | * @throws \LogicException If something was not set up right. |
||
1124 | */ |
||
1125 | 10 | public function filter($section, $function, $params = 'this', $order = 10) |
|
1126 | { |
||
1127 | 10 | $errors = array(); |
|
1128 | 10 | if ($section == 'response') { |
|
1129 | 3 | if (!is_callable($function, false, $name)) { |
|
1130 | 1 | $errors[] = "'{$name}' cannot be called"; |
|
1131 | 1 | } |
|
1132 | 3 | if (!is_array($params)) { |
|
1133 | 3 | $params = explode(' ', $params); |
|
1134 | 3 | } |
|
1135 | 3 | foreach ($params as $key => $value) { |
|
1136 | 3 | if (empty($value) || $value == 'this') { |
|
1137 | 1 | unset($params[$key]); |
|
1138 | 1 | } |
|
1139 | 3 | } |
|
1140 | 3 | $key = false; |
|
1141 | 10 | } elseif (!in_array($section, array('metadata', 'css', 'styles', 'head', 'content', 'javascript', 'scripts', 'body', 'page'))) { |
|
1142 | 1 | $errors[] = "'{$section}' cannot be filtered"; |
|
1143 | 8 | } elseif (in_array($function, array('prepend', 'append'))) { |
|
1144 | 3 | if (!is_string($params)) { |
|
1145 | 1 | $errors[] = "When using '{$function}', \$params must be a string"; |
|
1146 | 3 | } elseif (in_array($section, array('css', 'javascript'))) { |
|
1147 | 1 | $this->filters[$function][$section][] = $params; // [prepend|append][css|javascript][] = (string) |
|
1148 | 1 | return; |
|
1149 | } |
||
1150 | 3 | $key = ''; // not applicable here |
|
1151 | 3 | } else { |
|
1152 | 5 | $params = (array) $params; |
|
1153 | 5 | $key = array_search('this', $params); |
|
1154 | 5 | if ($key === false) { |
|
1155 | 1 | $errors[] = "'this' must be listed in the \$params so that we can give you something to filter"; |
|
1156 | 1 | } |
|
1157 | 5 | if (!is_callable($function, false, $name)) { |
|
1158 | 2 | $errors[] = "'{$name}' cannot be called"; |
|
1159 | 2 | } |
|
1160 | } |
||
1161 | 10 | if (!empty($errors)) { |
|
1162 | 5 | throw new \LogicException(implode("\n\n", $errors)); |
|
1163 | } |
||
1164 | 5 | $this->filters[$section][] = array('function' => $function, 'params' => $params, 'order' => $order, 'key' => $key); |
|
0 ignored issues
–
show
The variable
$key does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
1165 | 5 | } |
|
1166 | |||
1167 | /** |
||
1168 | * This method fulfills the measure of the whole Page component's existence: to be able to manipulate every part of an HTML page at any time. |
||
1169 | * |
||
1170 | * @param string $content Of your page. |
||
1171 | * |
||
1172 | * @return string The complete HTML page from top to bottom. |
||
1173 | */ |
||
1174 | 9 | public function display($content) |
|
1175 | { |
||
1176 | 9 | $content = $this->process('content', $content); |
|
1177 | $head = array( |
||
1178 | 9 | $this->process('metadata', "\t".implode("\n\t", $this->metadata())), |
|
1179 | 9 | $this->process('styles', "\t".implode("\n\t", $this->styles())), |
|
1180 | 9 | ); |
|
1181 | $body = array( |
||
1182 | 9 | $content, |
|
1183 | 9 | $this->process('scripts', "\t".implode("\n\t", $this->scripts())), |
|
1184 | 9 | ); |
|
1185 | $html = array( |
||
1186 | 9 | $this->html['doctype'], |
|
1187 | 9 | '<html lang="'.$this->html['language'].'">', |
|
1188 | 9 | '<head>', |
|
1189 | 9 | $this->process('head', implode("\n", $head)), |
|
1190 | 9 | '</head>', |
|
1191 | 9 | (!empty($this->html['body'])) ? '<body '.$this->html['body'].'>' : '<body>', |
|
1192 | 9 | $this->process('body', implode("\n", $body)), |
|
1193 | 9 | '</body>', |
|
1194 | 9 | '</html>', |
|
1195 | 9 | ); |
|
1196 | |||
1197 | 9 | return $this->process('page', implode("\n", $html)); |
|
1198 | } |
||
1199 | |||
1200 | /** |
||
1201 | * Sends a Symfony Response object, and allows you to further process and ``$page->filter()`` it. |
||
1202 | * |
||
1203 | * @param object|string|integer $response Either a Symfony Response object, the content of your response, or just a quick status code eg. ``$page->send(404)`` |
||
1204 | * @param integer $status The status code if your ``$response`` is a content string. |
||
1205 | * @param array $headers A headers array if your ``response`` is a content string. |
||
1206 | * |
||
1207 | * @return object If you set ``Page::html(array('testing'=>true))`` then we will return the Symfony Response object so that it doesn't halt your script, otherwise it will send the Response and exit the page. |
||
1208 | * |
||
1209 | * ```php |
||
1210 | * if ($html = $page->load($page->file('index.php'))) { |
||
1211 | * $page->send($page->display($html)); |
||
1212 | * } else { |
||
1213 | * $page->send(404); |
||
1214 | * } |
||
1215 | * ``` |
||
1216 | */ |
||
1217 | 11 | public function send($response = '', $status = 200, array $headers = array()) |
|
1218 | { |
||
1219 | 11 | if (!$response instanceof Response) { |
|
1220 | 3 | if (func_num_args() == 1 && is_numeric($response)) { |
|
1221 | 2 | $status = (int) $response; |
|
1222 | 2 | $response = ''; |
|
1223 | 2 | } |
|
1224 | 3 | $response = new Response($response, $status, $headers); |
|
1225 | 3 | } |
|
1226 | 11 | $status = $response->getStatusCode(); |
|
1227 | 11 | if ($response instanceof RedirectResponse) { |
|
1228 | 5 | $type = 'redirect'; |
|
1229 | 11 | } elseif ($response instanceof JsonResponse) { |
|
1230 | 2 | $type = 'json'; |
|
1231 | 6 | } elseif (null === $type = $response->headers->get('Content-Type')) { |
|
1232 | 3 | $type = ($status == 304) ? $this->url['format'] : 'html'; |
|
1233 | 4 | } elseif (stripos($type, 'html') !== false) { |
|
1234 | 1 | $type = 'html'; |
|
1235 | 1 | } |
|
1236 | 11 | $this->process('response', $response, $status, $type); |
|
1237 | 11 | $response = $response->prepare($this->request)->send(); |
|
1238 | |||
1239 | 11 | return ($this->testing === false) ? exit : $response; |
|
0 ignored issues
–
show
The method
send() contains an exit expression.
An exit expression should only be used in rare cases. For example, if you write a short command line script. In most cases however, using an ![]() |
|||
1240 | } |
||
1241 | |||
1242 | /** |
||
1243 | * Creates and sends a Symfony JsonResponse object. |
||
1244 | * |
||
1245 | * @param mixed $data The response data. |
||
1246 | * @param integer $status The response status code. |
||
1247 | */ |
||
1248 | 2 | public function sendJson($data = '', $status = 200) |
|
1249 | { |
||
1250 | 2 | return $this->send(JsonResponse::create($data, $status)); |
|
1251 | } |
||
1252 | |||
1253 | /** |
||
1254 | * An internal method we use that comes in handy elsewhere as well. |
||
1255 | * |
||
1256 | * @param array $files An array of files that share a common directory somewhere. |
||
1257 | * |
||
1258 | * @return The common directory (with trailing slash) shared amongst your $files. |
||
1259 | */ |
||
1260 | 24 | public function commonDir(array $files) |
|
1261 | { |
||
1262 | 24 | $files = array_values($files); |
|
1263 | 24 | $cut = 0; |
|
1264 | 24 | $count = count($files); |
|
1265 | 24 | $shortest = min(array_map('mb_strlen', $files)); |
|
1266 | 24 | while ($cut < $shortest) { |
|
1267 | 24 | $char = $files[0][$cut]; |
|
1268 | 24 | for ($i = 1; $i < $count; ++$i) { |
|
1269 | 24 | if ($files[$i][$cut] !== $char) { |
|
1270 | 23 | break 2; |
|
1271 | } |
||
1272 | 24 | } |
|
1273 | 24 | ++$cut; |
|
1274 | 24 | } |
|
1275 | 24 | $dir = substr($files[0], 0, $cut); |
|
1276 | 24 | if (false !== $slash = strrpos($dir, '/')) { |
|
1277 | 24 | $dir = substr($dir, 0, $slash + 1); |
|
1278 | 24 | } elseif (false !== $slash = strrpos($dir, '\\')) { |
|
1279 | 1 | $dir = substr($dir, 0, $slash + 1); |
|
1280 | 1 | } |
|
1281 | |||
1282 | 24 | return $dir; // with trailing slash (if any) |
|
1283 | } |
||
1284 | |||
1285 | 19 | protected function process($section, $param, $code = 0, $type = '') |
|
1286 | { |
||
1287 | // Used in $this->send(), $this->display(), $this->styles(), and $this->scripts() |
||
1288 | 19 | if (!isset($this->filters[$section])) { |
|
1289 | 17 | return $param; |
|
1290 | } |
||
1291 | 5 | usort($this->filters[$section], function ($a, $b) { |
|
1292 | 1 | return $a["order"] - $b["order"]; |
|
1293 | 5 | }); |
|
1294 | 5 | foreach ($this->filters[$section] as $key => $filter) { |
|
1295 | 4 | if ($section == 'response') { |
|
1296 | 3 | foreach ($filter['params'] as $response) { |
|
1297 | 3 | if (is_numeric($response)) { |
|
1298 | 2 | if ($response != $code) { |
|
1299 | 1 | continue 2; |
|
1300 | } |
||
1301 | 3 | } elseif (stripos($type, $response) === false) { |
|
1302 | 1 | continue 2; |
|
1303 | } |
||
1304 | 3 | } |
|
1305 | 3 | call_user_func($filter['function'], $this, $param, $type); // $page, $response, $type |
|
1306 | 4 | } elseif ($filter['function'] == 'prepend') { |
|
1307 | 1 | $param = $filter['params'].$param; |
|
1308 | 2 | } elseif ($filter['function'] == 'append') { |
|
1309 | 1 | $param .= $filter['params']; |
|
1310 | 1 | } else { |
|
1311 | 2 | $filter['params'][$filter['key']] = $param; |
|
1312 | 2 | $param = call_user_func_array($filter['function'], $filter['params']); |
|
1313 | } |
||
1314 | 4 | unset($this->filters[$section][$key]); |
|
1315 | 5 | } |
|
1316 | |||
1317 | 5 | return $param; |
|
1318 | } |
||
1319 | |||
1320 | 11 | protected function data($type, $value, $prepend) |
|
1321 | { |
||
1322 | // Used in $this->meta() and $this->link() |
||
1323 | 11 | if ($prepend !== false) { |
|
1324 | 5 | if (!isset($this->data[$type])) { |
|
1325 | 2 | $this->data[$type] = array(); |
|
1326 | 2 | } |
|
1327 | 5 | array_unshift($this->data[$type], $value); |
|
1328 | 5 | } else { |
|
1329 | 11 | $this->data[$type][] = $value; |
|
1330 | } |
||
1331 | 11 | } |
|
1332 | |||
1333 | 9 | protected function metadata() |
|
1334 | { |
||
1335 | // Used in $this->display() |
||
1336 | 9 | $metadata = array(); |
|
1337 | 9 | $metadata[] = '<meta charset="'.$this->html['charset'].'">'; |
|
1338 | 9 | $metadata[] = '<title>'.trim($this->html['title']).'</title>'; |
|
1339 | 9 | if (!empty($this->html['description'])) { |
|
1340 | 7 | $metadata[] = '<meta name="description" content="'.trim($this->html['description']).'">'; |
|
1341 | 7 | } |
|
1342 | 9 | if (!empty($this->html['keywords'])) { |
|
1343 | 7 | $metadata[] = '<meta name="keywords" content="'.trim($this->html['keywords']).'">'; |
|
1344 | 7 | } |
|
1345 | 9 | if ($this->robots !== true) { |
|
0 ignored issues
–
show
The property
robots does not exist on object<BootPress\Page\Component> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
1346 | 7 | $metadata[] = ($this->html['robots']) ? '<meta name="robots" content="'.$this->html['robots'].'">' : '<meta name="robots" content="noindex, nofollow">'; // ie. false or null |
|
1347 | 7 | } |
|
1348 | 9 | if (isset($this->data['meta'])) { |
|
1349 | 7 | foreach ($this->data['meta'] as $tag) { |
|
1350 | 7 | $metadata[] = '<meta '.$tag.'>'; |
|
1351 | 7 | } |
|
1352 | 7 | } |
|
1353 | |||
1354 | 9 | return $metadata; |
|
1355 | } |
||
1356 | |||
1357 | 9 | protected function styles() |
|
1358 | { |
||
1359 | // Used in $this->display() |
||
1360 | 9 | $styles = array(); |
|
1361 | 9 | if (isset($this->data['ico'])) { |
|
1362 | 6 | $styles[] = '<link rel="shortcut icon" href="'.$this->data['ico'].'">'; |
|
1363 | 6 | } |
|
1364 | 9 | if (isset($this->data['apple'])) { |
|
1365 | 6 | $styles[] = '<link rel="apple-touch-icon" href="'.$this->data['apple'].'">'; |
|
1366 | 6 | } |
|
1367 | 9 | if (isset($this->filters['prepend']['css'])) { |
|
1368 | 1 | $this->link($this->filters['prepend']['css'], 'prepend'); |
|
1369 | 1 | } |
|
1370 | 9 | if (isset($this->filters['append']['css'])) { |
|
1371 | 1 | $this->link($this->filters['append']['css']); |
|
1372 | 1 | } |
|
1373 | 9 | unset($this->filters['prepend']['css'], $this->filters['append']['css']); |
|
1374 | 9 | $css = (isset($this->data['css'])) ? $this->data['css'] : array(); |
|
1375 | 9 | $css = $this->process('css', array_unique($css)); |
|
1376 | 9 | foreach ($css as $url) { |
|
1377 | 7 | $styles[] = '<link rel="stylesheet" href="'.$url.'">'; |
|
1378 | 9 | } |
|
1379 | 9 | if (isset($this->data['style'])) { |
|
1380 | 6 | foreach ($this->data['style'] as $style) { |
|
1381 | 6 | $styles[] = $style; |
|
1382 | 6 | } |
|
1383 | 6 | } |
|
1384 | 9 | if (isset($this->data['other'])) { |
|
1385 | 6 | foreach ($this->data['other'] as $other) { |
|
1386 | 6 | $styles[] = $other; |
|
1387 | 6 | } |
|
1388 | 6 | } |
|
1389 | |||
1390 | 9 | return $styles; |
|
1391 | } |
||
1392 | |||
1393 | 9 | protected function scripts() |
|
1394 | { |
||
1395 | // Used in $this->display() |
||
1396 | 9 | $scripts = array(); |
|
1397 | 9 | if (isset($this->filters['prepend']['javascript'])) { |
|
1398 | 1 | $this->link($this->filters['prepend']['javascript'], 'prepend'); |
|
1399 | 1 | } |
|
1400 | 9 | $jquery = (isset($this->html['jquery'])) ? $this->html['jquery'] : false; |
|
1401 | 9 | $code = (isset($this->data['jquery'])) ? $this->data['jquery'] : false; |
|
1402 | 9 | if ($jquery || $code) { |
|
1403 | 4 | if (isset($code['ui'])) { |
|
1404 | 3 | $this->link($code['ui'] ? $code['ui'] : 'https://cdn.jsdelivr.net/jquery.ui/1.11.4/jquery-ui.min.js', 'prepend'); |
|
1405 | 3 | unset($code['ui']); |
|
1406 | 3 | } |
|
1407 | 4 | $this->link($jquery ? $jquery : 'https://cdn.jsdelivr.net/jquery/1.12.3/jquery.min.js', 'prepend'); |
|
1408 | 4 | if ($code) { |
|
1409 | 4 | $code = array_filter(array_unique($code)); |
|
1410 | 4 | } |
|
1411 | 4 | if (!empty($code)) { |
|
1412 | 4 | foreach ($code as $key => $value) { |
|
1413 | 4 | $code[$key] = $this->indent($value); |
|
1414 | 4 | } |
|
1415 | 4 | $this->script('$(document).ready(function(){'."\n".implode("\n", $code)."\n".'});'); |
|
1416 | 4 | } |
|
1417 | 4 | } |
|
1418 | 9 | if (isset($this->filters['append']['javascript'])) { |
|
1419 | 1 | $this->link($this->filters['append']['javascript']); |
|
1420 | 1 | } |
|
1421 | 9 | unset($this->filters['prepend']['javascript'], $this->filters['append']['javascript']); |
|
1422 | 9 | $javascript = (isset($this->data['js'])) ? $this->data['js'] : array(); |
|
1423 | 9 | $javascript = $this->process('javascript', array_unique($javascript)); |
|
1424 | 9 | foreach ($javascript as $url) { |
|
1425 | 8 | $scripts[] = '<script src="'.$url.'"></script>'; |
|
1426 | 9 | } |
|
1427 | 9 | if (isset($this->data['script'])) { |
|
1428 | 7 | foreach (array_unique($this->data['script']) as $script) { |
|
1429 | 7 | $scripts[] = $script; |
|
1430 | 7 | } |
|
1431 | 7 | } |
|
1432 | |||
1433 | 9 | return $scripts; |
|
1434 | } |
||
1435 | |||
1436 | 5 | protected function indent($string, $tab = "\t") |
|
1437 | { |
||
1438 | // Used in $this->style() and $this->script() |
||
1439 | 5 | $array = preg_split("/\r\n|\n|\r/", trim($string)); |
|
1440 | 5 | $first = $tab.trim(array_shift($array)); |
|
1441 | 5 | if (empty($array)) { |
|
1442 | 4 | return $first; // ie. no indentation at all |
|
1443 | } |
||
1444 | 5 | $spaces = array(); |
|
1445 | 5 | foreach ($array as $value) { |
|
1446 | 5 | $spaces[] = strspn($value, " \t"); |
|
1447 | 5 | } |
|
1448 | 5 | $spaces = min($spaces); |
|
1449 | 5 | foreach ($array as $key => $value) { |
|
1450 | 5 | $array[$key] = $tab.substr($value, $spaces); |
|
1451 | 5 | } |
|
1452 | 5 | array_unshift($array, $first); |
|
1453 | |||
1454 | 5 | return implode("\n", $array); |
|
1455 | } |
||
1456 | |||
1457 | 70 | protected function formatLocalPath($url, $array = false) |
|
1458 | { |
||
1459 | 70 | if (!preg_match('/^((?!((f|ht)tps?:)?\/\/)|'.$this->url['preg'].'?)(['.$this->url['chars'].'\/]+)?(\.[a-z0-9]*)?(.*)$/i', $url, $matches)) { |
|
1460 | 8 | return ($array) ? array($url, '', '', '') : $url; |
|
1461 | } |
||
1462 | 63 | list($full, $url, $not, $applicable, $path, $suffix, $query) = $matches; |
|
0 ignored issues
–
show
The assignment to
$full is unused. Consider omitting it like so list($first,,$third) .
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
![]() The assignment to
$url is unused. Consider omitting it like so list($first,,$third) .
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
![]() The assignment to
$not is unused. Consider omitting it like so list($first,,$third) .
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
![]() The assignment to
$applicable is unused. Consider omitting it like so list($first,,$third) .
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
![]() |
|||
1463 | 63 | $url = $this->url['base']; |
|
1464 | 63 | $path = trim($path, '/'); |
|
1465 | 63 | if ($path == 'index') { |
|
1466 | 5 | $path = ''; |
|
1467 | 5 | } |
|
1468 | 63 | if (in_array($suffix, $this->url['html'])) { |
|
1469 | 56 | $suffix = (!empty($path)) ? $this->url['suffix'] : ''; |
|
1470 | 56 | } |
|
1471 | |||
1472 | 63 | return ($array) ? array($url, $path, $suffix, $query) : $url.$path.$suffix.$query; |
|
1473 | } |
||
1474 | |||
1475 | 43 | protected function __construct() |
|
1476 | { |
||
1477 | 43 | } |
|
1478 | } |
||
1479 |
Let’s assume you have a class which uses late-static binding:
The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the
getSomeVariable()
on that sub-class, you will receive a runtime error:In the case above, it makes sense to update
SomeClass
to useself
instead: