Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit. Copying files over from http://plugins.svn.wordpress.…

…org/vip-scanner/ (r502822) because github's svn importer is broken and I'm too lazy to deal with git2svn right now :)
  • Loading branch information...
commit 2c266b7e870e1db200d04ec8f26873d88da470b4 1 parent ed7ad53
@mjangda mjangda authored
Showing with 2,356 additions and 0 deletions.
  1. +57 −0 css/vip-scanner.css
  2. +40 −0 readme.txt
  3. BIN  screenshot-1.png
  4. +18 −0 vip-scanner-wpcom.php
  5. +179 −0 vip-scanner-wpcom/checks/VIPRestrictedCommandsCheck.php
  6. +43 −0 vip-scanner-wpcom/checks/VIPRestrictedPatternsCheck.php
  7. +34 −0 vip-scanner-wpcom/checks/VIPWhitelistCheck.php
  8. +205 −0 vip-scanner.php
  9. +67 −0 vip-scanner/checks/BadThingsCheck.php
  10. +43 −0 vip-scanner/checks/BloginfoDeprecatedCheck.php
  11. +168 −0 vip-scanner/checks/DeprecatedCheck.php
  12. +25 −0 vip-scanner/checks/DirectoriesCheck.php
  13. +33 −0 vip-scanner/checks/GetOptionDeprecated.php
  14. +19 −0 vip-scanner/checks/GravatarCheck.php
  15. +35 −0 vip-scanner/checks/HardcodedLinksCheck.php
  16. +33 −0 vip-scanner/checks/MalwareCheck.php
  17. +35 −0 vip-scanner/checks/MoreDeprecatedCheck.php
  18. +31 −0 vip-scanner/checks/NonPrintableCheck.php
  19. +28 −0 vip-scanner/checks/PHPShortTagsCheck.php
  20. +27 −0 vip-scanner/checks/ThemeArtisteerCheck.php
  21. +48 −0 vip-scanner/checks/ThemeBasicChecks.php
  22. +23 −0 vip-scanner/checks/ThemeCommentPaginationCheck.php
  23. +22 −0 vip-scanner/checks/ThemeContentWidthCheck.php
  24. +28 −0 vip-scanner/checks/ThemeCustomizeCheck.php
  25. +19 −0 vip-scanner/checks/ThemeEditorStyleCheck.php
  26. +40 −0 vip-scanner/checks/ThemeFilesCheck.php
  27. +21 −0 vip-scanner/checks/ThemeIncludeCheck.php
  28. +22 −0 vip-scanner/checks/ThemeNavMenuCheck.php
  29. +37 −0 vip-scanner/checks/ThemePostFormatCheck.php
  30. +23 −0 vip-scanner/checks/ThemePostPaginationCheck.php
  31. +29 −0 vip-scanner/checks/ThemePostThumbnailCheck.php
  32. +27 −0 vip-scanner/checks/ThemeStyleOptionalCheck.php
  33. +37 −0 vip-scanner/checks/ThemeStyleRequiredCheck.php
  34. +25 −0 vip-scanner/checks/ThemeStyleSuggestedCheck.php
  35. +33 −0 vip-scanner/checks/ThemeSupportCheck.php
  36. +21 −0 vip-scanner/checks/ThemeTagCheck.php
  37. +36 −0 vip-scanner/checks/TimThumbCheck.php
  38. +32 −0 vip-scanner/checks/TimeDateCheck.php
  39. +135 −0 vip-scanner/checks/UndefinedFunctionCheck.php
  40. +30 −0 vip-scanner/checks/WormCheck.php
  41. +171 −0 vip-scanner/class-base-check.php
  42. +163 −0 vip-scanner/class-base-scanner.php
  43. +14 −0 vip-scanner/class-content-scanner.php
  44. +19 −0 vip-scanner/class-diff-scanner.php
  45. +70 −0 vip-scanner/class-directory-scanner.php
  46. +15 −0 vip-scanner/class-theme-scanner.php
  47. +41 −0 vip-scanner/config-vip-scanner.php
  48. +55 −0 vip-scanner/vip-scanner.php
