View source
<?php
function purl_boot() {
}
function purl_theme($existing, $type, $theme, $path) {
return array(
'purl_settings_form' => array(
'render element' => 'form',
),
);
}
function purl_ctools_plugin_api($owner, $api) {
if ($owner == 'purl' && $api == 'processor') {
return array(
'version' => 1,
'path' => 'includes',
);
}
}
function purl_ctools_plugin_type() {
$plugins = array(
'processor' => array(
'cache' => TRUE,
'use hooks' => TRUE,
),
);
return $plugins;
}
function purl_menu() {
$items = array();
$items['admin/config/search/purl'] = array(
'title' => 'Persistent URL',
'type' => MENU_NORMAL_ITEM,
'description' => 'Settings for persistent url.',
'position' => 'left',
'weight' => -5,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'purl_settings_form',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'purl.admin.inc',
);
$items['admin/config/search/purl/settings'] = array(
'title' => 'Settings',
'type' => MENU_DEFAULT_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'purl_settings_form',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'purl.admin.inc',
'weight' => 1,
);
$items['admin/config/search/purl/list'] = array(
'type' => MENU_LOCAL_TASK,
'title' => 'Modifiers',
'page callback' => 'purl_admin',
'access arguments' => array(
'administer site configuration',
),
'file' => 'purl.admin.inc',
'weight' => 2,
);
$items['admin/config/search/purl/types'] = array(
'type' => MENU_LOCAL_TASK,
'title' => 'Types',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'purl_types_form',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'purl.admin.inc',
'weight' => 3,
);
return $items;
}
function purl_form_alter(&$form, &$form_state, $form_id) {
switch ($form_id) {
case 'menu_edit_menu':
case 'menu_edit_item':
case 'redirect_edit_form':
module_load_include('inc', 'purl', 'purl.admin');
_purl_form_alter($form, $form_state, $form_id);
break;
case 'views_exposed_form':
foreach (purl_active()
->get('querystring') as $element) {
if (!isset($form[$element->value])) {
$form[$element->value] = array(
'#type' => 'hidden',
'#value' => $element->id,
);
}
}
break;
}
}
function purl_init() {
static $once;
if (!isset($once)) {
$once = TRUE;
if (!isset($_GET['q'])) {
$_GET['q'] = '';
}
purl_inited(TRUE);
$_GET['q'] = $q = $_GET['q'];
drupal_path_initialize();
purl_get_normal_path($q, TRUE);
}
}
function purl_language_strip($path) {
$mode = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
$languages = language_list('enabled');
$languages = $languages[1];
if (in_array($mode, array(
LANGUAGE_NEGOTIATION_PATH_DEFAULT,
LANGUAGE_NEGOTIATION_PATH,
))) {
$args = explode('/', $path);
$prefix = array_shift($args);
foreach ($languages as $language) {
if (!empty($language->prefix) && $language->prefix == $prefix) {
return implode('/', $args);
}
}
}
return $path;
}
function purl_inited($set = NULL) {
static $status = FALSE;
if (isset($set)) {
$status = $set;
}
return $status;
}
function purl_url_inbound_alter(&$path, $original_path, $path_language) {
$path = purl_inited() ? purl_get_normal_path($path) : $path;
}
function purl_get_normal_path($q, $activate = FALSE, $reset = FALSE) {
static $cache = array();
static $adjusted = array();
if (!isset($cache[$q]) || $reset) {
$cache[$q] = array();
$adjusted[$q] = $q;
foreach (array_keys(_purl_options()) as $method) {
$processor = purl_get_processor($method);
$value = $processor
->detect($adjusted[$q]);
$elements = purl_parse($processor, $value);
if (is_array($elements)) {
foreach ($elements as $element) {
$processor
->adjust($value, $element, $adjusted[$q]);
}
$cache[$q][$method] = $elements;
}
}
if ($src = drupal_lookup_path('source', $adjusted[$q])) {
$adjusted[$q] = $src;
}
}
if ($activate) {
foreach ($cache[$q] as $method => $elements) {
foreach ($elements as $element) {
purl_active()
->add($method, $element)
->set($element);
}
}
}
if (!empty($q)) {
return !empty($adjusted[$q]) ? $adjusted[$q] : variable_get('site_frontpage', 'node');
}
return $adjusted[$q];
}
function purl_parse($processor, $q) {
static $cache;
if (!isset($cache)) {
$cache = new purl_cache();
}
if ($cache
->get($processor
->method(), $q) === false) {
$valid_values = purl_modifiers($processor
->method());
$item = $processor
->parse($valid_values, $q);
$cache
->add($processor
->method(), array(
$q => $item,
));
}
return $cache
->get($processor
->method(), $q);
}
function purl_url_outbound_alter(&$path, &$options, $original) {
static $global_elements;
if (!purl_disable() && empty($options['alias']) && !strpos($path, '://')) {
$elements = array();
if (purl_inited() && !isset($global_elements)) {
$global_elements = array();
foreach (purl_active()
->get() as $method => $items) {
while ($item = array_pop($items)) {
$global_elements[$item->provider] = $item;
}
}
}
$elements = isset($global_elements) ? $global_elements : array();
if (!empty($options['purl']['provider']) && !empty($options['purl']['id'])) {
if ($e = purl_generate_rewrite_elements($options['purl'])) {
$elements = array(
$e,
);
}
}
elseif (isset($options['purl']['add'])) {
foreach ($options['purl']['add'] as $item) {
if ($e = purl_generate_rewrite_elements($item)) {
$elements[$item['provider']] = $e;
}
}
}
foreach ($elements as $e) {
$e->processor
->rewrite($path, $options, $e);
}
}
}
function purl_generate_rewrite_elements($item) {
$method = variable_get('purl_method_' . $item['provider'], 'path');
$processor = purl_get_processor($method);
$local_modifiers = purl_modifiers($method);
$provider = $id = NULL;
foreach ($local_modifiers as $k => $v) {
if ($v['provider'] == $item['provider']) {
if ($v['id'] === null || $v['id'] == $item['id']) {
$provider = $item['provider'];
$id = $item['id'];
break;
}
}
}
if (isset($provider) && isset($id)) {
return new purl_path_element($processor, $k, $provider, $id);
}
}
function purl_modifiers($requested_method = NULL, $reset = FALSE) {
static $values;
global $language;
if (!isset($values) && !$reset) {
$cache = cache_get('purl_modifiers_' . $language->language);
if ($cache) {
$values = $cache->data;
}
}
if (isset($requested_method) && !isset($values[$requested_method]) && !$reset) {
$cache = cache_get("purl_modifiers:{$requested_method}");
if ($cache) {
$values[$requested_method] = $cache->data;
}
}
if (!isset($values[$requested_method]) || $reset) {
$providers = module_invoke_all('purl_modifiers');
foreach ($providers as $provider => $items) {
$method = variable_get('purl_method_' . $provider, 'path');
$info = ctools_get_plugins('purl', 'processor', $method);
if (!empty($info['null_id'])) {
$value = variable_get('purl_method_' . $provider . '_key', false);
if ($value != false) {
$values[$method][$value] = array(
'provider' => $provider,
'id' => null,
);
}
}
else {
foreach ($items as $item) {
if ($item['value'] && $item['id']) {
$values[$method][$item['value']] = array(
'provider' => $provider,
'id' => $item['id'],
);
}
}
}
}
$providers = array_diff_key(purl_providers(), $providers);
$result = db_query("SELECT * FROM {purl}");
$db_values = array();
foreach ($result as $row) {
$db_values[$row->provider][$row->value] = array(
'provider' => $row->provider,
'id' => $row->id,
);
}
foreach ($providers as $provider => $info) {
$method = variable_get('purl_method_' . $provider, 'path');
$info = ctools_get_plugins('purl', 'processor', $method);
if (!empty($info['null_id'])) {
$value = variable_get('purl_method_' . $provider . '_key', false);
if ($value != false) {
$values[$method][$value] = array(
'provider' => $provider,
'id' => null,
);
}
}
else {
if (!empty($db_values[$provider])) {
$values[$method] = isset($values[$method]) ? $values[$method] : array();
$values[$method] = $values[$method] + $db_values[$provider];
}
}
}
cache_set('purl_modifiers_' . $language->language, $values);
}
return isset($values[$requested_method]) ? $values[$requested_method] : array();
}
function purl_providers($by_method = FALSE) {
static $providers;
if (!is_array($providers)) {
$providers = array();
$providers = module_invoke_all('purl_provider');
}
if ($by_method) {
static $methods;
if (!isset($methods)) {
$methods = new purl_cache();
foreach ($providers as $id => $provider) {
$methods
->add(variable_get('purl_method_' . $id, 'path'), array(
$id => $provider,
));
}
}
return $methods
->get();
}
else {
return $providers;
}
}
function purl_load($modifier, $reset = FALSE) {
static $cache;
if (!isset($cache) || $reset) {
$cache = array();
}
foreach (array(
'id',
'value',
) as $key) {
if (isset($modifier['provider'], $modifier[$key])) {
$provider = $modifier['provider'];
$val = $modifier[$key];
if (!isset($cache[$key][$provider][$val])) {
$query = db_select('purl', 'p');
$loaded = $query
->fields('p')
->condition($key, $val)
->condition('provider', $provider)
->execute()
->fetchAssoc();
$cache[$key][$provider][$val] = $loaded;
}
return $cache[$key][$provider][$val];
}
}
return FALSE;
}
function purl_validate($modifier) {
if (check_plain($modifier['provider']) && !empty($modifier['value']) && preg_match('!^[\\.a-z0-9_-]+$!', $modifier['value']) && !menu_get_item($modifier['value'])) {
$id = db_query("SELECT id FROM {purl} WHERE value = :value", array(
':value' => $modifier['value'],
))
->fetchField();
if (!$id) {
return TRUE;
}
else {
if (isset($modifier['id']) && $id == $modifier['id']) {
return TRUE;
}
}
}
return FALSE;
}
function purl_save($modifier) {
if (purl_validate($modifier)) {
$id = db_query("SELECT id FROM {purl} WHERE id = :id AND provider = :provider", array(
':id' => $modifier['id'],
':provider' => $modifier['provider'],
))
->fetchField();
if (!empty($id)) {
$status = drupal_write_record('purl', $modifier, array(
'provider',
'id',
));
}
else {
$status = drupal_write_record('purl', $modifier);
}
purl_load(NULL, TRUE);
purl_modifiers(NULL, TRUE);
return $status;
}
return FALSE;
}
function purl_delete($modifier) {
if (!empty($modifier['value'])) {
$param = 'value';
$where = $modifier['value'];
}
else {
if (!empty($modifier['id'])) {
$param = 'id';
$where = $modifier['id'];
}
}
$check = db_query("SELECT id FROM {purl} WHERE provider = :provider AND {$param} = :param", array(
':provider' => $modifier['provider'],
':param' => $where,
))
->fetchField();
if ($check) {
$status = db_query("DELETE FROM {purl} WHERE provider = :provider AND {$param} = :param", array(
':provider' => $modifier['provider'],
':param' => $where,
));
purl_load(NULL, TRUE);
purl_modifiers(NULL, TRUE);
return $status;
}
return FALSE;
}
function purl_goto($path = '', $options = array(), $http_response_code = 302) {
$options = !is_array($options) ? array() : $options;
$options['absolute'] = TRUE;
if (isset($_GET['destination'])) {
extract(parse_url(urldecode($_GET['destination'])));
}
else {
if (isset($_REQUEST['edit']['destination'])) {
extract(parse_url(urldecode($_REQUEST['edit']['destination'])));
}
}
$url = url($path, $options);
if (isset($options['purl'])) {
$current_url = url($_GET['q'], array(
'absolute' => TRUE,
'query' => drupal_get_query_parameters(),
));
if ($url == $current_url) {
watchdog('purl', 'Infinite redirect prevented.', array(), WATCHDOG_INFO);
return;
}
}
$url = str_replace(array(
"\n",
"\r",
), '', $url);
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
module_invoke_all('exit', $url);
}
session_write_close();
header('Location: ' . $url, TRUE, $http_response_code);
exit;
}
function purl_disable($set = FALSE) {
static $drop;
if (!isset($drop)) {
$drop = FALSE;
}
if ($set) {
$drop = TRUE;
}
return $drop;
}
function purl_form($provider, $id, $value = '', $required = TRUE) {
$method = variable_get('purl_method_' . $provider, 'path');
$processor = purl_get_processor($method);
$form = array(
'#tree' => TRUE,
'#element_validate' => array(
'purl_form_validate',
),
);
$processors = _purl_options();
global $base_url;
$form['value'] = array(
'#title' => isset($processors[$method]) ? $processors[$method] : '',
'#type' => 'textfield',
'#description' => $processor
->description(),
'#size' => 20,
'#maxlength' => 255,
'#required' => $required,
'#default_value' => $value,
'#field_prefix' => $method == 'path' ? $base_url . '/' : NULL,
);
$form['provider'] = array(
'#type' => 'value',
'#value' => $provider,
);
$form['id'] = array(
'#type' => 'value',
'#value' => $id,
);
return $form;
}
function purl_form_validate($form) {
if (!$form['value']['#required'] && empty($form['value']['#value'])) {
return TRUE;
}
$modifier = array(
'provider' => $form['provider']['#value'],
'value' => $form['value']['#value'],
'id' => $form['id']['#value'],
);
if (!purl_validate($modifier)) {
form_set_error($form['#parents'][0], t('There was an error registering the value "@value". It is either invalid or is already taken. Please choose another.', array(
'@value' => $form['value']['#value'],
)));
return FALSE;
}
else {
return TRUE;
}
}
function _purl_options($active = TRUE) {
static $enabled_options;
if (isset($enabled_options) && $active) {
return $enabled_options;
}
module_load_include('module', 'ctools', 'ctools');
ctools_include('plugins');
$options = array();
foreach (ctools_get_plugins('purl', 'processor') as $key => $processor) {
if (!empty($processor['title'])) {
$options[$key] = $processor['title'];
}
}
if ($active) {
$enabled = variable_get('purl_types', array(
'path' => 'path',
));
$options = array_intersect_key($options, array_filter($enabled));
}
return $options;
}
function purl_active() {
static $cache;
if (!isset($cache)) {
$cache = new purl_cache();
}
return $cache;
}
class purl_cache {
protected $cache = array();
function __construct() {
foreach (_purl_options() as $k => $v) {
$this->cache[$k] = array();
}
}
public function add($method, $item, $merge = true) {
if (is_array($item) && $merge) {
if (!isset($this->cache[$method]) && count($item) >= 1) {
$this->cache[$method] = array();
}
if (count($item) >= 1) {
$this->cache[$method] = $this->cache[$method] + $item;
}
}
else {
$this->cache[$method][] = $item;
}
return $this;
}
public function get($method = false, $id = false) {
if ($method !== false && $id !== false) {
return isset($this->cache[$method][$id]) ? $this->cache[$method][$id] : false;
}
elseif ($method !== false) {
return isset($this->cache[$method]) ? $this->cache[$method] : array();
}
else {
return $this->cache;
}
}
public function set($e) {
if ($e->provider && $e->id) {
$providers = purl_providers();
$callback = $providers[$e->provider]['callback'];
if (function_exists($callback)) {
$args = array();
if (isset($providers[$e->provider]['callback arguments'])) {
$args = $providers[$e->provider]['callback arguments'];
}
$args[] = $e->id;
call_user_func_array($callback, $args);
}
}
return $this;
}
public function remove($method = NULL, $provider = NULL) {
if (isset($provider)) {
$methods = isset($method) ? array(
$method,
) : array_keys($this->cache);
foreach ($methods as $method) {
if (isset($this->cache[$method])) {
foreach ($this->cache[$method] as $key => $item) {
if (is_object($item) && !empty($item->provider) && $item->provider == $provider) {
unset($this->cache[$method][$key]);
}
}
}
}
}
else {
if (isset($method)) {
if (isset($this->cache[$method])) {
unset($this->cache[$method]);
}
}
}
return $this;
}
}
function purl_get_processor($method) {
static $processors;
if (!isset($processors[$method])) {
ctools_include('plugins');
$class = ctools_plugin_load_class('purl', 'processor', $method, 'handler');
$processors[$method] = new $class();
}
return isset($processors[$method]) ? $processors[$method] : NULL;
}
function _purl_skip($e, $o) {
if (!empty($o['purl']['disabled'])) {
return true;
}
if (isset($o['purl']['remove'])) {
return in_array($e->provider, $o['purl']['remove']);
}
return false;
}
function purl_path_elements($processor, $values) {
$return = array();
foreach ($values as $v => $i) {
$return[$v] = new purl_path_element($processor, $v, $i['provider'], $i['id']);
}
return $return;
}
class purl_path_element {
public $processor;
public $value;
public $provider;
public $id;
function __construct($processor, $value, $provider, $id) {
$this->processor = $processor;
$this->value = $value;
$this->provider = $provider;
$this->id = $id;
}
}
function purl_purl_processor() {
$info = array();
$info['processor'] = array(
'handler' => array(
'class' => 'purl_processor',
'file' => 'purl_processor.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
),
);
$info['path'] = array(
'title' => t('Path'),
'handler' => array(
'class' => 'purl_path',
'file' => 'purl_path.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'processor',
),
);
$info['pair'] = array(
'title' => t('Path pair'),
'null_id' => true,
'handler' => array(
'class' => 'purl_pair',
'file' => 'purl_pair.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'path',
),
);
$info['subdomain'] = array(
'title' => t('Subdomain'),
'handler' => array(
'class' => 'purl_subdomain',
'file' => 'purl_subdomain.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'processor',
),
);
$info['domain'] = array(
'title' => t('Domain'),
'handler' => array(
'class' => 'purl_domain',
'file' => 'purl_domain.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'processor',
),
);
$info['extension'] = array(
'title' => t('File extension'),
'handler' => array(
'class' => 'purl_extension',
'file' => 'purl_extension.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'processor',
),
);
$info['useragent'] = array(
'title' => t('User agent'),
'handler' => array(
'class' => 'purl_useragent',
'file' => 'purl_useragent.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'processor',
),
);
$info['querystring'] = array(
'title' => t('Query string'),
'null_id' => true,
'handler' => array(
'class' => 'purl_querystring',
'file' => 'purl_querystring.inc',
'path' => drupal_get_path('module', 'purl') . '/includes',
'parent' => 'processor',
),
);
return $info;
}