Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • Announcement_Controller
  • AnnouncementHolder_Controller
  • BookingAdminPage_Controller
  • BookingPage_Controller
  • Cart_Controller
  • CartPage_Controller
  • Catalog_Controller
  • CheckoutPage_Controller
  • ChequePayment_Handler
  • ContactsPage_Controller
  • ContentController
  • ContentNegotiator
  • Controller
  • DataObjectManager_Controller
  • DatePickerField_Controller
  • Director
  • DocPage_Controller
  • DocumentsPage_Controller
  • Event_Controller
  • EventHolder_Controller
  • FileDataObjectManager_Controller
  • FindCyrillic_Controller
  • HomePage_Controller
  • LastDoc_Controller
  • LiveCalendarWidget_Controller
  • MapObject_Controller
  • MapObjectGroup_Controller
  • MapPage_Controller
  • MediawebPage_Controller
  • ModelAsController
  • MultiUploadControls
  • NewsArchive
  • Orders1CExchange_Controller
  • Page_Controller
  • Payment_Handler
  • PhotoAlbumManager_Controller
  • Product_Controller
  • ProductSearchPage_Controller
  • ProfilePage_Controller
  • PublHolder_Controller
  • Publication_Controller
  • RatingExtension_Controller
  • RegistrationPage_Controller
  • RemoveOrphanedPagesTask
  • RequestHandler
  • Room_Controller
  • RoomCatalog_Controller
  • RootURLController
  • SapphireInfo
  • Search_Controller
  • Session
  • SimpleOrderPage_Controller
  • SiteMap_Controller
  • SpecialCatalog_Controller
  • SS_HTTPRequest
  • SS_HTTPResponse
  • StartCatalog_Controller
  • SubsitesSelectorPage_Controller
  • VideoBankPage_Controller

Interfaces

  • NestedController

