Viewing file: parsers.php (12.43 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
/**
* A base class for parsers.
*
* In the context of this plugin, a "parser" is a class that knows how to extract or modify
* a specific type of links from a given piece of text. For example, there could be a "HTML Link"
* parser that knows how to find and modify standard HTML links such as this one :
* <a href="http://example.com/">Example</a>
*
* Other parsers could extract plaintext URLs or handle metadata fields.
*
* Each parser has a list of supported formats (e.g. "html", "plaintext", etc) and container types
* (e.g. "post", "comment", "blogroll", etc). When something needs to be parsed, the involved
* container class will look up the parsers that support the relevant format or the container's type,
* and apply them to the to-be-parsed string.
*
* All sub-classes of blcParser should override at least the blcParser::parse() method.
*
* @see blcContainer::$fields
*
* @package Broken Link Checker
* @access public
*/
class blcParser extends blcModule {
var $parser_type;
var $supported_formats = array();
var $supported_containers = array();
/**
* Initialize the parser. Nothing much here.
*
* @return void
*/
function init(){
parent::init();
$this->parser_type = $this->module_id;
}
/**
* Called when the parser is activated.
*
* @return void
*/
function activated(){
parent::activated();
$this->resynch_relevant_containers();
}
/**
* Called when BLC is activated.
*/
function plugin_activated() {
//Intentionally do nothing. BLC can not parse containers while it's inactive, so we can be
//pretty sure that there are no already-parsed containers that need to be resynchronized.
}
/**
* Mark containers that this parser might be interested in as unparsed.
*
* @uses blcContainerHelper::mark_as_unsynched_where()
*
* @param bool $only_return If true, just return the list of formats and container types without actually modifying any synch. records.
* @return void|array Either nothing or an array in the form [ [format1=>timestamp1, ...], [container_type1=>timestamp1, ...] ]
*/
function resynch_relevant_containers($only_return = false){
global $blclog;
$blclog->log(sprintf('...... Parser "%s" is marking relevant items as unsynched', $this->module_id));
$last_deactivated = $this->module_manager->get_last_deactivation_time($this->module_id);
$formats = array();
foreach($this->supported_formats as $format){
$formats[$format] = $last_deactivated;
}
$container_types = array();
foreach($this->supported_containers as $container_type){
$container_types[$container_type] = $last_deactivated;
}
if ( $only_return ){
return array($formats, $container_types);
} else {
blcContainerHelper::mark_as_unsynched_where($formats, $container_types);
}
}
/**
* Parse a string for links.
*
* @param string $content The text to parse.
* @param string $base_url The base URL to use for normalizing relative URLs. If ommitted, the blog's root URL will be used.
* @param string $default_link_text
* @return array An array of new blcLinkInstance objects. The objects will include info about the links found, but not about the corresponding container entity.
*/
function parse($content, $base_url = '', $default_link_text = ''){
return array();
}
/**
* Change all links that have a certain URL to a new URL.
*
* @param string $content Look for links in this string.
* @param string $new_url Change the links to this URL.
* @param string $old_url The URL to look for.
* @param string $old_raw_url The raw, not-normalized URL of the links to look for. Optional.
*
* @return array|WP_Error If successful, the return value will be an associative array with two
* keys : 'content' - the modified content, and 'raw_url' - the new raw, non-normalized URL used
* for the modified links. In most cases, the returned raw_url will be equal to the new_url.
*/
function edit($content, $new_url, $old_url, $old_raw_url){
return new WP_Error(
'not_implemented',
sprintf(__("Editing is not implemented in the '%s' parser", 'broken-link-checker'), $this->parser_type)
);
}
/**
* Remove all links that have a certain URL, leaving anchor text intact.
*
* @param string $content Look for links in this string.
* @param string $url The URL to look for.
* @param string $raw_url The raw, non-normalized version of the URL to look for. Optional.
* @return string Input string with all matching links removed.
*/
function unlink($content, $url, $raw_url){
return new WP_Error(
'not_implemented',
sprintf(__("Unlinking is not implemented in the '%s' parser", 'broken-link-checker'), $this->parser_type)
);
}
/**
* Get the link text for printing in the "Broken Links" table.
* Sub-classes should override this method and display the link text in a way appropriate for the link type.
*
* @param blcLinkInstance $instance
* @param string $context
* @return string HTML
*/
function ui_get_link_text($instance, $context = 'display'){
return $instance->link_text;
}
/**
* Check if the parser supports editing the link text.
*
* @return bool
*/
public function is_link_text_editable() {
return false;
}
/**
* Check if the parser supports editing the link URL.
*
* @return bool
*/
public function is_url_editable() {
return true;
}
/**
* Turn a relative URL into an absolute one.
*
* WordPress 3.4 has WP_Http::make_absolute_url() which is well-tested but not as comprehensive
* as this implementation. For example, WP_Http doesn't properly handle directory traversal with "..",
* and it removes #anchors for no good reason. The BLC implementation deals with both pretty well.
*
* @param string $url Relative URL.
* @param string $base_url Base URL. If omitted, the blog's root URL will be used.
* @return string
*/
function relative2absolute($url, $base_url = ''){
if ( empty($base_url) ){
$base_url = home_url();
}
$p = @parse_url($url);
if(!$p) {
//URL is a malformed
return false;
}
if( isset($p["scheme"]) ) return $url;
//If the relative URL is just a query string or anchor, simply attach it to the absolute URL and return
$first_char = substr($url, 0, 1);
if ( ($first_char == '?') || ($first_char == '#') ){
return $base_url . $url;
}
$parts=(parse_url($base_url));
//Protocol-relative URLs start with "//". We just need to prepend the right protocol.
if ( substr($url, 0, 2) === '//' ) {
$scheme = isset($parts['scheme']) ? $parts['scheme'] : 'http';
return $scheme . ':'. $url;
}
if(substr($url,0,1)=='/') {
//Relative URL starts with a slash => ignore the base path and jump straight to the root.
$path_segments = explode("/", $url);
array_shift($path_segments);
} else {
if(isset($parts['path'])){
$aparts=explode('/',$parts['path']);
array_pop($aparts);
$aparts=array_filter($aparts);
} else {
$aparts=array();
}
//Merge together the base path & the relative path
$aparts = array_merge($aparts, explode("/", $url));
//Filter the merged path
$path_segments = array();
foreach($aparts as $part){
if ( $part == '.' ){
continue; //. = "this directory". It's basically a no-op, so we skip it.
} elseif ( $part == '..' ) {
array_pop($path_segments); //.. = one directory up. Remove the last seen path segment.
} else {
array_push($path_segments, $part); //Normal directory -> add it to the path.
}
}
}
$path = implode("/", $path_segments);
//Build the absolute URL.
$url = '';
if($parts['scheme']) {
$url = "$parts[scheme]://";
}
if(isset($parts['user'])) {
$url .= $parts['user'];
if(isset($parts['pass'])) {
$url .= ":".$parts['pass'];
}
$url .= "@";
}
if(isset($parts['host'])) {
$url .= $parts['host'];
if(isset($parts['port'])) {
$url .= ':' . $parts['port'];
}
$url .= '/';
}
$url .= $path;
return $url;
}
/**
* Apply a callback function to all links found in a string and return the results.
*
* The first argument passed to the callback function will be an associative array
* of link data. If the optional $extra parameter is set, it will be passed as the
* second argument to the callback function.
*
* The link data array will contain at least these keys :
* 'href' - the URL of the link, as-is (i.e. without any sanitization or relative-to-absolute translation).
* '#raw' - the raw link code, e.g. the entire '<a href="...">...</a>' tag of a HTML link.
*
* Sub-classes may also set additional keys.
*
* This method is currently used only internally, so sub-classes are not required
* to implement it.
*
* @param string $content A text string to parse for links.
* @param callback $callback Callback function to apply to all found links.
* @param mixed $extra If the optional $extra param. is supplied, it will be passed as the second parameter to the function $callback.
* @return array An array of all detected links after applying $callback to each of them.
*/
function map($content, $callback, $extra = null){
return array();
}
/**
* Modify all links found in a string using a callback function.
*
* The first argument passed to the callback function will be an associative array
* of link data. If the optional $extra parameter is set, it will be passed as the
* second argument to the callback function. See the map() method of this class for
* details on the first argument.
*
* The callback function should return either an associative array or a string. If
* a string is returned, the parser will replace the current link with the contents
* of that string. If an array is returned, the current link will be modified/rebuilt
* by substituting the new values for the old ones (e.g. returning array with the key
* 'href' set to 'http://example.com/' will replace the current link's URL with
* http://example.com/).
*
* This method is currently only used internally, so sub-classes are not required
* to implement it.
*
* @see blcParser::map()
*
* @param string $content A text string containing the links to edit.
* @param callback $callback Callback function used to modify the links.
* @param mixed $extra If supplied, $extra will be passed as the second parameter to the function $callback.
* @return string The modified input string.
*/
function multi_edit($content, $callback, $extra = null){
return $content; //No-op
}
}
/**
* A helper class for working with parsers. All its methods should be called statically.
*
* @see blcParser
*
* @package Broken Link Checker
* @access public
*/
class blcParserHelper {
/**
* Get the parser matching a parser type ID.
*
* @uses blcModuleManager::get_module()
*
* @param string $parser_type
* @return blcParser|null
*/
static function get_parser( $parser_type ){
$manager = blcModuleManager::getInstance();
return $manager->get_module($parser_type, true, 'parser');
}
/**
* Get all parsers that support either the specified format or the container type.
* If a parser supports both, it will still be included only once.
*
* @param string $format
* @param string $container_type
* @return blcParser[]
*/
static function get_parsers( $format, $container_type ){
$found = array();
//Retrieve a list of active parsers
$manager = blcModuleManager::getInstance();
$active_parsers = $manager->get_modules_by_category('parser');
//Try each one
foreach($active_parsers as $module_id => $module_data){
$parser = $manager->get_module($module_id); //Will autoload if necessary
if ( !$parser ){
continue;
}
if ( in_array($format, $parser->supported_formats) || in_array($container_type, $parser->supported_containers) ){
array_push($found, $parser);
}
}
return $found;
}
}
|