View
57 css/vip-scanner.css
@@ -0,0 +1,57 @@
+.scan-results-table {
+ margin: 12px 0;
+}
+ .scan-results-table th,
+ .scan-results-table td {
+ padding: 3px 5px;
+ text-align: left;
+ border-bottom: #ECECEC 1px solid;
+ }
+ .scan-results-table td {
+ text-align: right;
+ }
+ .scan-results-table .pass {
+ color: #fff;
+ background-color: #7DA300;
+ }
+ .scan-results-table .fail {
+ color: #fff;
+ background-color: #C80030;
+ }
+
+.scan-results-list {
+}
+ .scan-results-list li {
+ border-bottom: 1px solid #DFDFDF;
+ padding: 5px 0;
+ }
+ .scan-level {
+ font-weight: bold;
+ color: #fff;
+ padding: 0 10px;
+ }
+ .scan-result-note .scan-level {
+ background-color: #A3C3D1;
+ }
+ .scan-result-warning .scan-level {
+ background-color: #FFE926;
+ }
+ .scan-result-blocker .scan-level {
+ background-color: #C80030;
+ }
+ .scan-file {
+ float: right;
+ font-family: courier new, monospace;
+ }
+ .scan-lines {
+ clear: both;
+ }
+ .scan-line .syntaxhighlighter {
+ padding: .5em 0;
+ background-color: #F7F9FE !important;
+ }
+ .scan-line .syntaxhighlighter .line,
+ .scan-line .syntaxhighlighter .line.alt1,
+ .scan-line .syntaxhighlighter .line.alt2 {
+ background-color: #F7F9FE !important;
+ }
View
40 readme.txt
@@ -0,0 +1,40 @@
+=== VIP Scanner ===
+Contributors: batmoo, automattic, tott
+Tags: scanner, scan, files, security, theme check
+Requires at least: 3.3
+Tested up to: 3.3
+Stable tag: 0.1
+
+Scan all sorts of themes and files and things.
+
+== Description ==
+
+Scan all sorts of themes and files and things.
+
+The plugin itself is simple a UI for the VIP Scanner library, which does all the heavy lifting. The library allows you to create arbitrary "Checks" (e.g. UndefinedFunctionCheck), group them together as Reviews (WordPress.org Theme Review), and run them against themes, plugins, directories, single files, and even diffs.
+
+This plugin is based on code from the <a href="http://wordpress.org/extend/plugins/theme-check/">Theme Check</a> (written by Pross and Otto42) and <a href="http://wordpress.org/extend/plugins/exploit-scanner/">Exploit Scanner</a> (written by donncha) plugins.
+
+== Installation ==
+
+1. Upload the plugin folder to the `/wp-content/plugins/` directory
+1. Activate the plugin through the 'Plugins' menu in WordPress
+1. Tools > VIP Scanner
+
+or
+
+Install using the Plugin Installer.
+
+== Frequently Asked Questions ==
+
+To come...
+
+== Screenshots ==
+
+1. The VIP Scanner has a slick UI. Slicker than your average.
+
+== Changelog ==
+
+= 0.1 =
+
+* Initial version, using slightly older versions of the Theme Check plugin's checks.
View
BIN  screenshot-1.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
18 vip-scanner-wpcom.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Plugin Name: VIP Scanner WordPress.com Rules
+ * Description: Custom rules for the VIP Scanner specific to WordPress.com
+ * Author: Automattic
+ *
+ * License: GPLv2
+ */
+
+add_action( 'vip_scanner_loaded', 'vip_scanner_custom_load_rules' );
+
+function vip_scanner_custom_load_rules() {
+ VIP_Scanner::get_instance()->register_review( 'VIP Theme Review', array(
+ 'VIPWhitelistCheck' => __DIR__ . '/vip-scanner-wpcom/checks/VIPWhitelistCheck.php',
+ 'VIPRestrictedPatternsCheck' => __DIR__ . '/vip-scanner-wpcom/checks/VIPRestrictedPatternsCheck.php',
+ 'VIPRestrictedCommandsCheck' => __DIR__ . '/vip-scanner-wpcom/checks/VIPRestrictedCommandsCheck.php',
+ ) );
+}
View
179 vip-scanner-wpcom/checks/VIPRestrictedCommandsCheck.php
@@ -0,0 +1,179 @@
+<?php
+
+class VIPRestrictedCommandsCheck extends BaseCheck
+{
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ // wordpress functions
+ "remove_filter" => array( "level" => "Warning", "note" => "Removing filters" ),
+ "remove_action" => array( "level" => "Warning", "note" => "Removing actions" ),
+ "add_filter" => array( "level" => "Note", "note" => "Altering filters" ),
+ "add_action" => array( "level" => "Note", "note" => "Altering actions" ),
+
+ "wp_cache_set" => array( "level" => "Warning", "note" => "Setting Cache Object" ),
+ "wp_cache_get" => array( "level" => "Note", "note" => "Getting Cache Object" ),
+ "wp_cache_add" => array( "level" => "Warning", "note" => "Adding Cache Object" ),
+ "wp_cache_delete" => array( "level" => "Warning", "note" => "Deleting Cache Object" ),
+ "set_transient" => array( "level" => "Warning", "note" => "Setting transient Object" ),
+ "get_transient" => array( "level" => "Note", "note" => "Getting transient Object" ),
+ "delete_transient" => array( "level" => "Warning", "note" => "Deleting transient Object" ),
+
+ "update_post_caches" => array( "level" => "Warning", "note" => "Post cache alteration" ),
+
+ "update_option" => array( "level" => "Warning", "note" => "Updating option" ),
+ "get_option" => array( "level" => "Note", "note" => "Getting option" ),
+ "add_option" => array( "level" => "Warning", "note" => "Adding Option" ),
+ "delete_option" => array( "level" => "Warning", "note" => "Deleting Option" ),
+
+ "wp_remote_get" => array( "level" => "Warning", "note" => "Remote operation" ),
+ "fetch_feed" => array( "level" => "Warning", "note" => "Remote feed operation" ),
+
+ "wp_schedule_event" => array( "level" => "Warning", "note" => "WP Cron usage" ),
+ "wp_schedule_single_event" => array( "level" => "Warning", "note" => "WP Cron usage" ),
+ "wp_clear_scheduled_hook" => array( "level" => "Warning", "note" => "WP Cron usage" ),
+ "wp_next_scheduled" => array( "level" => "Warning", "note" => "WP Cron usage" ),
+ "wp_unschedule_event" => array( "level" => "Warning", "note" => "WP Cron usage" ),
+ "wp_get_schedule" => array( "level" => "Warning", "note" => "WP Cron usage" ),
+
+ "add_feed" => array( "level" => "Warning", "note" => "Custom feed implementation" ),
+
+ // debugging
+ "error_log" => array( "level" => "Blocker", "note" => "Filesystem operation" ),
+ "var_dump" => array( "level" => "Warning", "note" => "Unfiltered variable output" ),
+ "print_r" => array( "level" => "Warning", "note" => "Unfiltered variable output" ),
+ "var_export" => array( "level" => "Warning", "note" => "Unfiltered variable output" ),
+
+ // other
+ "date_default_timezone_set" => array( "level" => "Blocker", "note" => "Timezone manipulation" ),
+ "error_reporting" => array( "level" => "Blocker", "note" => "Settings alteration" ),
+ "ini_set" => array( "level" => "Blocker", "note" => "Settings alteration" ),
+
+ // filesystem functions
+ //"basename" => array( "level" => "Note", "note" => "Returns filename component of path" ),
+ "chgrp" => array( "level" => "Blocker", "note" => "Changes file group" ),
+ "chmod" => array( "level" => "Blocker", "note" => "Changes file mode" ),
+ "chown" => array( "level" => "Blocker", "note" => "Changes file owner" ),
+ "clearstatcache" => array( "level" => "Blocker", "note" => "Clears file status cache" ),
+ "copy" => array( "level" => "Blocker", "note" => "Copies file" ),
+ "delete" => array( "level" => "Blocker", "note" => "See unlink or unset" ),
+ //"dirname" => array( "level" => "Warning", "note" => "Returns directory name component of path" ),
+ "disk_free_space" => array( "level" => "Warning", "note" => "Returns available space in directory" ),
+ "disk_total_space" => array( "level" => "Warning", "note" => "Returns the total size of a directory" ),
+ "diskfreespace" => array( "level" => "Warning", "note" => "Alias of disk_free_space" ),
+ "fclose" => array( "level" => "Warning", "note" => "Closes an open file pointer" ),
+ "feof" => array( "level" => "Warning", "note" => "Tests for end-of-file on a file pointer" ),
+ "fflush" => array( "level" => "Blocker", "note" => "Flushes the output to a file" ),
+ "fgetc" => array( "level" => "Warning", "note" => "Gets character from file pointer" ),
+ "fgetcsv" => array( "level" => "Warning", "note" => "Gets line from file pointer and parse for CSV fields" ),
+ "fgets" => array( "level" => "Warning", "note" => "Gets line from file pointer" ),
+ "fgetss" => array( "level" => "Warning", "note" => "Gets line from file pointer and strip HTML tags" ),
+ //"file_exists" => array( "level" => "Warning", "note" => "Checks whether a file or directory exists" ),
+ "file_get_contents" => array( "level" => "Warning", "note" => "Reads entire file into a string" ),
+ "file_put_contents" => array( "level" => "Blocker", "note" => "Write a string to a file" ),
+ "file" => array( "level" => "Warning", "note" => "Reads entire file into an array" ),
+ "fileatime" => array( "level" => "Warning", "note" => "Gets last access time of file" ),
+ "filectime" => array( "level" => "Warning", "note" => "Gets inode change time of file" ),
+ "filegroup" => array( "level" => "Warning", "note" => "Gets file group" ),
+ "fileinode" => array( "level" => "Warning", "note" => "Gets file inode" ),
+ "filemtime" => array( "level" => "Warning", "note" => "Gets file modification time" ),
+ "fileowner" => array( "level" => "Warning", "note" => "Gets file owner" ),
+ "fileperms" => array( "level" => "Warning", "note" => "Gets file permissions" ),
+ "filesize" => array( "level" => "Warning", "note" => "Gets file size" ),
+ "filetype" => array( "level" => "Warning", "note" => "Gets file type" ),
+ "flock" => array( "level" => "Warning", "note" => "Portable advisory file locking" ),
+ "fnmatch" => array( "level" => "Warning", "note" => "Match filename against a pattern" ),
+ "fopen" => array( "level" => "Blocker", "note" => "Opens file or URL" ),
+ "fpassthru" => array( "level" => "Warning", "note" => "Output all remaining data on a file pointer" ),
+ "fputcsv" => array( "level" => "Blocker", "note" => "Format line as CSV and write to file pointer" ),
+ "fputs" => array( "level" => "Blocker", "note" => "Alias of fwrite" ),
+ "fread" => array( "level" => "Warning", "note" => "Binary-safe file read" ),
+ "fscanf" => array( "level" => "Warning", "note" => "Parses input from a file according to a format" ),
+ "fseek" => array( "level" => "Warning", "note" => "Seeks on a file pointer" ),
+ "fstat" => array( "level" => "Warning", "note" => "Gets information about a file using an open file pointer" ),
+ "ftell" => array( "level" => "Warning", "note" => "Returns the current position of the file read/write pointer" ),
+ "ftruncate" => array( "level" => "Blocker", "note" => "Truncates a file to a given length" ),
+ "fwrite" => array( "level" => "Blocker", "note" => "Binary-safe file write" ),
+ "glob" => array( "level" => "Warning", "note" => "Find pathnames matching a pattern" ),
+ "is_dir" => array( "level" => "Warning", "note" => "Tells whether the filename is a directory" ),
+ "is_executable" => array( "level" => "Warning", "note" => "Tells whether the filename is executable" ),
+ "is_file" => array( "level" => "Warning", "note" => "Tells whether the filename is a regular file" ),
+ "is_link" => array( "level" => "Warning", "note" => "Tells whether the filename is a symbolic link" ),
+ //"is_readable" => array( "level" => "Warning", "note" => "Tells whether the filename is readable" ),
+ "is_uploaded_file" => array( "level" => "Warning", "note" => "Tells whether the file was uploaded via HTTP POST" ),
+ "is_writable" => array( "level" => "Warning", "note" => "Tells whether the filename is writable" ),
+ "is_writeable" => array( "level" => "Warning", "note" => "Alias of is_writable" ),
+ "lchgrp" => array( "level" => "Blocker", "note" => "Changes group ownership of symlink" ),
+ "lchown" => array( "level" => "Blocker", "note" => "Changes user ownership of symlink" ),
+ "link" => array( "level" => "Blocker", "note" => "Create a hard link" ),
+ "linkinfo" => array( "level" => "Warning", "note" => "Gets information about a link" ),
+ "lstat" => array( "level" => "Warning", "note" => "Gives information about a file or symbolic link" ),
+ "mkdir" => array( "level" => "Blocker", "note" => "Makes directory" ),
+ "move_uploaded_file" => array( "level" => "Blocker", "note" => "Moves an uploaded file to a new location" ),
+ "parse_ini_file" => array( "level" => "Warning", "note" => "Parse a configuration file" ),
+ "parse_ini_string" => array( "level" => "Warning", "note" => "Parse a configuration string" ),
+ "pathinfo" => array( "level" => "Warning", "note" => "Returns information about a file path" ),
+ "pclose" => array( "level" => "Warning", "note" => "Closes process file pointer" ),
+ "popen" => array( "level" => "Blocker", "note" => "Opens process file pointer" ),
+ "readfile" => array( "level" => "Warning", "note" => "Outputs a file" ),
+ "readlink" => array( "level" => "Warning", "note" => "Returns the target of a symbolic link" ),
+ "realpath" => array( "level" => "Warning", "note" => "Returns canonicalized absolute pathname" ),
+ "rename" => array( "level" => "Blocker", "note" => "Renames a file or directory" ),
+ "rewind" => array( "level" => "Warning", "note" => "Rewind the position of a file pointer" ),
+ "rmdir" => array( "level" => "Blocker", "note" => "Removes directory" ),
+ "set_file_buffer" => array( "level" => "Warning", "note" => "Alias of stream_set_write_buffer" ),
+ "stat" => array( "level" => "Warning", "note" => "Gives information about a file" ),
+ "symlink" => array( "level" => "Blocker", "note" => "Creates a symbolic link" ),
+ "tempnam" => array( "level" => "Warning", "note" => "Create file with unique file name" ),
+ "tmpfile" => array( "level" => "Blocker", "note" => "Creates a temporary file" ),
+ "touch" => array( "level" => "Blocker", "note" => "Sets access and modification time of file" ),
+ "umask" => array( "level" => "Blocker", "note" => "Changes the current umask" ),
+ "unlink" => array( "level" => "Blocker", "note" => "Deletes a file" ),
+
+ // process control functions
+ "pcntl_alarm" => array( "level" => "Blocker", "note" => "Set an alarm clock for delivery of a signal" ),
+ "pcntl_exec" => array( "level" => "Blocker", "note" => "Executes specified program in current process space" ),
+ "pcntl_fork" => array( "level" => "Blocker", "note" => "Forks the currently running process" ),
+ "pcntl_getpriority" => array( "level" => "Blocker", "note" => "Get the priority of any process" ),
+ "pcntl_setpriority" => array( "level" => "Blocker", "note" => "Change the priority of any process" ),
+ "pcntl_signal_dispatch" => array( "level" => "Blocker", "note" => "Calls signal handlers for pending signals" ),
+ "pcntl_signal" => array( "level" => "Blocker", "note" => "Installs a signal handler" ),
+ "pcntl_sigprocmask" => array( "level" => "Blocker", "note" => "Sets and retrieves blocked signals" ),
+ "pcntl_sigtimedwait" => array( "level" => "Blocker", "note" => "Waits for signals, with a timeout" ),
+ "pcntl_sigwaitinfo" => array( "level" => "Blocker", "note" => "Waits for signals" ),
+ "pcntl_wait" => array( "level" => "Blocker", "note" => "Waits on or returns the status of a forked child" ),
+ "pcntl_waitpid" => array( "level" => "Blocker", "note" => "Waits on or returns the status of a forked child" ),
+ "pcntl_wexitstatus" => array( "level" => "Blocker", "note" => "Returns the return code of a terminated child" ),
+ "pcntl_wifexited" => array( "level" => "Blocker", "note" => "Checks if status code represents a normal exit" ),
+ "pcntl_wifsignaled" => array( "level" => "Blocker", "note" => "Checks whether the status code represents a termination due to a signal" ),
+ "pcntl_wifstopped" => array( "level" => "Blocker", "note" => "Checks whether the child process is currently stopped" ),
+ "pcntl_wstopsig" => array( "level" => "Blocker", "note" => "Returns the signal which caused the child to stop" ),
+ "pcntl_wtermsig" => array( "level" => "Blocker", "note" => "Returns the signal which caused the child to terminate" ),
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ( $checks as $check => $check_info ) {
+ $pattern = "/\s+($check)+\s?\(+/msiU";
+
+ $this->increment_check_count();
+
+ if ( preg_match( $pattern, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );//esc_html( rtrim( $matches[0],'(') );
+ $lines = $this->grep_content( rtrim( $matches[0], '(' ), $file_content );
+ $this->add_error(
+ $check,
+ $check_info['note'],
+ $check_info['level'],
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+
+ return $result;
+ }
+}
View
43 vip-scanner-wpcom/checks/VIPRestrictedPatternsCheck.php
@@ -0,0 +1,43 @@
+<?php
+
+class VIPRestrictedPatternsCheck extends BaseCheck
+{
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ "/(kses)+/msiU" => array ( "level" => "Warning", "note" => "Working with kses" ),
+ "/(\\\$wpdb->|mysql_|WP_Query)+.+(ALTER)+\s+/msiU" => array( "level" => "Blocker", "note" => "Possible database table alteration" ),
+ "/(\\\$wpdb->|mysql_|WP_Query)+.+(CREATE)+\s+/msiU" => array( "level" => "Blocker", "note" => "Possible database table creation" ),
+ "/(\\\$wpdb->|mysql_|WP_Query)+.+(DROP)+\s+/msiU" => array( "level" => "Blocker", "note" => "Possible database table deletion" ),
+ "/(\\\$wpdb->|mysql_|WP_Query)+.+(DELETE)+\s+(FROM)+\s+/msiU" => array( "level" => "Note", "note" => "Direct database delete query" ),
+ "/(\\\$wpdb->|mysql_|WP_Query)+.+(SELECT)+\s.+/msiU" => array( "level" => "Note", "note" => "Direct Database select query" ),
+ "/(^GLOBAL)(\\\$wpdb->|mysql_|WP_Query)+/msiU" => array( "level" => "Warning", "note" => "Possible direct database query" ),
+ "/(echo|print|\<\?\=)+.+(\\\$GLOBALS|\\\$_SERVER|\\\$_GET|\\\$_REQUEST|\\\$_POST)+/msiU" => array( "level" => "Warning", "note" => "Possible output of restricted variables" ),
+ "/(echo|print|\<\?\=)+.+(get_search_query)+/msiU" => array( "level" => "Warning", "note" => "Output of search query" ),
+ "/(\\\$GLOBALS|\\\$_SERVER|\\\$_GET|\\\$_REQUEST|\\\$_POST)+/msiU" => array( "level" => "Note", "note" => "Working with superglobals" ),
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ( $checks as $check => $check_info ) {
+ $this->increment_check_count();
+
+ if ( preg_match( $check, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );//esc_html( rtrim( $matches[0],'(') );
+ $lines = $this->grep_content( $matches[0], $file_content );
+ $this->add_error(
+ $check,
+ $check_info['note'],
+ $check_info['level'],
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+
+ return $result;
+ }
+}
View
34 vip-scanner-wpcom/checks/VIPWhitelistCheck.php
@@ -0,0 +1,34 @@
+<?php
+
+class VIPWhitelistCheck extends BaseCheck
+{
+ function check( $files ) {
+ $result = true;
+
+ $php = $this->merge_files( $files, 'php' );
+
+ $checks = array(
+ "/<!DOCTYPE\s+html([^>]{0,})/msiU" => array( "level" => "Warning", "note" => "No doctype defined" ),
+ "/<html.+(language_attributes){1}([^>]{0,})/msiU" => array( "level" => "Warning", "note" => "No language_attributes() in html tag" ),
+ "/<head.+profile=\"(.+)\"([^>]{0,})/msiU" => array( "level" => "Warning", "note" => "Profile attribute missing in head tag" ),
+ //"/<meta\sname=\"generator\"\scontent=\".*WordPress.*\"([^>]+)/msiU" => array( "level" => "Warning", "note" => "Meta tag generator not set or not wordpress.com" ),
+ "/(wp_head)+\s?\(\)/msiU" => array( "level" => "Blocker", "note" => "wp_head() call missing" ),
+ "/(wp_footer)+\s?\(\)/msiU" => array( "level" => "Blocker", "note" => "wp_footer() call missing" ),
+ "/<a.+href=[\"|']?(http:\/\/en\.wordpress\.com\/vip-hosting\/).[\"|']?([^>]+).+Wordpress\.com\sVIP([^<]+)</msiU" => array( "level" => "Warning", "note" => "Attribution link missing or not well formatted" ),
+ );
+
+ foreach ( $checks as $check => $check_info ) {
+ $this->increment_check_count();
+ if ( ! preg_match( $check, $php ) ) {
+ $this->add_error(
+ $check,
+ $check_info['note'],
+ $check_info['level']
+ );
+ $result = false;
+ }
+ }
+
+ return $result;
+ }
+}
View
205 vip-scanner.php
@@ -0,0 +1,205 @@
+<?php
+/*
+Plugin Name: VIP Scanner
+Plugin URI: http://vip.wordpress.com
+Description: Easy to use UI for the VIP Scanner.
+Author: Mohammad Jangda (Original code by Pross, Otto42, and Thorsten Ott), Automattic
+Version: 0.1
+
+License: GPLv2
+*/
+
+require_once( __DIR__ . '/vip-scanner/vip-scanner.php' );
+
+class VIP_Scanner_UI {
+ const key = 'vip-scanner';
+
+ private static $instance;
+
+ function __construct() {
+ add_action( 'init', array( $this, 'init' ) );
+ do_action( 'vip_scanner_loaded' );
+ }
+
+ function init() {
+ add_action( 'admin_menu', array( $this, 'add_menu_page' ) );
+ }
+
+ static function get_instance() {
+ if ( ! isset( self::$instance ) ) {
+ $class_name = __CLASS__;
+ self::$instance = new $class_name;
+ }
+ return self::$instance;
+ }
+
+ function add_menu_page() {
+ $hook = add_submenu_page( 'tools.php', 'VIP Scanner', 'VIP Scanner', 'manage_options', self::key, array( $this, 'display_admin_page' ) );
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
+ }
+
+ function admin_enqueue_scripts( $hook ) {
+ if ( 'tools_page_' . self::key !== $hook )
+ return;
+
+ wp_enqueue_style( 'vip-scanner-css', plugins_url( 'css/vip-scanner.css', __FILE__ ) );
+ }
+
+ function display_admin_page() {
+ global $title;
+
+ if ( !current_user_can( 'manage_options' ) ) {
+ wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
+ }
+
+ ?>
+ <div id="vip-scanner" class="wrap">
+ <?php screen_icon( 'themes' ); ?>
+ <h2><?php echo esc_html( $title ); ?></h2>
+ <?php $this->display_vip_scanner_form(); ?>
+ <?php $this->do_theme_review(); ?>
+ </div>
+ <?php
+ }
+
+ function display_vip_scanner_form() {
+ $themes = get_themes();
+ $review_types = VIP_Scanner::get_instance()->get_review_types();
+ $current_theme = isset( $_POST[ 'vip-scanner-theme-name' ] ) ? sanitize_text_field( $_POST[ 'vip-scanner-theme-name' ] ) : get_stylesheet();
+ $current_review = isset( $_POST[ 'vip-scanner-review-type' ] ) ? sanitize_text_field( $_POST[ 'vip-scanner-review-type' ] ) : $review_types[0]; // TODO: eugh, need better error checking
+ ?>
+ <form method="POST">
+ <p>Select a theme and the review that you want to run:</p>
+ <select name="vip-scanner-theme-name">
+ <?php foreach ( $themes as $name => $location ) : ?>
+ <?php var_dump( $location, $current_theme ); ?>
+ <option <?php selected( $current_theme, $location['Stylesheet'] ); ?> value="<?php echo esc_attr( $location['Stylesheet'] ); ?>"><?php echo esc_html( $name ); ?></option>
+ <?php endforeach; ?>
+ </select>
+ <select name="vip-scanner-review-type">
+ <?php foreach ( $review_types as $review_type ) : ?>
+ <option <?php selected( $current_review, $review_type ); ?> value="<?php echo esc_attr( $review_type ); ?>"><?php echo esc_html( $review_type ); ?></option>
+ <?php endforeach; ?>
+ </select>
+ <?php submit_button( 'Check it!', 'primary', 'submit', false ); ?>
+ <?php wp_nonce_field( 'vip-scan-theme', 'vip-scanner-nonce' ); ?>
+ <input type="hidden" name="page" value="<?php echo self::key; ?>" />
+ </form>
+ <?php
+ }
+
+ function do_theme_review() {
+ if( ! isset( $_POST[ 'vip-scanner-nonce' ] ) || ! wp_verify_nonce( $_POST[ 'vip-scanner-nonce' ], 'vip-scan-theme' ) )
+ return;
+
+ if ( ! isset( $_POST[ 'vip-scanner-theme-name' ] ) )
+ return;
+
+ $theme = sanitize_text_field( $_POST[ 'vip-scanner-theme-name' ] );
+ $review = isset( $_POST[ 'vip-scanner-review-type' ] ) ? sanitize_text_field( $_POST[ 'vip-scanner-review-type' ] ) : $review_types[0]; // TODO: eugh, need better error checking
+
+ $scanner = VIP_Scanner::get_instance()->run_theme_review( $theme, $review );
+ if ( $scanner )
+ $this->display_theme_review_result( $scanner, $theme );
+ else
+ $this->display_scan_error();
+ }
+
+ function display_theme_review_result( $scanner, $theme ) {
+ global $SyntaxHighlighter;
+ if ( isset( $SyntaxHighlighter ) ) {
+ add_action( 'admin_footer', array( &$SyntaxHighlighter, 'maybe_output_scripts' ) );
+ }
+
+ $errors_whitelist = 'blocker'; // todo: filter
+
+ $results = $scanner->get_results();
+ $errors = $scanner->get_errors( $errors_whitelist ); // TODO: Need to set level filter at scan funtion. Otherwise you might get 0 blockers but still fail
+ $errors_count = count( $errors );
+ $result = ! $errors_count;
+ ?>
+ <h4>Scanning: <?php echo $theme; ?></h4>
+
+ <table class="scan-results-table">
+ <tr>
+ <th>Scan Result</th>
+ <td class="<?php echo $result ? 'pass' : 'fail'; ?>"><?php echo $result ? 'Pass' : 'Fail'; ?></td>
+ </tr>
+ <tr>
+ <th>Total Files</th>
+ <td><?php echo intval( $results['total_files'] ); ?></td>
+ </tr>
+ <tr>
+ <th>Total Checks</th>
+ <td><?php echo intval( $results['total_checks'] ); ?></td>
+ </tr>
+ <tr>
+ <th>Total Errors</th>
+ <td><?php echo $errors_count; ?></td>
+ </tr>
+ </table>
+
+ <ol class="scan-results-list">
+ <?php
+ foreach( $errors as $error ) {
+ $this->display_theme_review_result_row( $error, $scanner, $theme );
+ }
+ ?>
+ </ol>
+ <?php
+ }
+
+ function display_theme_review_result_row( $error, $scanner, $theme ) {
+ global $SyntaxHighlighter;
+
+ $level = $error['level'];
+ $description = $error['description'];
+ if( ! empty( $error['file'] ) ) {
+ $file_full_path = $error['file'];
+ $file_theme_path = substr( $file_full_path, strrpos( $file_full_path, sprintf( '/%s/', $theme ) ) );
+ $file = strrchr( $file_full_path, sprintf( '/%s/', $theme ) );
+ } else {
+ $file = '';
+ }
+ $lines = ! empty( $error['lines'] ) ? $error['lines'] : array();
+
+ ?>
+ <li class="scan-result-<?php echo strtolower( $level ); ?>">
+ <span class="scan-level"><?php echo $level; ?></span>
+ <span class="scan-description"><?php echo $description; ?></span>
+
+ <?php if( ! empty( $file ) ) : ?>
+ <span class="scan-file">
+ <?php echo $file; ?>
+ </span>
+ <?php endif; ?>
+
+ <?php if( ! empty( $lines ) ) : ?>
+ <div class="scan-lines">
+ <?php foreach( $lines as $line ) : ?>
+ <div class="scan-line">
+ <?php
+ if ( isset( $SyntaxHighlighter ) ) {
+ // TODO: Should detect file type and set appropriate brush
+ $line_shortcode = '[sourcecode language="php" htmlscript="true" light="true"]' . html_entity_decode( $line ) . '[/sourcecode]';
+ echo $SyntaxHighlighter->parse_shortcodes( $line_shortcode );
+ } else {
+ echo '<pre>' . html_entity_decode( $line ) . '</pre>';
+ }
+ ?>
+ </div>
+ <?php endforeach; ?>
+ </div>
+ <?php endif; ?>
+
+ </li>
+ <?php
+ }
+
+ function display_scan_error() {
+ echo 'Uh oh! Looks like something went wrong :(';
+ }
+}
+
+// Initialize!
+VIP_Scanner_UI::get_instance();
View
67 vip-scanner/checks/BadThingsCheck.php
@@ -0,0 +1,67 @@
+<?php
+class BadThingsCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ '/[\s|]eval\s*\([^\$|\'](.){25}/i' => 'eval() is not allowed.',
+ '/[\s](popen|proc_open|exec|shell_exec|system|passthru)\(/is' => 'PHP system calls should be disabled by server admins anyway!',
+ '/base64_decode/ims' => '`base64_decode()` is not allowed',
+ '/base64_encode/ims' => '`base64_encode()` is not allowed',
+ '/uudecode/ims' => 'uudecode() is not allowed',
+ '/str_rot13/ims' => 'str_rot13() is not allowed',
+ '/cx=[0-9]{21}:[a-z0-9]{10}/ims' => 'Google search code detected',
+ '/add_(admin|submenu|theme)_page\s?\x28.*,\s?[0-9]\s?,/i' => 'Please see [Roles and Capabilities](http://codex.wordpress.org/Roles_and_Capabilities)',
+ '/pub-[0-9]{16}/i' => 'Google advertising code detected'
+ );
+
+ $php_files = $this->filter_files( $files, 'php' );
+
+ foreach ( $php_files as $file_path => $file_content ) {
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );
+ $lines = $this->grep_content( $error, $file_content );
+ $this->add_error(
+ $key,
+ sprintf( 'Found `%1$s` in the file. %2$s.', $error, $check ),
+ 'warning',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+
+
+ $checks = array(
+ '/cx=[0-9]{21}:[a-z0-9]{10}/ms' => 'Google search code detected',
+ '/pub-[0-9]{16}/' => 'Google advertising code detected'
+ );
+
+ $other_files = array_diff( $this->get_all_files( $files ), $php_files );
+
+ foreach ( $other_files as $file_path => $file_content ) {
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file_content, $matches ) ) {
+ $filename = tc_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );
+ $lines = $this->grep_content( $error, $file_content );
+ $this->add_error(
+ $key,
+ sprintf( 'Found `%1$s` in the file. %2$s.', $error, $check ),
+ 'warning',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
43 vip-scanner/checks/BloginfoDeprecatedCheck.php
@@ -0,0 +1,43 @@
+<?php
+class BloginfoDeprecatedCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ '/[\s|]get_bloginfo\((\s|)("|\')url("|\')(\s|)\)/m' => 'home_url()',
+ '/[\s|]get_bloginfo\((\s|)("|\')wpurl("|\')(\s|)\)/m' => 'site_url()',
+ '/[\s|]get_bloginfo\((\s|)("|\')stylesheet_directory("|\')(\s|)\)/m' => 'get_stylesheet_directory_uri()',
+ '/[\s|]get_bloginfo\((\s|)("|\')template_directory("|\')(\s|)\)/m' => 'get_template_directory_uri()',
+ '/[\s|]get_bloginfo\((\s|)("|\')template_url("|\')(\s|)\)/m' => 'get_template_directory_uri()',
+ '/[\s|]get_bloginfo\((\s|)("|\')text_direction("|\')(\s|)\)/m' => 'is_rtl()',
+ '/[\s|]get_bloginfo\((\s|)("|\')feed_url("|\')(\s|)\)/m' => 'get_feed_link( \'feed\' ) (where feed is rss, rss2, atom)',
+ '/[\s|]bloginfo\((\s|)("|\')url("|\')(\s|)\)/m' => 'echo home_url()',
+ '/[\s|]bloginfo\((\s|)("|\')wpurl("|\')(\s|)\)/m' => 'echo site_url()',
+ '/[\s|]bloginfo\((\s|)("|\')stylesheet_directory("|\')(\s|)\)/m' => 'get_stylesheet_directory_uri()',
+ '/[\s|]bloginfo\((\s|)("|\')template_directory("|\')(\s|)\)/m' => 'get_template_directory_uri()',
+ '/[\s|]bloginfo\((\s|)("|\')template_url("|\')(\s|)\)/m' => 'get_template_directory_uri()',
+ '/[\s|]bloginfo\((\s|)("|\')text_direction("|\')(\s|)\)/m' => 'is_rtl()',
+ '/[\s|]bloginfo\((\s|)("|\')feed_url("|\')(\s|)\)/m' => 'get_feed_link( \'feed\' ) (where feed is rss, rss2, atom)',
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = trim( rtrim( $matches[0], '(' ) ); //trim( esc_html( rtrim( $matches[0], '(' ) ) );
+ $lines = $this->grep_content( rtrim( $matches[0], '(' ), $file_content );
+ $this->add_error(
+ $key,
+ sprintf( '`%1$s` was found in the file. Use `%2$s` instead.', $error, $check ),
+ 'recommended',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
168 vip-scanner/checks/DeprecatedCheck.php
@@ -0,0 +1,168 @@
+<?php
+
+class DeprecatedCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ // start wp-includes deprecated
+ array('get_post_data' => 'get_post()', '1.5.1'),
+ array('start_wp' => 'Use the Loop', '1.5'),
+ array('the_category_id' => 'get_the_category()', '0.71'),
+ array('the_category_head' => 'get_the_category_by_ID()', '0.71'),
+ array('previous_post' => 'previous_post_link()', '2.0'),
+ array('next_post' => 'next_post_link()', '2.0'),
+ array('user_can_create_post' => 'current_user_can()', '2.0'),
+ array('user_can_create_draft' => 'current_user_can()', '2.0'),
+ array('user_can_edit_post' => 'current_user_can()', '2.0'),
+ array('user_can_delete_post' => 'current_user_can()', '2.0'),
+ array('user_can_set_post_date' => 'current_user_can()', '2.0'),
+ array('user_can_edit_post_comments' => 'current_user_can()', '2.0'),
+ array('user_can_delete_post_comments' => 'current_user_can()', '2.0'),
+ array('user_can_edit_user' => 'current_user_can()', '2.0'),
+ array('get_linksbyname' => 'get_bookmarks()', '2.1'),
+ array('wp_get_linksbyname' => 'wp_list_bookmarks()', '2.1'),
+ array('get_linkobjectsbyname' => 'get_bookmarks()', '2.1'),
+ array('get_linkobjects' => 'get_bookmarks()', '2.1'),
+ array('get_linksbyname_withrating' => 'get_bookmarks()', '2.1'),
+ array('get_links_withrating' => 'get_bookmarks()', '2.1'),
+ array('get_autotoggle' => 'none available', '2.1'),
+ array('list_cats' => 'wp_list_categories', '2.1'),
+ array('wp_list_cats' => 'wp_list_categories', '2.1'),
+ array('dropdown_cats' => 'wp_dropdown_categories()', '2.1'),
+ array('list_authors' => 'wp_list_authors()', '2.1'),
+ array('wp_get_post_cats' => 'wp_get_post_categories()', '2.1'),
+ array('wp_set_post_cats' => 'wp_set_post_categories()', '2.1'),
+ array('get_archives' => 'wp_get_archives', '2.1'),
+ array('get_author_link' => 'get_author_posts_url()', '2.1'),
+ array('link_pages' => 'wp_link_pages()', '2.1'),
+ array('get_settings' => 'get_option()', '2.1'),
+ array('permalink_link' => 'the_permalink()', '1.2'),
+ array('permalink_single_rss' => 'permalink_rss()', '2.3'),
+ array('wp_get_links' => 'wp_list_bookmarks()', '2.1'),
+ array('get_links' => 'get_bookmarks()', '2.1'),
+ array('get_links_list' => 'wp_list_bookmarks()', '2.1'),
+ array('links_popup_script' => 'none available', '2.1'),
+ array('get_linkrating' => 'sanitize_bookmark_field()', '2.1'),
+ array('get_linkcatname' => 'get_category()', '2.1'),
+ array('comments_rss_link' => 'post_comments_feed_link()', '2.5'),
+ array('get_category_rss_link' => 'get_category_feed_link()'. '2.5'),
+ array('get_author_rss_link' => 'get_author_feed_link()', '2.5'),
+ array('comments_rss' => 'get_post_comments_feed_link()', '2.2'),
+ array('create_user' => 'wp_create_user()', '2.0'),
+ array('gzip_compression' => 'none available', '2.5'),
+ array('get_commentdata' => 'get_comment()', '2.7'),
+ array('get_catname' => 'get_cat_name()', '2.8'),
+ array('get_category_children' => 'get_term_children', '2.8'),
+ array('get_the_author_description' => 'get_the_author_meta(\'description\')', '2.8'),
+ array('the_author_description' => 'the_author_meta(\'description\')', '2.8'),
+ array('get_the_author_login' => 'the_author_meta(\'login\')', '2.8'),
+ array('get_the_author_firstname' => 'get_the_author_meta(\'first_name\')', '2.8'),
+ array('the_author_firstname' => 'the_author_meta(\'first_name\')', '2.8'),
+ array('get_the_author_lastname' => 'get_the_author_meta(\'last_name\')', '2.8'),
+ array('the_author_lastname' => 'the_author_meta(\'last_name\')', '2.8'),
+ array('get_the_author_nickname' => 'get_the_author_meta(\'nickname\')', '2.8'),
+ array('the_author_nickname' => 'the_author_meta(\'nickname\')', '2.8'),
+ array('get_the_author_email' => 'get_the_author_meta(\'email\')', '2.8'),
+ array('the_author_email' => 'the_author_meta(\'email\')', '2.8'),
+ array('get_the_author_icq' => 'get_the_author_meta(\'icq\')', '2.8'),
+ array('the_author_icq' => 'the_author_meta(\'icq\')', '2.8'),
+ array('get_the_author_yim' => 'get_the_author_meta(\'yim\')', '2.8'),
+ array('the_author_yim' => 'the_author_meta(\'yim\')', '2.8'),
+ array('get_the_author_msn' => 'get_the_author_meta(\'msn\')', '2.8'),
+ array('the_author_msn' => 'the_author_meta(\'msn\')', '2.8'),
+ array('get_the_author_aim' => 'get_the_author_meta(\'aim\')', '2.8'),
+ array('the_author_aim' => 'the_author_meta(\'aim\')', '2.8'),
+ array('get_author_name' => 'get_the_author_meta(\'display_name\')', '2.8'),
+ array('get_the_author_url' => 'get_the_author_meta(\'url\')', '2.8'),
+ array('the_author_url' => 'the_author_meta(\'url\')', '2.8'),
+ array('get_the_author_ID' => 'get_the_author_meta(\'ID\')', '2.8'),
+ array('the_author_ID' => 'the_author_meta(\'ID\')', '2.8'),
+ array('the_content_rss' => 'the_content_feed()', '2.9'),
+ array('make_url_footnote' => 'none available', '2.9'),
+ array('_c' => '_x()', '2.9'),
+ array('translate_with_context' => '_x()', '3.0'),
+ array('nc' => 'nx()', '3.0'),
+ array('__ngettext' => '_n_noop()', '2.8'),
+ array('__ngettext_noop' => '_n_noop()', '2.8'),
+ array('get_alloptions' => 'wp_load_alloptions()', '3.0'),
+ array('get_the_attachment_link' => 'wp_get_attachment_link()', '2.5'),
+ array('get_attachment_icon_src' => 'wp_get_attachment_image_src()', '2.5'),
+ array('get_attachment_icon' => 'wp_get_attachment_image()', '2.5'),
+ array('get_attachment_innerhtml' => 'wp_get_attachment_image()', '2.5'),
+ array('get_link' => 'get_bookmark()', '2.1'),
+ array('sanitize_url' => 'esc_url()', '2.8'),
+ array('clean_url' => 'esc_url()', '3.0'),
+ array('js_escape' => 'esc_js()', '2.8'),
+ array('wp_specialchars' => 'esc_html()', '2.8'),
+ array('attribute_escape' => 'esc_attr()', '2.8'),
+ array('register_sidebar_widget' => 'wp_register_sidebar_widget()', '2.8'),
+ array('unregister_sidebar_widget' => 'wp_unregister_sidebar_widget()', '2.8'),
+ array('register_widget_control' => 'wp_register_widget_control()', '2.8'),
+ array('unregister_widget_control' => 'wp_unregister_widget_control()', '2.8'),
+ array('delete_usermeta' => 'delete_user_meta()', '3.0'),
+ array('get_usermeta' => 'get_user_meta()', '3.0'),
+ array('update_usermeta' => 'update_user_meta()', '3.0'),
+ array('automatic_feed_links' => 'add_theme_support( \'automatic-feed-links\' )', '3.0'),
+ array('get_profile' => 'get_the_author_meta()', '3.0'),
+ array('get_usernumposts' => 'count_user_posts()', '3.0'),
+ array('funky_javascript_callback' => 'none available', '3.0'),
+ array('funky_javascript_fix' => 'none available', '3.0'),
+ array('is_taxonomy' => 'taxonomy_exists()', '3.0'),
+ array('is_term' => 'term_exists()', '3.0'),
+ array('is_plugin_page' => '$plugin_page and/or get_plugin_page_hookname() hooks', '3.1'),
+ array('update_category_cache' => 'No alternatives', '3.1'),
+ // end wp-includes deprecated
+
+ // start wp-admin deprecated
+ array('tinymce_include' => 'wp_tiny_mce()', '2.1'),
+ array('documentation_link' => 'None available', '2.5'),
+ array('wp_shrink_dimensions' => 'wp_constrain_dimensions()','3.0'),
+ array('dropdown_categories' => 'wp_category_checklist()','2.6'),
+ array('dropdown_link_categories' => 'wp_link_category_checklist()','2.6'),
+ array('wp_dropdown_cats' => 'wp_dropdown_categories()','3.0'),
+ array('add_option_update_handler' => 'register_setting()','3.0'),
+ array('remove_option_update_handler' => 'unregister_setting()','3.0'),
+ array('codepress_get_lang' => 'None available','3.0'),
+ array('codepress_footer_js' => 'None available','3.0'),
+ array('use_codepress' => 'None available','3.0'),
+ array('get_author_user_ids' => 'None available','3.1'),
+ array('get_editable_authors' => 'None available','3.1'),
+ array('get_editable_user_ids' => 'None available','3.1'),
+ array('get_nonauthor_user_ids' => 'None available','3.1'),
+ array('WP_User_Search' => 'WP_User_Query','3.1'),
+ array('get_others_unpublished_posts' => 'None available','3.1'),
+ array('get_others_drafts' => 'None available','3.1'),
+ array('get_others_pending' => 'None available','3.1'),
+ array('register_column_headers' => 'WP_list_table','3.1'),
+ array('print_column_headers WP_list_table' => 'None available','3.1')
+ // end wp-admin
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ( $checks as $alt => $check ) {
+ $this->increment_check_count();
+
+ $version = $check;
+ $key = key( $check );
+ $alt = $check[$key];
+
+ if ( preg_match( '/[\s|]' . $key . '\(/m', $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );
+ $version = $check[0];
+ $lines = $this->grep_content( $error, $file_content );
+ $this->add_error(
+ $key,
+ sprintf( '%1$s` found in the file. Deprecated since v%2$s. Use `%3$s` instead.', $error, $version, $alt ),
+ 'blocker',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
25 vip-scanner/checks/DirectoriesCheck.php
@@ -0,0 +1,25 @@
+<?php
+
+class DirectoriesCheck extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+ $found = false;
+
+ foreach ( $files as $path => $file ) {
+ $this->increment_check_count();
+ if ( strpos( $path, '.git' ) !== false || strpos( $path, '.svn' ) !== false )
+ $found = true;
+ }
+
+ if ( $found ) {
+ $this->add_error(
+ 'unnecessary-directories',
+ 'Please remove any extraneous directories like `.git` or `.svn`',
+ 'required'
+ );
+ $result = false;
+ }
+ return $result;
+ }
+}
View
33 vip-scanner/checks/GetOptionDeprecated.php
@@ -0,0 +1,33 @@
+<?php
+
+class GetOptionDeprecated extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+
+ $checks = array(
+ '/[\s|]get_option\((\s|)("|\')home("|\')(\s|)\)/m' => 'home_url()',
+ '/[\s|]get_option\((\s|)("|\')site_url("|\')(\s|)\)/m' => 'site_url()',
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );//esc_html( rtrim($matches[0],'(') );
+ $lines = $this->grep_content( rtrim($matches[0],'('), $file_content );
+ $this->add_error(
+ $key,
+ sprintf( '`%1$s` was found in the file. Use `%2$s` instead.', $error, $check ),
+ 'required',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
19 vip-scanner/checks/GravatarCheck.php
@@ -0,0 +1,19 @@
+<?php
+
+class GravatarCheck extends BaseCheck {
+
+ function check( $files ) {
+ $result = true;
+
+ $this->increment_check_count();
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( ( strpos( $php, 'get_avatar' ) === false ) && ( strpos( $php, 'wp_list_comments' ) === false ) ) {
+ $this->add_error( 'gravatar', 'blocker', 'Gravatar support not found. Use `get_avatar` or `wp_list_comments` to add this support.' );
+ $result = false;
+ }
+
+ return $result;
+ }
+
+}
View
35 vip-scanner/checks/HardcodedLinksCheck.php
@@ -0,0 +1,35 @@
+<?php
+class HardcodedLinksCheck extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ $this->increment_check_count();
+
+ // regex borrowed from TAC
+ $url_regex ='([[:alnum:]\-\.])+(\\.)([[:alnum:]]){2,4}([[:blank:][:alnum:]\/\+\=\%\&\_\\\.\~\?\-]*)';
+ $title_regex ='[[:blank:][:alnum:][:punct:]]*'; // 0 or more: any num, letter(upper/lower) or any punc symbol
+ $space_regex ='(\\s*)';
+
+ if ( preg_match_all( "/(<a)(\\s+)(href" . $space_regex . "=" . $space_regex . "\"" . $space_regex . "((http|https|ftp):\\/\\/)?)" . $url_regex . "(\"".$space_regex . $title_regex . $space_regex .">)" . $title_regex . "(<\\/a>)/is", $file_content, $out, PREG_SET_ORDER ) ) {
+ $filename = $this->get_filename( $file_path );
+ foreach( $out as $key ) {
+ if ( $key[0] && !strpos( $key[0], 'wordpress.org' ) ) {
+ $lines = $this->grep_content( $key[0], $file_content );
+ }
+ }
+ if ( ! empty( $lines ) ) {
+ $this->add_error(
+ 'hardcoded-links',
+ 'Possible hard-coded links were found in the file',
+ 'info',
+ $filename,
+ $lines
+ );
+ }
+ }
+ }
+ return $result;
+ }
+}
View
33 vip-scanner/checks/MalwareCheck.php
@@ -0,0 +1,33 @@
+<?php
+class MalwareCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ '/[^a-z0-9|_](file_get_contents|curl_exec|ob_get_contents|curl_init|readfile|fopen|fsockopen|pfsockopen|fclose|fread|file_put_contents)\(/' => 'possible file operations',
+ '/iframe\ssrc/' => 'iframes can contain spam links'
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = ltrim( $matches[0], '(' );
+ $error = rtrim( $error, '(' );
+ $error = str_replace( ' src', '', $error );
+ $lines = $this->grep_content( $error, $file_content );
+ $this->add_error(
+ $key,
+ sprintf( '`%1$s` was found in the file. %2$s', $error, $check ),
+ 'info',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
35 vip-scanner/checks/MoreDeprecatedCheck.php
@@ -0,0 +1,35 @@
+<?php
+
+class MoreDeprecatedCheck extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+
+ $checks = array(
+ 'get_bloginfo\((\s|)("|\')home("|\')(\s|)\)' => 'get_bloginfo( \'url\' )',
+ 'bloginfo\((\s|)("|\')home("|\')(\s|)\)' => 'bloginfo( \'url\' )'
+ );
+
+ foreach( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach( $checks as $deprecated => $replacement ) {
+ $this->increment_check_count();
+
+ if( preg_match( '/[\s|]' . $deprecated . '/m', $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );
+ $grep = $this->grep_content( $error, $file_content );
+
+ $this->add_error(
+ $deprecated,
+ 'blocker',
+ sprintf( '`%1$s` is deprecated. Use `%2$s` instead.', $error, $replacement ),
+ $filename,
+ $grep
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
31 vip-scanner/checks/NonPrintableCheck.php
@@ -0,0 +1,31 @@
+<?php
+class NonPrintableCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ foreach ( $this->filter_files( $files, 'php' ) as $path => $content) {
+
+ $this->increment_check_count();
+
+ // 09 = tab
+ // 0A = line feed
+ // 0D = new line
+ $pattern = '/[\x00-\x08\x0B-\x0C\x0E-\x1F\x80-\xFF]/';
+
+ if ( preg_match( $pattern, $content, $matches ) ) {
+ $filename = $this->get_filename( $path );
+ $non_print = $this->preg_content( $pattern, $content );
+ $this->add_error(
+ 'non-printable',
+ 'Non-printable characters were found in the file. You may want to check this file for errors.',
+ 'info',
+ $filesname,
+ $non_print
+ );
+ }
+ }
+
+ // return the pass/fail
+ return $result;
+ }
+}
View
28 vip-scanner/checks/PHPShortTagsCheck.php
@@ -0,0 +1,28 @@
+<?php
+class PHPShortTagsCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ $this->increment_check_count();
+
+ $pattern = '/<\?(?!php|xml)/';
+
+ if ( preg_match( $pattern, $file_content ) ) {
+
+ $filename = $this->get_filename( $file_path );
+ $lines = $this->grep_content( $pattern, $file_content );
+
+ $this->add_error(
+ 'php-shorttags',
+ 'Found PHP short tags in file <strong>{$filename}</strong>.',
+ 'warning',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ return $result;
+ }
+}
View
27 vip-scanner/checks/ThemeArtisteerCheck.php
@@ -0,0 +1,27 @@
+<?php
+
+class ThemeArtisteerCheck extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+ if (
+ strpos( $php, 'art_normalize_widget_style_tokens' ) !== false
+ || strpos( $php, 'adi_normalize_widget_style_tokens' ) !== false
+ || strpos( $php, 'm_normalize_widget_style_tokens' ) !== false
+ || strpos ( $php, "bw = '<!--- BEGIN Widget --->';" ) !== false
+ || strpos ( $php, "ew = '<!-- end_widget -->';" ) !== false
+ || strpos ( $php, "end_widget' => '<!-- end_widget -->'") !== false
+ ) {
+ $this->add_error(
+ 'theme-artisteer',
+ 'This theme appears to have been auto-generated. Generated themes are not allowed in the themes directory.',
+ 'warning'
+ );
+ $result = false;
+ }
+ return $result;
+ }
+}
View
48 vip-scanner/checks/ThemeBasicChecks.php
@@ -0,0 +1,48 @@
+<?php
+
+// do some basic checks for strings
+class ThemeBasicChecks extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $php = $this->merge_files( $files, 'php' );
+
+ $checks = array(
+ 'DOCTYPE' => 'See: <a href="http://codex.wordpress.org/HTML_to_XHTML">http://codex.wordpress.org/HTML_to_XHTML</a><pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"<br />"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"?&gt;</pre>',
+ 'wp_footer\(' => 'See: <a href="http://codex.wordpress.org/Function_Reference/wp_footer">wp_footer</a><pre> &lt;?php wp_footer(); ?&gt;</pre>',
+ 'wp_head\(' => 'See: <a href="http://codex.wordpress.org/Function_Reference/wp_head">wp_head</a><pre> &lt;?php wp_head(); ?&gt;</pre>',
+ 'language_attributes' => 'See: <a href="http://codex.wordpress.org/Function_Reference/language_attributes">language_attributes</a><pre>&lt;html &lt;?php language_attributes(); ?&gt;</pre>',
+ 'charset' => 'There must be a charset defined in the Content-Type or the meta charset tag in the head.',
+ 'add_theme_support\((\s|)("|\')automatic-feed-links("|\')(\s|)\)' => 'See: <a href="http://codex.wordpress.org/Function_Reference/add_theme_support">add_theme_support</a><pre> &lt;?php add_theme_support( $feature ); ?&gt;</pre>',
+ 'register_sidebar\(' => 'See: <ahref="http://codex.wordpress.org/Function_Reference/register_sidebar">register_sidebar</a><pre> &lt;?php register_sidebar( $args ); ?&gt;</pre>',
+ 'dynamic_sidebar\(' => 'See: <a href="http://codex.wordpress.org/Function_Reference/dynamic_sidebar">dynamic_sidebar</a><pre> &lt;?php dynamic_sidebar( $index ); ?&gt;</pre>',
+ 'comments_template\(' => 'See: <a href="http://codex.wordpress.org/Template_Tags/comments_template">comments_template</a><pre> &lt;?php comments_template( $file, $separate_comments ); ?&gt;</pre>',
+ 'wp_list_comments\(' => 'See: <a href="http://codex.wordpress.org/Template_Tags/wp_list_comments">wp_list_comments</a><pre> &lt;?php wp_list_comments( $args ); ?&gt;</pre>',
+ 'comment_form\(' => 'See: <a href="http://codex.wordpress.org/Template_Tags/comment_form">comment_form</a><pre> &lt;?php comment_form(); ?&gt;</pre>',
+ 'wp_enqueue_script\((\s|)("|\')comment-reply("|\')(\s|)\)' => 'See: <a href="http://codex.wordpress.org/Migrating_Plugins_and_Themes_to_2.7/Enhanced_Comment_Display">Migrating Plugins and Themes to 2.7/Enhanced Comment Display</a><pre> &lt;?php if ( is_singular() ) wp_enqueue_script( "comment-reply" ); ?&gt;</pre>',
+ '<body.*body_class\(' => 'See: <a href="http://codex.wordpress.org/Template_Tags/body_class">body_class</a><pre> &lt;?php body_class( $class ); ?&gt;</pre>',
+ 'post_class\(' => 'See: <a href="http://codex.wordpress.org/Template_Tags/post_class">post_class</a><pre> &lt;div id="post-&lt;?php the_ID(); ?&gt;" &lt;?php post_class(); ?&gt;&gt;</pre>'
+ );
+
+ foreach ($checks as $key => $check) {
+ $this->increment_check_count();
+ if ( ! preg_match( '/' . $key . '/i', $php ) ) {
+ if ( $key === 'add_theme_support\((\s|)("|\')automatic-feed-links("|\')(\s|)\)' )
+ $key = 'add_theme_support( \'automatic-feed-links\' )';
+ if ( $key === 'wp_enqueue_script\((\s|)("|\')comment-reply("|\')(\s|)\)' )
+ $key = 'wp_enqueue_script( \'comment-reply\' )';
+ if ( $key === '<body.*body_class\(' )
+ $key = 'body_class call in body tag';
+
+ $key = rtrim( $key,'\(' );
+ $this->add_error(
+ $key,
+ sprintf( 'Could not find `%1$s`. %2$s', $key, $check ),
+ 'required'
+ );
+ $result = false;
+ }
+ }
+ return $result;
+ }
+}
View
23 vip-scanner/checks/ThemeCommentPaginationCheck.php
@@ -0,0 +1,23 @@
+<?php
+
+class ThemeCommentPaginationCheck extends BaseCheck {
+
+ function check( $files ) {
+ $result = true;
+ $this->increment_check_count();
+
+ // combine all the php files into one string to make it easier to search
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'paginate_comments_links' ) === false &&
+ ( strpos( $php, 'next_comments_link' ) === false && strpos( $php, 'previous_comments_link' ) === false ) ) {
+ $this->add_error(
+ 'comment-pagination',
+ 'The theme doesn\'t have comment pagination code in it. Use `paginate_comments_links()` or `next_comments_link()` and `previous_comments_link()` to add comment pagination.',
+ 'required'
+ );
+ $result = false;
+ }
+ return $result;
+ }
+}
View
22 vip-scanner/checks/ThemeContentWidthCheck.php
@@ -0,0 +1,22 @@
+<?php
+
+class ThemeContentWidthCheck extends BaseCheck {
+
+ function check( $files ) {
+
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, '$content_width' ) === false && !preg_match( '/add_filter\((\s|)("|\')embed_defaults/', $php ) ) {
+ $this->add_error(
+ 'theme-content-width',
+ 'No content width has been defined, e.g. `if ( ! isset( $content_width ) ) $content_width = 900;`',
+ 'required'
+ );
+ $result = false;
+ }
+ return $result;
+ }
+}
View
28 vip-scanner/checks/ThemeCustomizeCheck.php
@@ -0,0 +1,28 @@
+<?php
+
+class ThemeCustomizeCheck extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'add_custom_image_header' ) === false ) {
+ $this->add_error(
+ 'add_custom_image_header',
+ 'No reference to `add_custom_image_header` was found in the theme. It is recommended that the theme implement this functionality if using an image for the header.',
+ 'recommended'
+ );
+ }
+
+ if ( strpos( $php, 'add_custom_background' ) === false ) {
+ $this->add_error(
+ 'add_custom_background',
+ 'No reference to `add_custom_background()` was found in the theme. If the theme uses background images or solid colors for the background, then it is recommended that the theme implement this functionality.',
+ 'recommended'
+ );
+ }
+ return $result;
+ }
+}
View
19 vip-scanner/checks/ThemeEditorStyleCheck.php
@@ -0,0 +1,19 @@
+<?php
+
+class ThemeEditorStyleCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'add_editor_style' ) === false ) {
+ $this->add_error(
+ 'add_editor_style',
+ 'No reference to `add_editor_style()` was found in the theme. It is recommended that the theme implement editor styling, to make the editor content match the resulting post output in the theme, for a better user experience.',
+ 'recommended'
+ );
+ }
+ return $result;
+ }
+}
View
40 vip-scanner/checks/ThemeFilesCheck.php
@@ -0,0 +1,40 @@
+<?php
+class ThemeFilesCheck extends BaseCheck {
+
+ function check( $files ) {
+
+ $this->increment_check_count();
+
+ $filenames = array();
+
+ foreach ( $this->get_all_files( $files ) as $filename => $file_contents ) {
+ array_push( $filenames, strtolower( basename( $filename ) ) );
+ }
+
+ $must_have = array( 'index.php', 'comments.php', 'screenshot.png', 'style.css' );
+ $recommended = array( 'readme.txt' );
+
+ foreach( $must_have as $file ) {
+ if ( ! in_array( $file, $filenames ) ) {
+ $this->add_error(
+ 'missing-file',
+ sprintf( 'Could not find the file `%s` in the theme.', $file ),
+ 'warning'
+ );
+ }
+ }
+
+ foreach( $recommended as $file ) {
+ if ( ! in_array( $file, $filenames ) ) {
+ $this->add_error(
+ 'missing-file',
+ sprintf( 'Could not find the file `%s` in the theme.', $file ),
+ 'note'
+ );
+
+ $this->error[] = "<span class='tc-lead tc-recommended'>RECOMMENDED</span>: could not find the file <strong>{$file}</strong> in the theme.";
+ }
+ }
+ return $this->get_results();
+ }
+}
View
21 vip-scanner/checks/ThemeIncludeCheck.php
@@ -0,0 +1,21 @@
+<?php
+
+class ThemeIncludeCheck extends BaseCheck {
+
+ function check( $files ) {
+
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( preg_match( '/include[\s|]*\(/', $php ) != 0 || preg_match( '/require[\s|]*\(/', $php ) != 0 ) {
+ $this->add_error(
+ 'include-files',
+ 'The theme appears to use `include` or `require`. If these are being used to include separate sections of a template from independant files, then `get_template_part()` should be used instead.',
+ 'info'
+ );
+ }
+ return $result;
+ }
+}
View
22 vip-scanner/checks/ThemeNavMenuCheck.php
@@ -0,0 +1,22 @@
+<?php
+
+class ThemeNavMenuCheck extends BaseCheck {
+
+ function check( $files ) {
+
+ $result = true;
+ $this->increment_check_count();
+
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'nav_menu' ) === false ) {
+ $this->add_error(
+ 'theme-nav-menu',
+ 'No reference to `nav_menu` was found in the theme. Note that if your theme has a menu bar, it is required to use the WordPress `nav_menu` functionality for it.',
+ '' // recommended
+ );
+ }
+ return $result;
+ }
+}
View
37 vip-scanner/checks/ThemePostFormatCheck.php
@@ -0,0 +1,37 @@
+<?php
+
+class ThemePostFormatCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+ $css = $this->merge_files( $files, 'css' );
+
+ $checks = array(
+ '/add_theme_support\((\s|)("|\')post-formats("|\')/m'
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ($checks as $check) {
+ $this->increment_check_count();
+ if ( preg_match( $check, $file_content, $matches ) ) {
+ if ( ! strpos( $php, 'get_post_format' ) && ! strpos( $php, 'has_post_format' ) && ! strpos( $css, '.format' ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );//esc_html( rtrim( $matches[0], '(' ) );
+ $lines = $this->grep_content( rtrim( $matches[0], '(' ), $file_content );
+ $this->add_error(
+ $check,
+ sprintf( '`%s` was found. However `get_post_format` and/or `has_post_format` were not found, and no use of formats was detected in the CSS.', $error ),
+ 'required',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ }
+ return $result;
+ }
+}
View
23 vip-scanner/checks/ThemePostPaginationCheck.php
@@ -0,0 +1,23 @@
+<?php
+
+class ThemePostPaginationCheck extends BaseCheck {
+ function check( $files ) {
+
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'posts_nav_link' ) === false && strpos( $php, 'paginate_links' ) === false &&
+ ( strpos( $php, 'previous_posts_link' ) === false && strpos( $php, 'next_posts_link' ) === false )
+ ) {
+ $this->add_error(
+ 'theme-post-pagination',
+ 'The theme doesn\'t have post pagination code in it. Use `posts_nav_link()` or `paginate_links()` or `next_posts_link()` and `previous_posts_link()` to add post pagination.',
+ 'required'
+ );
+ $result = false;
+ }
+ return $result;
+ }
+}
View
29 vip-scanner/checks/ThemePostThumbnailCheck.php
@@ -0,0 +1,29 @@
+<?php
+
+class ThemePostThumbnailCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'the_post_thumbnail' ) === false ) {
+ $this->add_error(
+ 'the_post_thumbnail',
+ 'No reference to `the_post_thumbnail()` was found in the theme. It is recommended that the theme implement this functionality instead of using custom fields for thumbnails.',
+ 'recommended'
+ );
+ }
+
+ // TODO: This should check for full function, i.e. add_theme_support( ... )
+ if ( strpos( $php, 'post-thumbnails' ) === false ) {
+ $this->add_error(
+ 'post-thumbnails',
+ 'No reference to `post-thumbnails` was found in the theme. If the theme has thumbnail-like functionality, it should be implemented with `add_theme_support( \'post-thumbnails\' )` in the `functions.php` file.',
+ 'recommended'
+ );
+ }
+
+ return $result;
+ }
+}
View
27 vip-scanner/checks/ThemeStyleOptionalCheck.php
@@ -0,0 +1,27 @@
+<?php
+
+class ThemeStyleOptionalCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $css = $this->merge_files( $files, 'css' );
+
+ $checks = array(
+ '\.sticky' => '.sticky',
+ '\.bypostauthor' => '.bypostauthor',
+ );
+
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( ! preg_match( '/' . $key . '/mi', $css, $matches ) ) {
+ $this->add_error(
+ $key,
+ sprintf( 'The CSS is missing the `%s` class.', $check ),
+ 'recommended'
+ );
+ }
+ }
+
+ return $result;
+ }
+}
View
37 vip-scanner/checks/ThemeStyleRequiredCheck.php
@@ -0,0 +1,37 @@
+<?php
+class ThemeStyleRequiredCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $css = $this->merge_files( $files, 'css' );
+
+ $checks = array(
+ '^[ \t\/*#]*Theme Name:' => '`Theme name:` is missing from your style.css header.',
+ '^[ \t\/*#]*Theme URI:' => '`Theme URI:` is missing from your style.css header.',
+ '^[ \t\/*#]*Description:' => '`Description:` is missing from your style.css header.',
+ '^[ \t\/*#]*Author:' => '`Author:` is missing from your style.css header.',
+ '^[ \t\/*#]*Version' => '`Version:` is missing from your style.css header.',
+ '^[ \t\/*#]*License:' => '`License:` is missing from your style.css header.',
+ '^[ \t\/*#]*License URI:' => '`License URI:` is missing from your style.css header.',
+ '\.alignleft' => '`.alignleft` css class is needed in your theme css.',
+ '\.alignright' => '`.alignright` css class is needed in your theme css.',
+ '\.aligncenter' => '`.aligncenter` css class is needed in your theme css.',
+ '\.wp-caption' => '`.wp-caption` css class is needed in your theme css.',
+ '\.wp-caption-text' => '`.wp-caption-text` css class is needed in your theme css.',
+ '\.gallery-caption' => '`.gallery-caption` css class is needed in your theme css.',
+ );
+
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( ! preg_match( '/' . $key . '/mi', $css, $matches ) ) {
+ $this->add_error(
+ $key,
+ $check,
+ 'required'
+ );
+ $result = false;
+ }
+ }
+ return $result;
+ }
+}
View
25 vip-scanner/checks/ThemeStyleSuggestedCheck.php
@@ -0,0 +1,25 @@
+<?php
+class ThemeStyleSuggestedCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $css = $this->merge_files( $files, 'css' );
+
+ $checks = array(
+ '^Tags:' => 'Tags:'
+ );
+
+ foreach ($checks as $key => $check) {
+ $this->increment_check_count();
+ if ( !preg_match( '/' . $key . '/mi', $css, $matches ) ) {
+ $this->add_error(
+ $key,
+ sprintf( '`%s` is missing from your style.css header.', $check ),
+ 'recommended'
+ );
+ $result = false;
+ }
+ }
+ return $result;
+ }
+}
View
33 vip-scanner/checks/ThemeSupportCheck.php
@@ -0,0 +1,33 @@
+<?php
+
+// From the codex: The following parameters are read only, and should only be used in the context of current_theme_supports()
+class ThemeSupportCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ '/add_theme_support\((\s|)("|\')custom-headers("|\')(\s|)\)/' => 'add_custom_image_header()',
+ '/add_theme_support\((\s|)("|\')custom-background("|\')(\s|)\)/' => 'add_custom_background()',
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+ foreach ($checks as $key => $check) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file_content, $matches ) ) {
+ $filename = $this->get_filename( $file_path );
+ $error = rtrim( $matches[0], '(' );//esc_html( rtrim( $matches[0],'(' ) );
+ $lines = $this->grep_content( rtrim( $matches[0], '(' ), $file_content );
+ $this->add_error(
+ $key,
+ sprintf( '`%1$s` was found in the file. Use `%2$s` instead.', $error, $check ),
+ 'required',
+ $filename,
+ $lines
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
21 vip-scanner/checks/ThemeTagCheck.php
@@ -0,0 +1,21 @@
+<?php
+
+class ThemeTagCheck extends BaseCheck {
+ function check( $files ) {
+ $result = true;
+ $this->increment_check_count();
+
+ $php = $this->merge_files( $files, 'php' );
+
+ if ( strpos( $php, 'the_tags' ) === false && strpos( $php, 'get_the_tag_list' ) === false && strpos( $php, 'get_the_term_list' ) === false ) {
+ $this->add_error(
+ 'theme-tags',
+ 'This theme doesn\'t seem to display tags. Modify it to display tags in appropriate locations.',
+ 'required'
+ );
+ $result = false;
+ }
+
+ return $result;
+ }
+}
View
36 vip-scanner/checks/TimThumbCheck.php
@@ -0,0 +1,36 @@
+<?php
+class TimThumbCheck extends BaseCheck {
+ const TIM_THUMB_CURRENT_VERSION = 1.19;
+
+ function check( $files ) {
+ $result = true;
+
+ foreach ( $this->filter_files( $files, 'php' ) as $path => $content ) {
+ $this->increment_check_count();
+
+ if ( strpos( $content, 'cleanSource($src);') !== false ) {
+ preg_match( "/define\s\('VERSION',\s'([0-9]\.[0-9]+)'\)/", $content, $matches );
+ $version = $matches[1];
+ $filename = $this->get_filename( $path );
+
+ if ($version < self::TIM_THUMB_CURRENT_VERSION) {
+ $this->add_error(
+ 'timthumb-outdated',
+ sprintf( 'TimThumb detected in file. Version `%s` is out of date!', $version ),
+ 'warning',
+ $filename
+ );
+ $result = false;
+ } else {
+ $this->add_error(
+ 'timthumb-outdated',
+ sprintf( 'TimThumb detected in file. Version detected was `%s`.', $version ),
+ 'info',
+ $filename
+ );
+ }
+ }
+ }
+ return $result;
+ }
+}
View
32 vip-scanner/checks/TimeDateCheck.php
@@ -0,0 +1,32 @@
+<?php
+class TimeDateCheck extends BaseCheck {
+
+ function check( $files ) {
+ $result = true;
+
+ $checks = array(
+ //'/get_the_time\((\s|)["|\'][A-Za-z\s]+(\s|)["|\']\)/' => 'get_the_time( get_option( \'date_format\' ) )',
+ '/\sdate\((\s|)["|\'][A-Za-z\s]+(\s|)["|\']\)/' => 'date( get_option( \'date_format\' ) )',
+ '/[^get_]the_date\((\s|)["|\'][A-Za-z\s]+(\s|)["|\']\)/' => 'the_date( get_option( \'date_format\' ) )',
+ '/[^get_]the_time\((\s|)["|\'][A-Za-z\s]+(\s|)["|\']\)/' => 'the_time( get_option( \'date_format\' ) )'
+ );
+
+ foreach ( $this->filter_files( $files, 'php' ) as $filepath => $file ) {
+ foreach ( $checks as $key => $check ) {
+ $this->increment_check_count();
+ if ( preg_match( $key, $file, $matches ) ) {
+ $filename = $this->get_filename( $filepath );
+ $error = trim( rtrim( $matches[0], '(' ) );//trim( esc_html( rtrim( $matches[0], '(' ) ) );
+ $this->add_error(
+ $key,
+ 'At least one hard-coded date was found. Consider `get_option( \'date_format\' )` instead.',
+ 'info',
+ $filename
+ );
+ $result = false;
+ }
+ }
+ }
+ return $result;
+ }
+}
View
135 vip-scanner/checks/UndefinedFunctionCheck.php
@@ -0,0 +1,135 @@
+<?php
+class UndefinedFunctionCheck extends BaseCheck {
+ var $defined_functions = array();
+
+ function check( $files ) {
+ $result = true;
+
+ // if WP not loaded, throw error
+ if( ! function_exists( 'wp' ) ) {
+ $this->add_error( 'wp-load', sprintf( '%s requires WordPress to be loaded.', get_class( $this ) ), 'fail' );
+ return false;
+ }
+
+ $this->get_defined_functions( $files );
+
+ // Loop through all files and check that all function calls are valid
+ foreach( $this->filter_files( $files, 'php' ) as $file_path => $file_content ) {
+
+ $tokens = token_get_all( $file_content );
+
+ for ( $i = 0; $i < count( $tokens ); $i++ ) {
+ $token = $tokens[$i];
+
+ if( is_array( $token ) ) {
+ list( $token_id, $token_text, $line ) = $token;
+
+ // Figure out if it's a function call
+ if( $this->is_function_call( $token, $tokens, $i ) ) {