$t('This patch file has been moved or deleted by the administrator. Please restore it, so we can verify that the patch has been properly applied.'),
'severity' => REQUIREMENT_ERROR,
'value' => $t('Unable to check'),
);
}
elseif (count($unpatched_files) == 0) {
$requirements[$key] += array(
'severity' => REQUIREMENT_OK,
'value' => $t('Applied'),
);
}
else {
$requirements[$key] += array(
'description' => $t('This patch has not been properly applied to the following files (or the patch has been updated):') . '
' . theme('item_list', $unpatched_files) . '
' . t('Please consult the installation instructions in the included README.txt.'),
'severity' => $not_properly_applied_severity,
'value' => $t('Not/incompletely applied patch or updated patch.'),
);
}
}
/**
* Check if a patch has been applied, given a set of patterns.
*/
function _cdn_requirements_check_patch_applied($patterns) {
$drupal_root = realpath('.');
$patched = TRUE;
$unpatched_files = array();
foreach ($patterns as $kind => $details) {
foreach ($details as $file_info => $patterns) {
foreach ($patterns as $pattern) {
if ($kind == 'core') {
$filename = $file_info;
$full_path = $drupal_root . '/' . $filename;
}
else {
list($name, $filename) = explode('|', $file_info);
$full_path = $drupal_root . '/' . drupal_get_path($kind, $name) . '/' . $filename;
}
if ($full_path) {
$match = preg_match('|' . preg_quote($pattern) . '|m', file_get_contents($full_path));
// If it didn't match, try allowing \r\n line endings and see if it
// it then matches. This is of course also qualifies as a correctly
// applied patch.
if (!$match) {
$match = preg_match('|' . preg_quote($pattern) . '|m', str_replace("\n", "\r\n", file_get_contents($full_path)));
}
$patched = $patched && $match;
// Remember unpatched files.
if (!$match && !in_array($full_path, $unpatched_files)) {
$unpatched_files[] = $full_path;
}
}
}
}
}
return $unpatched_files;
}
/**
* Generate patterns for a patch, given the full path to a patch. This
* effectively parses the patch and stores it in a meaningful structure.
*/
function _cdn_requirements_generate_patterns_for_patch($full_path) {
// The patch file must exist, otherwise we can't generate any patterns.
if (!file_exists($full_path)) {
return FALSE;
}
$file_kinds = array(
'/cvs/drupal/drupal/modules' => 'core',
'/cvs/drupal/drupal/themes' => 'core',
'/cvs/drupal/drupal' => 'core',
'/cvs/drupal-contrib/contributions/modules' => 'module',
'/cvs/drupal-contrib/contributions/themes' => 'theme',
);
$fp = fopen($full_path, 'r');
$patch_block = '';
while (!feof($fp) ) {
$line = fgets($fp);
// Check if the current line indicates the next file.
if (drupal_substr($line, 0, 7) == 'Index: ') {
$file_to_patch = drupal_substr($line, 7, drupal_strlen($line) - 7 - 1);
}
// Find out which kind of file this is: a core file, a module file or a
// theme file.
if (drupal_substr($line, 0, 10) == 'RCS file: ') {
$rcs_file = drupal_substr($line, 10);
foreach ($file_kinds as $patch_rcs_file => $patch_type) {
if (drupal_substr($rcs_file, 0, drupal_strlen($patch_rcs_file)) == $patch_rcs_file) {
$kind = $patch_type;
// For files of the module or theme kind, also store the exact name.
if ($kind == 'module' || $kind == 'theme') {
$start = drupal_strlen($patch_rcs_file) + 1;
$module_or_theme = drupal_substr($rcs_file, $start, strpos($rcs_file, '/', $start) - $start);
}
break;
}
}
}
// Finally, store the lines that have been added (+): concatenate them in
// a "patch block".
if ($line[0] == '+' && ($line[1] == ' ' | $line[1] == "\n")) {
$patch_block .= drupal_substr($line, 1);
}
// When we encounter a line that has not been added (+), the current patch
// block has ended and we should store it as a pattern.
else {
if ($patch_block != '') {
if ($kind == 'core') {
$patterns[$patch_type][$file_to_patch][] = $patch_block;
}
else {
$patterns[$patch_type][$module_or_theme . '|' . $file_to_patch][] = $patch_block;
}
}
$patch_block = '';
}
}
fclose($fp);
return $patterns;
}
/**
* Generates the patterns for the core patch.
*/
function _cdn_requirements_core_patch_patterns() {
return _cdn_requirements_generate_patterns_for_patch(drupal_get_path('module', 'cdn') . '/patches/drupal6.patch');
}
/**
* Generates the patterns for the ImageCache patch.
*/
function _cdn_requirements_imagecache_patch_patterns() {
return _cdn_requirements_generate_patterns_for_patch(drupal_get_path('module', 'cdn') . '/patches/imagecache.patch');
}
/**
* Generates the patterns for the ImageCache 6.2 branch patch.
*/
function _cdn_requirements_imagecache_6_2_patch_patterns() {
return _cdn_requirements_generate_patterns_for_patch(drupal_get_path('module', 'cdn') . '/patches/imagecache_6--2.patch');
}
/**
* Checks if the environment is Pressflow or not.
*/
function _cdn_requirements_is_pressflow() {
$profile = realpath('.') . '/profiles/default/default.profile';
if (!file_exists($profile)) {
return FALSE;
}
include_once $profile;
$default = default_profile_details();
return $default['name'] == 'Pressflow';
}
/**
* Detect whether the fallback mechanism (to alter file URLs, the best
* mechanism is the core patch, but a fallback to the theme layer is included)
* should be enabled or disabled, and actually enable/disable it, too.
*/
function _cdn_requirements_detect_fallback() {
// Check if the core patch is applied properly (i.e. no core files don't
// properly match the core patch). If it is properly applied, then the
// fallback will be (or remain) disabled, if not, then the fallback will be
// (or remain) enabled.
$fallback_currently_enabled = variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE);
if (!_cdn_requirements_is_pressflow() && count(_cdn_requirements_check_patch_applied(_cdn_requirements_core_patch_patterns())) > 0) {
if (!$fallback_currently_enabled) {
variable_set(CDN_THEME_LAYER_FALLBACK_VARIABLE, TRUE);
drupal_rebuild_theme_registry();
drupal_set_message(t("Drupal CDN integration status changed: core patch not (properly) applied; fallback mechanism enabled."), 'warning');
watchdog('cdn', "Drupal CDN integration status changed: core patch not (properly) applied; fallback mechanism enabled.");
}
}
else {
if ($fallback_currently_enabled) {
variable_set(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE);
drupal_rebuild_theme_registry();
drupal_set_message(t("Drupal CDN integration status changed: core patch properly applied; fallback mechanism disabled."), 'warning');
watchdog('cdn', "Drupal CDN integration status changed: core patch properly applied; fallback mechanism disabled.");
}
}
}
/**
* Get the integration mechanism that is currently being used by the CDN
* integration module.
*
* @return
* One of the following: 'fallback', 'pressflow', 'core patch'.
*/
function _cdn_requirements_get_integration_mechanism() {
if (variable_get(CDN_THEME_LAYER_FALLBACK_VARIABLE, FALSE)) {
return 'fallback';
}
elseif (_cdn_requirements_is_pressflow()) {
return 'pressflow';
}
else {
return 'core patch';
}
}