Version: current

      1 <?php
      2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
      3 // +----------------------------------------------------------------------+
      4 // | PHP Version 4                                                        |
      5 // +----------------------------------------------------------------------+
      6 // | Copyright (c) 1997-2003 The PHP Group                                |
      7 // +----------------------------------------------------------------------+
      8 // | This source file is subject to version 2.02 of the PHP license,      |
      9 // | that is bundled with this package in the file LICENSE, and is        |
     10 // | available at through the world-wide-web at                           |
     11 // | http://www.php.net/license/2_02.txt.                                 |
     12 // | If you did not receive a copy of the PHP license and are unable to   |
     13 // | obtain it through the world-wide-web, please send a note to          |
     14 // | license@php.net so we can mail you a copy immediately.               |
     15 // +----------------------------------------------------------------------+
     16 // | Author: Stijn de Reede <sjr@gmx.co.uk>                               |
     17 // +----------------------------------------------------------------------+
     18 //
     19 // $Id: Links.php,v 1.12 2007/07/02 18:26:17 cweiske Exp $
     20 //
     21
     22 /**
     23  * @package  sapphire
     24  * @subpackage misc
     25  * @author   Stijn de Reede  <sjr@gmx.co.uk>
     26  */
     27
     28 /**
     29  */
     30 require_once 'HTML/BBCodeParser/Filter.php';
     31
     32 /**
     33  * @package  sapphire
     34  * @subpackage misc
     35  */
     36 class SSHTMLBBCodeParser_Filter_Links extends SSHTMLBBCodeParser_Filter
     37 {
     38     /**
     39      * List of allowed schemes
     40      *
     41      * @access  private
     42      * @var     array
     43      */
     44     var $_allowedSchemes = array('http', 'https', 'ftp');
     45
     46     /**
     47      * Default scheme
     48      *
     49      * @access  private
     50      * @var     string
     51      */
     52     var $_defaultScheme = 'http';
     53
     54     /**
     55      * An array of tags parsed by the engine
     56      *
     57      * @access   private
     58      * @var      array
     59      */
     60     var $_definedTags = array(
     61         'url' => array(
     62             'htmlopen'  => 'a',
     63             'htmlclose' => 'a',
     64             'allowed'   => 'none^img',
     65             'attributes'=> array('url' => 'href=%2$s%1$s%2$s')
     66         )
     67     );
     68
     69
     70     /**
     71      * Executes statements before the actual array building starts
     72      *
     73      * This method should be overwritten in a filter if you want to do
     74      * something before the parsing process starts. This can be useful to
     75      * allow certain short alternative tags which then can be converted into
     76      * proper tags with preg_replace() calls.
     77      * The main class walks through all the filters and and calls this
     78      * method if it exists. The filters should modify their private $_text
     79      * variable.
     80      *
     81      * @return   none
     82      * @access   private
     83      * @see      $_text
     84      * @author   Stijn de Reede <sjr@gmx.co.uk>
     85      * @author   Seth Price <seth@pricepages.org>
     86      */
     87     function _preparse()
     88     {
     89         $options = SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser', '_options');
     90         $o = $options['open'];
     91         $c = $options['close'];
     92         $oe = $options['open_esc'];
     93         $ce = $options['close_esc'];
     94
     95         $schemes = implode('|', $this->_allowedSchemes);
     96
     97         $pattern = array(   "/(?<![\"'=".$ce."\/])(".$oe."[^".$ce."]*".$ce.")?(((".$schemes."):\/\/|www)[@-a-z0-9.]+\.[a-z]{2,4}[^\s()\[\]]*)/i",
     98                             "!".$oe."url(".$ce."|\s.*".$ce.")(.*)".$oe."/url".$ce."!iU",
     99                             "!".$oe."url=((([a-z]*:(//)?)|www)[@-a-z0-9.]+)([^\s\[\]]*)".$ce."(.*)".$oe."/url".$ce."!i");
    100
    101         $pp = preg_replace_callback($pattern[0], array($this, 'smarterPPLinkExpand'), $this->_text);
    102         $pp = preg_replace($pattern[1], $o."url=\$2\$1\$2".$o."/url".$c, $pp);
    103         $this->_preparsed = preg_replace_callback($pattern[2], array($this, 'smarterPPLink'), $pp);
    104
    105     }
    106
    107     /**
    108      * Intelligently expand a URL into a link
    109      *
    110      * @return  string
    111      * @access  private
    112      * @author  Seth Price <seth@pricepages.org>
    113      * @author  Lorenzo Alberton <l.alberton@quipo.it>
    114      */
    115     function smarterPPLinkExpand($matches)
    116     {
    117         $options = SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser','_options');
    118         $o = $options['open'];
    119         $c = $options['close'];
    120
    121         //If we have an intro tag that is [url], then skip this match
    122         if ($matches[1] == $o.'url'.$c) {
    123             return $matches[0];
    124         }
    125
    126         if(!BBCodeParser::autolinkUrls()){
    127             return $matches[0];
    128         }
    129
    130
    131         $punctuation = '.,;:'; // Links can't end with these chars
    132         $trailing = '';
    133         // Knock off ending punctuation
    134         $last = substr($matches[2], -1);
    135         while (strpos($punctuation, $last) !== false) {
    136             // Last character is punctuation - remove it from the url
    137             $trailing = $last.$trailing;
    138             $matches[2] = substr($matches[2], 0, -1);
    139             $last = substr($matches[2], -1);
    140         }
    141
    142         $off = strpos($matches[2], ':');
    143
    144         //Is a ":" (therefore a scheme) defined?
    145         if ($off === false) {
    146             /*
    147              * Create a link with the default scheme of http. Notice that the
    148              * text that is viewable to the user is unchanged, but the link
    149              * itself contains the "http://".
    150              */
    151             return $matches[1].$o.'url='.$this->_defaultScheme.'://'.$matches[2].$c.$matches[2].$o.'/url'.$c.$trailing;
    152         }
    153
    154         $scheme = substr($matches[2], 0, $off);
    155
    156         /*
    157          * If protocol is in the approved list than allow it. Note that this
    158          * check isn't really needed, but the created link will just be deleted
    159          * later in smarterPPLink() if we create it now and it isn't on the
    160          * scheme list.
    161          */
    162         if (in_array($scheme, $this->_allowedSchemes)) {
    163             return $matches[1].$o.'url'.$c.$matches[2].$o.'/url'.$c.$trailing;
    164         }
    165
    166         return $matches[0];
    167     }
    168
    169     /**
    170      * Finish preparsing URL to clean it up
    171      *
    172      * @return  string
    173      * @access  private
    174      * @author  Seth Price <seth@pricepages.org>
    175      */
    176     function smarterPPLink($matches)
    177     {
    178         $options = SSHTMLBBCodeParser::getStaticProperty('SSHTMLBBCodeParser','_options');
    179         $o = $options['open'];
    180         $c = $options['close'];
    181
    182         $urlServ = $matches[1];
    183         $path = $matches[5];
    184
    185         $off = strpos($urlServ, ':');
    186
    187         if ($off === false) {
    188             //Default to http
    189             $urlServ = $this->_defaultScheme.'://'.$urlServ;
    190             $off = strpos($urlServ, ':');
    191         }
    192
    193         //Add trailing slash if missing (to create a valid URL)
    194         if (!$path) {
    195             $path = '/';
    196         }
    197
    198         $protocol = substr($urlServ, 0, $off);
    199
    200         if (in_array($protocol, $this->_allowedSchemes)) {
    201             //If protocol is in the approved list than allow it
    202             return $o.'url='.$urlServ.$path.$c.$matches[6].$o.'/url'.$c;
    203         }
    204
    205         //Else remove url tag
    206         return $matches[6];
    207     }
    208 }
    209 ?>

[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. -