Exceptions

  • SS_HTTPResponse_Exception
  1 <?php
  2 
  3 /**
  4  * Represents a HTTP-request, including a URL that is tokenised for parsing, and a request method (GET/POST/PUT/DELETE).
  5  * This is used by {@link RequestHandler} objects to decide what to do.
  6  * 
  7  * The intention is that a single SS_HTTPRequest object can be passed from one object to another, each object calling
  8  * match() to get the information that they need out of the URL.  This is generally handled by 
  9  * {@link RequestHandler::handleRequest()}.
 10  * 
 11  * @todo Accept X_HTTP_METHOD_OVERRIDE http header and $_REQUEST['_method'] to override request types (useful for webclients
 12  *   not supporting PUT and DELETE)
 13  * 
 14  * @package sapphire
 15  * @subpackage control
 16  */
 17 class SS_HTTPRequest implements ArrayAccess {
 18 
 19     /**
 20      * @var string $url
 21      */
 22     protected $url;
 23 
 24     /**
 25      * The non-extension parts of the passed URL as an array, originally exploded by the "/" separator.
 26      * All elements of the URL are loaded in here,
 27      * and subsequently popped out of the array by {@link shift()}.
 28      * Only use this structure for internal request handling purposes.
 29      */
 30     protected $dirParts;
 31     
 32     /**
 33      * @var string $extension The URL extension (if present)
 34      */
 35     protected $extension;
 36     
 37     /**
 38      * @var string $httpMethod The HTTP method in all uppercase: GET/PUT/POST/DELETE/HEAD
 39      */
 40     protected $httpMethod;
 41     
 42     /**
 43      * @var array $getVars Contains alls HTTP GET parameters passed into this request.
 44      */
 45     protected $getVars = array();
 46     
 47     /**
 48      * @var array $postVars Contains alls HTTP POST parameters passed into this request.
 49      */
 50     protected $postVars = array();
 51 
 52     /**
 53      * HTTP Headers like "Content-Type: text/xml"
 54      *
 55      * @see http://en.wikipedia.org/wiki/List_of_HTTP_headers
 56      * @var array
 57      */
 58     protected $headers = array();
 59     
 60     /**
 61      * Raw HTTP body, used by PUT and POST requests.
 62      *
 63      * @var string
 64      */
 65     protected $body;
 66     
 67     /**
 68      * @var array $allParams Contains an assiciative array of all
 69      * arguments matched in all calls to {@link RequestHandler->handleRequest()}.
 70      * It's a "historical record" that's specific to the current call of
 71      * {@link handleRequest()}, and is only complete once the "last call" to that method is made.
 72      */
 73     protected $allParams = array();
 74     
 75     /**
 76      * @var array $latestParams Contains an associative array of all
 77      * arguments matched in the current call from {@link RequestHandler->handleRequest()},
 78      * as denoted with a "$"-prefix in the $url_handlers definitions.
 79      * Contains different states throughout its lifespan, so just useful
 80      * while processed in {@link RequestHandler} and to get the last
 81      * processes arguments.
 82      */
 83     protected $latestParams = array();
 84     
 85     protected $unshiftedButParsedParts = 0;
 86     
 87     /**
 88      * Construct a SS_HTTPRequest from a URL relative to the site root.
 89      */
 90     function __construct($httpMethod, $url, $getVars = array(), $postVars = array(), $body = null) {
 91         $this->httpMethod = strtoupper(self::detect_method($httpMethod, $postVars));
 92         $this->url = $url;
 93         
 94         if(Director::is_relative_url($url)) {
 95             $this->url = preg_replace(array('/\/+/','/^\//', '/\/$/'),array('/','',''), $this->url);
 96         }
 97         if(preg_match('/^(.*)\.([A-Za-z][A-Za-z0-9]*)$/', $this->url, $matches)) {
 98             $this->url = $matches[1];
 99             $this->extension = $matches[2];
100         }
101         if($this->url) $this->dirParts = preg_split('|/+|', $this->url);
102         else $this->dirParts = array();
103         
104         $this->getVars = (array)$getVars;
105         $this->postVars = (array)$postVars;
106         $this->body = $body;
107     }
108     
109     function isGET() {
110         return $this->httpMethod == 'GET';
111     }
112     
113     function isPOST() {
114         return $this->httpMethod == 'POST';
115     }
116     
117     function isPUT() {
118         return $this->httpMethod == 'PUT';
119     }
120 
121     function isDELETE() {
122         return $this->httpMethod == 'DELETE';
123     }   
124 
125     function isHEAD() {
126         return $this->httpMethod == 'HEAD';
127     }   
128     
129     function setBody($body) {
130         $this->body = $body;
131     }
132     
133     function getBody() {
134         return $this->body;
135     }
136     
137     function getVars() {
138         return $this->getVars;
139     }
140     function postVars() {
141         return $this->postVars;
142     }
143     
144     /**
145      * Returns all combined HTTP GET and POST parameters
146      * passed into this request. If a parameter with the same
147      * name exists in both arrays, the POST value is returned.
148      * 
149      * @return array
150      */
151     function requestVars() {
152         return array_merge($this->getVars, $this->postVars);
153     }
154     
155     function getVar($name) {
156         if(isset($this->getVars[$name])) return $this->getVars[$name];
157     }
158     
159     function postVar($name) {
160         if(isset($this->postVars[$name])) return $this->postVars[$name];
161     }
162     
163     function requestVar($name) {
164         if(isset($this->postVars[$name])) return $this->postVars[$name];
165         if(isset($this->getVars[$name])) return $this->getVars[$name];
166     }
167     
168     /**
169      * Returns a possible file extension found in parsing the URL
170      * as denoted by a "."-character near the end of the URL.
171      * Doesn't necessarily have to belong to an existing file,
172      * for example used for {@link RestfulServer} content-type-switching.
173      * 
174      * @return string
175      */
176     function getExtension() {
177         return $this->extension;
178     }
179     
180     /**
181      * Checks if the {@link SS_HTTPRequest->getExtension()} on this request matches one of the more common media types
182      * embedded into a webpage - e.g. css, png.
183      *
184      * This is useful for things like determining wether to display a fully rendered error page or not. Note that the
185      * media file types is not at all comprehensive.
186      *
187      * @return bool
188      */
189     public function isMedia() {
190         return in_array($this->getExtension(), array('css', 'js', 'jpg', 'jpeg', 'gif', 'png', 'bmp', 'ico'));
191     }
192     
193     /**
194      * Add a HTTP header to the response, replacing any header of the same name.
195      * 
196      * @param string $header Example: "Content-Type"
197      * @param string $value Example: "text/xml" 
198      */
199     function addHeader($header, $value) {
200         $this->headers[$header] = $value;
201     }
202     
203     /**
204      * @return array
205      */
206     function getHeaders() {
207         return $this->headers;
208     }
209     
210     /**
211      * Remove an existing HTTP header
212      *
213      * @param string $header
214      */
215     function getHeader($header) {
216         return (isset($this->headers[$header])) ? $this->headers[$header] : null;           
217     }
218     
219     /**
220      * Remove an existing HTTP header by its name,
221      * e.g. "Content-Type".
222      *
223      * @param string $header
224      */
225     function removeHeader($header) {
226         if(isset($this->headers[$header])) unset($this->headers[$header]);
227     }
228     
229     /**
230      * @return string
231      */
232     function getURL() {
233         return ($this->getExtension()) ? $this->url . '.' . $this->getExtension() : $this->url; 
234     }
235     
236     /**
237      * Enables the existence of a key-value pair in the request to be checked using
238      * array syntax, so isset($request['title']) will check for $_POST['title'] and $_GET['title']
239      *
240      * @param unknown_type $offset
241      * @return boolean
242      */
243     function offsetExists($offset) {
244         if(isset($this->postVars[$offset])) return true;
245         if(isset($this->getVars[$offset])) return true;
246         return false;
247     }
248     
249     /**
250      * Access a request variable using array syntax. eg: $request['title'] instead of $request->postVar('title')
251      *
252      * @param unknown_type $offset
253      * @return unknown
254      */
255     function offsetGet($offset) {
256         return $this->requestVar($offset);
257     }
258     
259     /**
260      * @ignore
261      */
262     function offsetSet($offset, $value) {}
263     
264     /**
265      * @ignore
266      */
267     function offsetUnset($offset) {}
268     
269     /**
270      * Construct an SS_HTTPResponse that will deliver a file to the client
271      */
272     static function send_file($fileData, $fileName, $mimeType = null) {
273         if(!$mimeType) $mimeType = HTTP::getMimeType($fileName);
274 
275         $response = new SS_HTTPResponse($fileData);
276         $response->addHeader("Content-Type", "$mimeType; name=\"" . addslashes($fileName) . "\"");
277         $response->addHeader("Content-disposition", "attachment; filename=" . addslashes($fileName));
278         $response->addHeader("Content-Length", strlen($fileData));
279         $response->addHeader("Pragma", ""); // Necessary because IE has issues sending files over SSL
280         
281         return $response;
282     }
283     
284     /**
285      * Matches a URL pattern
286      * The pattern can contain a number of segments, separated by / (and an extension indicated by a .)
287      * 
288      * The parts can be either literals, or, if they start with a $ they are interpreted as variables.
289      *  - Literals must be provided in order to match
290      *  - $Variables are optional
291      *  - However, if you put ! at the end of a variable, then it becomes mandatory.
292      * 
293      * For example:
294      *  - admin/crm/list will match admin/crm/$Action/$ID/$OtherID, but it won't match admin/crm/$Action!/$ClassName!
295      * 
296      * The pattern can optionally start with an HTTP method and a space.  For example, "POST $Controller/$Action".
297      * This is used to define a rule that only matches on a specific HTTP method.
298      */
299     function match($pattern, $shiftOnSuccess = false) {
300         // Check if a specific method is required
301         if(preg_match('/^([A-Za-z]+) +(.*)$/', $pattern, $matches)) {
302             $requiredMethod = $matches[1];
303             if($requiredMethod != $this->httpMethod) return false;
304             
305             // If we get this far, we can match the URL pattern as usual.
306             $pattern = $matches[2];
307         }
308         
309         // Special case for the root URL controller
310         if(!$pattern) {
311             return ($this->dirParts == array()) ? array('Matched' => true) : false;
312         }
313 
314         // Check for the '//' marker that represents the "shifting point"
315         $doubleSlashPoint = strpos($pattern, '//');
316         if($doubleSlashPoint !== false) {
317             $shiftCount = substr_count(substr($pattern,0,$doubleSlashPoint), '/') + 1;
318             $pattern = str_replace('//', '/', $pattern);
319             $patternParts = explode('/', $pattern);
320             
321             
322         } else {
323             $patternParts = explode('/', $pattern);
324             $shiftCount = sizeof($patternParts);
325         }
326 
327         $matched = true;
328         $arguments = array();
329         foreach($patternParts as $i => $part) {
330             $part = trim($part);
331 
332             // Match a variable
333             if(isset($part[0]) && $part[0] == '$') {
334                 // A variable ending in ! is required
335                 if(substr($part,-1) == '!') {
336                     $varRequired = true;
337                     $varName = substr($part,1,-1);
338                 } else {
339                     $varRequired = false;
340                     $varName = substr($part,1);
341                 }
342                 
343                 // Fail if a required variable isn't populated
344                 if($varRequired && !isset($this->dirParts[$i])) return false;
345                 
346                 $arguments[$varName] = isset($this->dirParts[$i]) ? $this->dirParts[$i] : null;
347                 if($part == '$Controller' && (!ClassInfo::exists($arguments['Controller']) || !ClassInfo::is_subclass_of($arguments['Controller'], 'Controller'))) {
348                     return false;
349                 }
350                 
351             // Literal parts with extension
352             } else if(isset($this->dirParts[$i]) && $this->dirParts[$i] . '.' . $this->extension == $part) {
353                 continue;
354                 
355             // Literal parts must always be there
356             } else if(!isset($this->dirParts[$i]) || $this->dirParts[$i] != $part) {
357                 return false;
358             }
359             
360         }
361 
362         if($shiftOnSuccess) {
363             $this->shift($shiftCount);
364             // We keep track of pattern parts that we looked at but didn't shift off.
365             // This lets us say that we have *parsed* the whole URL even when we haven't *shifted* it all
366             $this->unshiftedButParsedParts = sizeof($patternParts) - $shiftCount;
367         }
368 
369         $this->latestParams = $arguments;
370         
371         // Load the arguments that actually have a value into $this->allParams
372         // This ensures that previous values aren't overridden with blanks
373         foreach($arguments as $k => $v) {
374             if($v || !isset($this->allParams[$k])) $this->allParams[$k] = $v;
375         }
376 
377         if($arguments === array()) $arguments['_matched'] = true;
378         return $arguments;
379     }
380     
381     function allParams() {
382         return $this->allParams;
383     }
384     
385     /**
386      * Shift all the parameter values down a key space, and return the shifted value.
387      *
388      * @return string
389      */
390     public function shiftAllParams() {
391         $keys     = array_keys($this->allParams);
392         $values   = array_values($this->allParams);
393         $value    = array_shift($values);
394 
395         // push additional unparsed URL parts onto the parameter stack
396         if(array_key_exists($this->unshiftedButParsedParts, $this->dirParts)) {
397             $values[] = $this->dirParts[$this->unshiftedButParsedParts];
398         }
399 
400         foreach($keys as $position => $key) {
401             $this->allParams[$key] = isset($values[$position]) ? $values[$position] : null;
402         }
403 
404         return $value;
405     }
406     
407     function latestParams() {
408         return $this->latestParams;
409     }
410     function latestParam($name) {
411         if(isset($this->latestParams[$name]))
412             return $this->latestParams[$name];
413         else
414             return null;
415     }
416     
417     /**
418      * Finds a named URL parameter (denoted by "$"-prefix in $url_handlers)
419      * from the full URL.
420      * 
421      * @param string $name
422      * @return string Value of the URL parameter (if found)
423      */
424     function param($name) {
425         if(isset($this->allParams[$name])) return $this->allParams[$name];
426         else return null;
427     }
428     
429     /**
430      * Returns the unparsed part of the original URL
431      * separated by commas. This is used by {@link RequestHandler->handleRequest()}
432      * to determine if further URL processing is necessary.
433      * 
434      * @return string Partial URL
435      */
436     function remaining() {
437         return implode("/", $this->dirParts);
438     }
439     
440     /**
441      * Returns true if this is a URL that will match without shifting off any of the URL.
442      * This is used by the request handler to prevent infinite parsing loops.
443      */
444     function isEmptyPattern($pattern) {
445         if(preg_match('/^([A-Za-z]+) +(.*)$/', $pattern, $matches)) {
446             $pattern = $matches[2];
447         }
448         
449         if(trim($pattern) == "") return true;
450     }
451     
452     /**
453      * Shift one or more parts off the beginning of the URL.
454      * If you specify shifting more than 1 item off, then the items will be returned as an array
455      */
456     function shift($count = 1) {
457         if($count == 1) return array_shift($this->dirParts);
458         else for($i=0;$i<$count;$i++) $return[] = array_shift($this->dirParts);
459     }
460 
461     /**
462      * Returns true if the URL has been completely parsed.
463      * This will respect parsed but unshifted directory parts.
464      */
465     function allParsed() {
466         return sizeof($this->dirParts) <= $this->unshiftedButParsedParts;
467     }
468     
469     /**
470      * Returns the client IP address which
471      * originated this request.
472      *
473      * @return string
474      */
475     function getIP() {
476         if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
477             //check ip from share internet
478             return $_SERVER['HTTP_CLIENT_IP'];
479         } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
480             //to check ip is pass from proxy
481             return  $_SERVER['HTTP_X_FORWARDED_FOR'];
482         } elseif(isset($_SERVER['REMOTE_ADDR'])) {
483             return $_SERVER['REMOTE_ADDR'];
484         }
485     }
486     
487     /**
488      * Returns all mimetypes from the HTTP "Accept" header
489      * as an array.
490      * 
491      * @param boolean $includeQuality Don't strip away optional "quality indicators", e.g. "application/xml;q=0.9" (Default: false)
492      * @return array
493      */
494     function getAcceptMimetypes($includeQuality = false) {
495        $mimetypes = array();
496        $mimetypesWithQuality = explode(',',$this->getHeader('Accept'));
497        foreach($mimetypesWithQuality as $mimetypeWithQuality) {
498           $mimetypes[] = ($includeQuality) ? $mimetypeWithQuality : preg_replace('/;.*/', '', $mimetypeWithQuality);
499        }
500        return $mimetypes;
501     }
502     
503     /**
504      * @return string HTTP method (all uppercase)
505      */
506     public function httpMethod() {
507         return $this->httpMethod;
508     }
509     
510     /**
511      * Gets the "real" HTTP method for a request.
512      * 
513      * Used to work around browser limitations of form
514      * submissions to GET and POST, by overriding the HTTP method
515      * with a POST parameter called "_method" for PUT, DELETE, HEAD.
516      * Using GET for the "_method" override is not supported,
517      * as GET should never carry out state changes.
518      * Alternatively you can use a custom HTTP header 'X-HTTP-Method-Override'
519      * to override the original method in {@link Director::direct()}. 
520      * The '_method' POST parameter overrules the custom HTTP header.
521      *
522      * @param string $origMethod Original HTTP method from the browser request
523      * @param array $postVars
524      * @return string HTTP method (all uppercase)
525      */
526     public static function detect_method($origMethod, $postVars) {
527         if(isset($postVars['_method'])) {
528             if(!in_array(strtoupper($postVars['_method']), array('GET','POST','PUT','DELETE','HEAD'))) {
529                 user_error('Director::direct(): Invalid "_method" parameter', E_USER_ERROR);
530             }
531             return strtoupper($postVars['_method']);
532         } else {
533             return $origMethod;
534         }
535     }
536 }
537 
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0