View source
<?php
namespace HookUpdateDeployTools;
class Redirects implements ImportInterface {
public static function import($redirect_lists) {
$t = get_t();
$redirect_lists = (array) $redirect_lists;
$completed = array();
$total_requested = count($redirect_lists);
try {
self::canImport();
foreach ($redirect_lists as $key => $redirect_import_file_prefix) {
$filename = HudtInternal::normalizeFileName($redirect_import_file_prefix);
$page_machine_name = HudtInternal::normalizeMachineName($redirect_import_file_prefix);
if (HudtInternal::canReadFile($filename, 'redirect')) {
$file_contents = HudtInternal::readFileToString($filename, 'redirect');
self::parseList($file_contents);
$message = 'Redirects from: @machine_name - imported.';
$vars = array(
'@machine_name' => $page_machine_name,
);
Message::make($message, $vars, WATCHDOG_INFO, 1);
$completed[$page_machine_name] = $t('Imported');
}
}
} catch (\Exception $e) {
$vars = array(
'!error' => method_exists($e, 'logMessage') ? $e
->logMessage() : $e
->getMessage(),
);
if (!method_exists($e, 'logMessage')) {
$message = 'Redirects import denied because: !error';
Message::make($message, $vars, WATCHDOG_ERROR);
}
$done = HudtInternal::getSummary($completed, $total_requested, 'Imported');
Message::make($done, array(), FALSE, 1);
throw new HudtException('Caught Exception: Update aborted! !error', $vars, WATCHDOG_ERROR, FALSE);
}
$done = HudtInternal::getSummary($completed, $total_requested, 'Imported');
return $done;
}
public static function canImport() {
Check::canUse('redirect');
Check::canCall('redirect_hash');
Check::canCall('redirect_load_by_hash');
Check::canCall('redirect_save');
return TRUE;
}
private static function newRedirect() {
$empty_redirect = new \stdClass();
$empty_redirect->type = 'redirect';
$empty_redirect->redirect = '';
$empty_redirect->redirect_options = array();
$empty_redirect->source = '';
$empty_redirect->source_options = array();
$empty_redirect->language = LANGUAGE_NONE;
$empty_redirect->rid = NULL;
$empty_redirect->uid = $GLOBALS['user']->uid;
$empty_redirect->status_code = 0;
$empty_redirect->count = 0;
$empty_redirect->access = 0;
$empty_redirect->hash = '';
return $empty_redirect;
}
private static function parseList($redirect_list) {
self::canImport();
$output = array(
'created' => array(),
'infinite' => array(),
'existing' => array(),
'home' => array(),
'summary' => '',
);
$redirects = explode("\n", $redirect_list);
$line_count = count($redirects);
$output['summary'] = t('@line_count redirects to be processed.', array(
'@line_count' => $line_count,
));
foreach ($redirects as $index_redirects => $row) {
$original_import_row = self::cleanLineEnds($row);
$line_to_process = explode(',', $row);
$old_url = !empty($line_to_process[0]) ? $line_to_process[0] : '';
self::cleanUrlEnds($old_url);
$new_url = !empty($line_to_process[1]) ? $line_to_process[1] : '';
self::cleanUrlEnds($new_url);
$new_url_parsed = self::parseCompleteUrl($new_url);
$new_url_full = $new_url_parsed['completeURL'];
$redirect_object = self::newRedirect();
$redirect_object->redirect = $new_url_parsed['fullURI'];
if (!empty($new_url_parsed['query']) || !empty($new_url_parsed['fragment'])) {
if (!empty($new_url_parsed['fragment'])) {
$redirect_object->redirect_options['fragment'] = $new_url_parsed['fragment'];
}
if (!empty($new_url_parsed['query'])) {
$query = self::extractUrlParameters($new_url_parsed['query']);
$redirect_object->redirect_options['query'] = $query['query'];
}
}
$old_url_parsed = self::parseCompleteUrl($old_url);
$old_url_full = !empty($old_url_parsed['path']) ? $old_url_parsed['path'] : '';
$old_url_full .= !empty($old_url_parsed['query']) ? '?' . $old_url_parsed['query'] : '';
$variables = array(
'@old' => $old_url_full,
'@new' => $new_url_full,
);
$redirect_object->source = $old_url_parsed['path'];
if (!empty($old_url_parsed['query'])) {
$query = self::extractUrlParameters($old_url_parsed['query']);
$redirect_object->source_options['query'] = $query['query'];
}
$modified = '';
if (!empty($old_url_parsed['fragment'])) {
$modified = t(': DISCARDED fragment from original path: @fragment', array(
'@fragment' => $old_url_parsed['fragment'],
));
}
if (!empty($old_url_full) && $old_url_full !== '<front>') {
if ($old_url_full != $new_url_full) {
$hash = redirect_hash($redirect_object);
if (!redirect_load_by_hash($hash)) {
redirect_save($redirect_object);
$new_url_full = empty($new_url_full) ? 'ROOT' : $new_url_full;
$variables['@modified'] = empty($modified) ? '' : $modified;
$output['created'][] = t('@old redirects to @new @modified', $variables);
}
else {
$output['existing'][] = $old_url_full;
}
}
else {
$output['infinite'][] = t("@old loops to itself at @new", $variables);
}
}
else {
$output['home'][] = t("@old is a home page redirect", $variables);
}
}
self::outputReport($output);
self::outputReportSummary($output);
}
public static function parseForm($form, &$form_state) {
$redirect_list = $form_state['values']['redirect_import_txt'];
self::parseList($redirect_list);
}
private static function outputReport(&$output) {
$messsage = '';
if (!empty($output['created'])) {
$messsage .= t('Created:') . "\n";
foreach ($output['created'] as $created) {
$messsage .= "+ {$created}\n";
}
}
if (!empty($output['existing'])) {
$messsage .= t('Existing redirects skipped:') . "\n";
foreach ($output['existing'] as $exists) {
$messsage .= "- {$exists}\n";
}
}
if (!empty($output['infinite'])) {
$messsage .= t('Infinite redirects skipped:') . "\n";
foreach ($output['infinite'] as $infinite) {
$messsage .= "- {$infinite}\n";
}
}
if (!empty($output['home'])) {
$messsage .= t('Home page redirects skipped:') . "\n";
foreach ($output['home'] as $home) {
$messsage .= "- {$home}\n";
}
}
hudt_squeal($messsage);
}
private static function outputReportSummary(&$output) {
$summary = t("Redirect Import Summary:");
$summary .= "\n";
$summary .= $output['summary'];
$summary .= "\n";
$text = t("@count Redirects written to the 'redirects' table.", array(
'@count' => count($output['created']),
));
$summary .= " + {$text}\n";
$text = t("@count already existed and skipped.", array(
'@count' => count($output['existing']),
));
$summary .= " - {$text}\n";
$text = t("@count infinite redirects skipped.", array(
'@count' => count($output['infinite']),
));
$summary .= " - {$text}\n";
$text = t("@count redirects from the home page skipped.", array(
'@count' => count($output['home']),
));
$summary .= " - {$text}\n";
$messsage = \HookUpdateDeployTools\Message::make($summary, array(), WATCHDOG_INFO);
$breaker = "\n\n------------------------------------------------------------------------\n";
hudt_squeal($breaker . $messsage);
}
private static function cleanLineEnds($string) {
$string = trim($string);
$string = rtrim($string, "\n");
return $string;
}
private static function cleanUrlEnds(&$string) {
$chars_to_trim = '/ ';
$string = ltrim($string, $chars_to_trim);
$string = rtrim($string, $chars_to_trim);
$string = rtrim($string);
}
private static function parseCompleteUrl(&$url) {
self::fixBadFragment($url);
$parsed_url = parse_url($url);
self::fixMissingScheme($url, $parsed_url);
$parsed_url['path'] = !empty($parsed_url['path']) ? trim($parsed_url['path']) : '';
$parsed_url['path'] = !empty($parsed_url['path']) ? trim($parsed_url['path'], '/') : '';
$parsed_url['fullURI'] = !empty($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
$parsed_url['fullURI'] .= !empty($parsed_url['host']) ? $parsed_url['host'] . '/' : '';
$parsed_url['fullURI'] .= !empty($parsed_url['path']) ? $parsed_url['path'] : '';
$parsed_url['completeURL'] = $parsed_url['fullURI'];
$parsed_url['completeURL'] .= !empty($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
$parsed_url['completeURL'] .= !empty($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
return $parsed_url;
}
private static function fixBadFragment(&$url) {
$fragment_location = strpos($url, '#');
$query_location = strpos($url, '?');
if (!empty($fragment_location) && !empty($query_location) && $query_location > $fragment_location) {
$frag_length = $query_location - $fragment_location;
$fragment = substr($url, $fragment_location, $frag_length);
$url = str_replace($fragment, '', $url);
$url = $url . $fragment;
}
}
private static function fixMissingScheme(&$url, &$parsed_url) {
if (empty($parsed_url['scheme'])) {
$tld_check = array(
'.com',
'.edu',
'.gov',
'.net',
'.org',
'.us',
);
foreach ($tld_check as $tld) {
if (!empty($parsed_url['path']) && stripos($parsed_url['path'], $tld) > 1) {
$url = 'http://' . $url;
$parsed_url = parse_url($url);
}
}
}
}
private static function extractUrlParameters($parameters_string) {
$params_array = array();
if (!empty($parameters_string)) {
$param_elements = explode('&', $parameters_string);
foreach ($param_elements as $param_element) {
$param = explode('=', $param_element);
$params_array['query'][$param[0]] = $param[1];
}
}
return $params_array;
}
public static function getImportForm() {
$form = array();
$form['#prefix'] = t('<p>Hook Update Deploy Tools module allows for import of a CSV list of redirects in the order "old-path, new-path" where the path should be root relative without using the initial "/". The new-path can also support a full (http://somedomain.com/somepage.htm) URL if a redirect needs to go off-site.</p><p>Redirects to the home page should be listed as <i><front></i> or <b>/</b></p><p>Large imports should be broken down into 1000 or fewer per import.</p>');
$form['redirect_import_txt'] = array(
'#title' => t('csv-list-import'),
'#type' => 'textarea',
'#default_value' => 'old-path, newpath',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Import These Redirects'),
);
$form['#submit'][] = 'hook_update_deploy_tools_redirect_import_parse_form';
return $form;
}
}