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

  • FilesystemPublisher
  • RsyncMultiHostPublisher
  • StaticPublisher
  1 <?php
  2 
  3 /**
  4  * Usage: Object::add_extension("SiteTree", "FilesystemPublisher('static-folder', 'html')");
  5  * 
  6  * Usage: To work with Subsite module you need to:
  7  * - Add FilesystemPublisher::$domain_based_caching = true; in mysite/_config.php
  8  * - Added main site host mapping in subsites/host-map.php after everytime a new subsite is created or modified 
  9  *
 10  * You may also have a method $page->pagesAffectedByUnpublishing() to return other URLS
 11  * that should be de-cached if $page is unpublished.
 12  *
 13  * @see http://doc.silverstripe.com/doku.php?id=staticpublisher
 14  * 
 15  * @package cms
 16  * @subpackage publishers
 17  */
 18 class FilesystemPublisher extends StaticPublisher {
 19 
 20     /**
 21      * @var String
 22      */
 23     protected $destFolder = 'cache';
 24     
 25     /**
 26      * @var String
 27      */
 28     protected $fileExtension = 'html';
 29     
 30     /**
 31      * @var String
 32      */
 33     protected static $static_base_url = null;
 34     
 35     /**
 36      * @var Boolean Use domain based cacheing (put cache files into a domain subfolder)
 37      * This must be true if you are using this with the "subsites" module.
 38      * Please note that this form of caching requires all URLs to be provided absolute
 39      * (not relative to the webroot) via {@link SiteTree->AbsoluteLink()}.
 40      */
 41     public static $domain_based_caching = false;
 42     
 43     /**
 44      * Set a different base URL for the static copy of the site.
 45      * This can be useful if you are running the CMS on a different domain from the website.
 46      */
 47     static function set_static_base_url($url) {
 48         self::$static_base_url = $url;
 49     }
 50     
 51     /**
 52      * @param $destFolder The folder to save the cached site into.
 53      *   This needs to be set in sapphire/static-main.php as well through the {@link $cacheBaseDir} variable.
 54      * @param $fileExtension  The file extension to use, e.g 'html'.  
 55      *   If omitted, then each page will be placed in its own directory, 
 56      *   with the filename 'index.html'.  If you set the extension to PHP, then a simple PHP script will
 57      *   be generated that can do appropriate cache & redirect header negotation.
 58      */
 59     function __construct($destFolder, $fileExtension = null) {
 60         // Remove trailing slash from folder
 61         if(substr($destFolder, -1) == '/') $destFolder = substr($destFolder, 0, -1);
 62         
 63         $this->destFolder = $destFolder;
 64         $this->fileExtension = $fileExtension;
 65         
 66         parent::__construct();
 67     }
 68     
 69     /**
 70      * Transforms relative or absolute URLs to their static path equivalent.
 71      * This needs to be the same logic that's used to look up these paths through
 72      * sapphire/static-main.php. Does not include the {@link $destFolder} prefix.
 73      * Replaces various special characters in the resulting filename similar to {@link SiteTree::generateURLSegment()}.
 74      * 
 75      * Examples (without $domain_based_caching):
 76      *  - http://mysite.com/mywebroot/ => /index.html (assuming your webroot is in a subfolder)
 77      *  - http://mysite.com/about-us => /about-us.html
 78      *  - http://mysite.com/parent/child => /parent/child.html
 79      * 
 80      * Examples (with $domain_based_caching):
 81      *  - http://mysite.com/mywebroot/ => /mysite.com/index.html (assuming your webroot is in a subfolder)
 82      *  - http://mysite.com/about-us => /mysite.com/about-us.html
 83      *  - http://myothersite.com/about-us => /myothersite.com/about-us.html
 84      *  - http://subdomain.mysite.com/parent/child => /subdomain.mysite.com/parent/child.html
 85      * 
 86      * @param Array $urls Absolute or relative URLs
 87      * @return Array Map of original URLs to filesystem paths (relative to {@link $destFolder}).
 88      */
 89     function urlsToPaths($urls) {
 90         $mappedUrls = array();
 91         foreach($urls as $url) {
 92             $urlParts = @parse_url($url);
 93             
 94             // Remove base folders from the URL if webroot is hosted in a subfolder (same as static-main.php)
 95             $path = isset($urlParts['path']) ? $urlParts['path'] : '';
 96             if(substr(strtolower($path), 0, strlen(BASE_URL)) == strtolower(BASE_URL)) {
 97                 $urlSegment = substr($path, strlen(BASE_URL));
 98             } else {
 99                 $urlSegment = $path;
100             }
101 
102             // perform similar transformations to SiteTree::generateURLSegment()
103             $urlSegment = str_replace('&amp;','-and-',$urlSegment);
104             $urlSegment = str_replace('&','-and-',$urlSegment);
105             $urlSegment = ereg_replace('[^A-Za-z0-9\/-]+','-',$urlSegment);
106             $urlSegment = ereg_replace('-+','-',$urlSegment);
107             $urlSegment = trim($urlSegment, '/');
108 
109             $filename = $urlSegment ? "$urlSegment.$this->fileExtension" : "index.$this->fileExtension";
110 
111             if (self::$domain_based_caching) {
112                 if (!$urlParts) continue; // seriously malformed url here...
113                 $filename = $urlParts['host'] . '/' . $filename;
114             }
115         
116             $mappedUrls[$url] = ((dirname($filename) == '/') ? '' :  (dirname($filename).'/')).basename($filename);
117         }
118 
119         return $mappedUrls;
120     }
121     
122     function unpublishPages($urls) {
123         // Do we need to map these?
124         // Detect a numerically indexed arrays
125         if (is_numeric(join('', array_keys($urls)))) $urls = $this->urlsToPaths($urls);
126         
127         // This can be quite memory hungry and time-consuming
128         // @todo - Make a more memory efficient publisher
129         increase_time_limit_to();
130         increase_memory_limit_to();
131         
132         $cacheBaseDir = $this->getDestDir();
133         
134         foreach($urls as $url => $path) {
135             if (file_exists($cacheBaseDir.'/'.$path)) {
136                 @unlink($cacheBaseDir.'/'.$path);
137             }
138         }
139     }
140     
141     function publishPages($urls) { 
142         // Do we need to map these?
143         // Detect a numerically indexed arrays
144         if (is_numeric(join('', array_keys($urls)))) $urls = $this->urlsToPaths($urls);
145         
146         // This can be quite memory hungry and time-consuming
147         // @todo - Make a more memory efficient publisher
148         increase_time_limit_to();
149         increase_memory_limit_to();
150         
151         // Set the appropriate theme for this publication batch.
152         // This may have been set explicitly via StaticPublisher::static_publisher_theme,
153         // or we can use the last non-null theme.
154         if(!StaticPublisher::static_publisher_theme())
155             SSViewer::set_theme(SSViewer::current_custom_theme());
156         else
157             SSViewer::set_theme(StaticPublisher::static_publisher_theme());
158             
159         $currentBaseURL = Director::baseURL();
160         if(self::$static_base_url) Director::setBaseURL(self::$static_base_url);
161         if($this->fileExtension == 'php') SSViewer::setOption('rewriteHashlinks', 'php'); 
162         if(StaticPublisher::echo_progress()) echo $this->class.": Publishing to " . self::$static_base_url . "\n";      
163         $files = array();
164         $i = 0;
165         $totalURLs = sizeof($urls);
166 
167         foreach($urls as $url => $path) {
168             
169             if(self::$static_base_url) Director::setBaseURL(self::$static_base_url);
170             $i++;
171 
172             if($url && !is_string($url)) {
173                 user_error("Bad url:" . var_export($url,true), E_USER_WARNING);
174                 continue;
175             }
176             
177             if(StaticPublisher::echo_progress()) {
178                 echo " * Publishing page $i/$totalURLs: $url\n";
179                 flush();
180             }
181 
182             Requirements::clear();
183             
184             if(Director::is_relative_url($url)) $url = Director::absoluteURL($url);
185             $response = Director::test(str_replace('+', ' ', $url));
186             
187             Requirements::clear();
188             
189             
190             
191             singleton('DataObject')->flushCache();
192 
193             // Generate file content            
194             // PHP file caching will generate a simple script from a template
195             if($this->fileExtension == 'php') {
196                 if(is_object($response)) {
197                     if($response->getStatusCode() == '301' || $response->getStatusCode() == '302') {
198                         $content = $this->generatePHPCacheRedirection($response->getHeader('Location'));
199                     } else {
200                         $content = $this->generatePHPCacheFile($response->getBody(), HTTP::get_cache_age(), date('Y-m-d H:i:s'));
201                     }
202                 } else {
203                     $content = $this->generatePHPCacheFile($response . '', HTTP::get_cache_age(), date('Y-m-d H:i:s'));
204                 }
205                 
206             // HTML file caching generally just creates a simple file
207             } else {
208                 if(is_object($response)) {
209                     if($response->getStatusCode() == '301' || $response->getStatusCode() == '302') {
210                         $absoluteURL = Director::absoluteURL($response->getHeader('Location'));
211                         $content = "<meta http-equiv=\"refresh\" content=\"2; URL=$absoluteURL\">";
212                     } else {
213                         $content = $response->getBody();
214                     }
215                 } else {
216                     $content = $response . '';
217                 }
218             }
219             
220             $files[] = array(
221                 'Content' => $content,
222                 'Folder' => dirname($path).'/',
223                 'Filename' => basename($path),
224             );
225             
226             // Add externals
227             /*
228             $externals = $this->externalReferencesFor($content);
229             if($externals) foreach($externals as $external) {
230                 // Skip absolute URLs
231                 if(preg_match('/^[a-zA-Z]+:\/\//', $external)) continue;
232                 // Drop querystring parameters
233                 $external = strtok($external, '?');
234                 
235                 if(file_exists("../" . $external)) {
236                     // Break into folder and filename
237                     if(preg_match('/^(.*\/)([^\/]+)$/', $external, $matches)) {
238                         $files[$external] = array(
239                             "Copy" => "../$external",
240                             "Folder" => $matches[1],
241                             "Filename" => $matches[2],
242                         );
243                     
244                     } else {
245                         user_error("Can't parse external: $external", E_USER_WARNING);
246                     }
247                 } else {
248                     $missingFiles[$external] = true;
249                 }
250             }*/
251         }
252 
253         if(self::$static_base_url) Director::setBaseURL($currentBaseURL); 
254         if($this->fileExtension == 'php') SSViewer::setOption('rewriteHashlinks', true); 
255 
256         $base = BASE_PATH . "/$this->destFolder";
257         foreach($files as $file) {
258             Filesystem::makeFolder("$base/$file[Folder]");
259             
260             if(isset($file['Content'])) {
261                 $fh = fopen("$base/$file[Folder]$file[Filename]", "w");
262                 fwrite($fh, $file['Content']);
263                 fclose($fh);
264             } else if(isset($file['Copy'])) {
265                 copy($file['Copy'], "$base/$file[Folder]$file[Filename]");
266             }
267         }
268     }
269     
270     /**
271      * Generate the templated content for a PHP script that can serve up the given piece of content with the given age and expiry
272      */
273     protected function generatePHPCacheFile($content, $age, $lastModified) {
274         $template = file_get_contents(BASE_PATH . '/cms/code/staticpublisher/CachedPHPPage.tmpl');
275         return str_replace(
276                 array('**MAX_AGE**', '**LAST_MODIFIED**', '**CONTENT**'),
277                 array((int)$age, $lastModified, $content),
278                 $template);
279     }
280     /**
281      * Generate the templated content for a PHP script that can serve up a 301 redirect to the given destionation
282      */
283     protected function generatePHPCacheRedirection($destination) {
284         $template = file_get_contents(BASE_PATH . '/cms/code/staticpublisher/CachedPHPRedirection.tmpl');
285         return str_replace(
286                 array('**DESTINATION**'),
287                 array($destination),
288                 $template);
289     }
290     
291     public function getDestDir() {
292         return BASE_PATH . '/' . $this->destFolder;
293     }
294     
295     /**
296      * Return an array of all the existing static cache files, as a map of URL => file.
297      * Only returns cache files that will actually map to a URL, based on urlsToPaths.
298      */
299     public function getExistingStaticCacheFiles() {
300         $cacheDir = BASE_PATH . '/' . $this->destFolder;
301 
302         $urlMapper = array_flip($this->urlsToPaths($this->owner->allPagesToCache()));
303         
304         $output = array();
305         
306         // Glob each dir, then glob each one of those
307         foreach(glob("$cacheDir/*", GLOB_ONLYDIR) as $cacheDir) {
308             foreach(glob($cacheDir.'/*') as $cacheFile) {
309                 $mapKey = str_replace(BASE_PATH . "/cache/","",$cacheFile);
310                 if(isset($urlMapper[$mapKey])) {
311                     $url = $urlMapper[$mapKey];
312                     $output[$url] = $cacheFile;
313                 }
314             }
315         }
316         
317         return $output;
318     }
319     
320 }
321 
322 ?>
[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