Skip to content
This repository has been archived by the owner on Jul 20, 2018. It is now read-only.

Added class to check for forbidden functions only in template files #189

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
99 changes: 99 additions & 0 deletions tests/checks/test-TemplateForbiddenFunctionsCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

class TemplateForbiddenFunctionsCheckTest extends WP_UnitTestCase {
protected $_TemplateForbiddenFunctionsCheck;

public function setUp() {
parent::setUp();
require_once VIP_SCANNER_DIR . '/checks/TemplateForbiddenFunctionsCheck.php';

$this->_TemplateForbiddenFunctionsCheck = new TemplateForbiddenFunctionsCheck();
}

public function testRedirectInHeader() {
$input = array(
'php' => array(
'header.php' => "<?php

wp_redirect( 'wordpress.com' );

?>
"
)
);

$result = $this->_TemplateForbiddenFunctionsCheck->check( $input );

$errors = $this->_TemplateForbiddenFunctionsCheck->get_errors();

$error_slugs = wp_list_pluck( $errors, 'slug' );
$this->assertContains( 'template-forbidden-functions-wp_redirect', $error_slugs );
$this->assertFalse( $result );
}

public function testRedirectInSpecificPageTemplate() {
$input = array(
'php' => array(
'page-about.php' => "<?php

wp_redirect( 'automattic.com' );

?>
"
)
);

$result = $this->_TemplateForbiddenFunctionsCheck->check( $input );

$errors = $this->_TemplateForbiddenFunctionsCheck->get_errors();

$error_slugs = wp_list_pluck( $errors, 'slug' );
$this->assertContains( 'template-forbidden-functions-wp_redirect', $error_slugs );
$this->assertFalse( $result );
}

public function testSafeRedirectInPageTemplateWithinSubDirectory() {
$input = array(
'php' => array(
'page-templates/contributors.php' => "<?php
/*
Template Name: Contributors
*/

wp_safe_redirect( 'automattic.com' );

?>
"
)
);

$result = $this->_TemplateForbiddenFunctionsCheck->check( $input );

$errors = $this->_TemplateForbiddenFunctionsCheck->get_errors();

$error_slugs = wp_list_pluck( $errors, 'slug' );
$this->assertContains( 'template-forbidden-functions-wp_safe_redirect', $error_slugs );
$this->assertFalse( $result );
}

public function testAllowedRedirectInFunctionsPHPFile() {
$input = array(
'php' => array(
'functions.php' => "<?php

wp_redirect( 'automattic.com' );

?>
"
)
);

$result = $this->_TemplateForbiddenFunctionsCheck->check( $input );

$errors = $this->_TemplateForbiddenFunctionsCheck->get_errors();

$error_slugs = wp_list_pluck( $errors, 'slug' );
$this->assertNotContains( 'template-forbidden-functions-wp_redirect', $error_slugs );
$this->assertTrue( $result );
}
}
108 changes: 108 additions & 0 deletions vip-scanner/checks/TemplateForbiddenFunctionsCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

/**
* Checks for redirect calls in core template files.
*/
class TemplateForbiddenFunctionsCheck extends BaseCheck {

function check( $files ) {
$result = true;
$this->increment_check_count();

$theme_file_patterns = array(
'/(\/)?404.php/',
'/(\/)?archive(-([^\/]+))?.php/',
'/(\/)?attachment.php/',
'/(\/)?author(-(\d+|([^\/]+)))?.php/',
'/(\/)?category(-(\d+|([^\/]+)))?.php/',
'/(\/)?comments.php/',
'/(\/)?(featured-)?content(-([^\/]+))?.php/',
'/(\/)?date.php/',
'/(\/)?footer.php/',
'/(\/)?front-page.php/',
'/(\/)?header.php/',
'/(\/)?home.php/',
'/(\/)?image.php/',
'/(\/)?index.php/',
'/(\/)?search.php/',
'/(\/)?page(-(\d+|([^\/]+)))?.php/',
'/(\/)?paged.php/',
'/(\/)?sidebar(-([^\/]+))?.php/',
'/(\/)?single(-(post|([^\/]+)))?.php/',
'/(\/)?tag(-(\d+|([^\/]+)))?.php/',
'/(\/)?taxonomy(-(\d+|([^\/]+)))?.php/',
);

$mime_types = get_allowed_mime_types();

foreach ( $mime_types as $extension => $mime_type ) {
$theme_file_patterns[] = '/' . str_replace( '/', '_', $mime_type ) . '.php/';

preg_match( '/(.+)\/(.+)/', $mime_type, $patterns );

if ( ! empty( $patterns ) ) {
for ( $index = 1; $index <= 2; $index ++ ) {
if ( isset( $patterns[ $index ] ) && ! empty( $patterns[ $index ] ) ) {
$new_pattern = '/(^-)' . str_replace( '/', '_', $patterns[ $index ] ) . '.php/';
if ( ! in_array( $new_pattern, $theme_file_patterns ) ) {
$theme_file_patterns[] = $new_pattern;
}
}
}
}
}

$checks = array(
'auth_redirect',
'maybe_redirect_404',
'redirect_canonical',
'redirect_post',
'wp_old_slug_redirect',
'wp_redirect',
'wp_redirect_admin_locations',
'wp_safe_redirect',
);

foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {

// Match template files that can have any names
if ( preg_match( '/Template Name:/', $file_content, $file_matches ) ) {
if ( false == $this->check_file_contents( $checks, $file_path, $file_content ) ) {
$result = false;
}
} else {
// Test incoming file against all theme file name patterns
foreach ( $theme_file_patterns as $theme_file_pattern ) {
if ( preg_match( $theme_file_pattern, $file_path, $file_matches ) ) {
if ( false == $this->check_file_contents( $checks, $file_path, $file_content ) ) {
$result = false;
};
break;
}
}
}
}

return $result;
}

function check_file_contents( $checks, $file_path, $file_content ) {
$result = true;

foreach ( $checks as $check ) {
if ( false !== strpos( $file_content, $check ) ) {
$lines = $this->grep_content( $check, $file_content );
$this->add_error(
'template-forbidden-functions-' . $check,
sprintf( 'Redirection functions should not be called from template files' ),
'blocker',
$this->get_filename( $file_path ),
$lines
);
$result = false;
}
}

return $result;
}
}
1 change: 1 addition & 0 deletions vip-scanner/config-vip-scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'MasonryCheck',
'PostThumbnailsCheck',
'ScreenshotCheck',
'TemplateForbiddenFunctionsCheck',
'ThemecolorsCheck',
'ThemeNameCheck',
'TitleCheck',
Expand Down