Making WordPress.org

Changeset 10089


Ignore:
Timestamp:
07/22/2020 05:00:49 AM (5 years ago)
Author:
tellyworth
Message:

Plugin directory: catch known problem PHP function calls in block validator.

Some PHP calls are likely indicators of a plugin that is not compatible with the Block Directory. This will produce a warning or error if they are found in a plugin.

See #5303.

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-block-plugin-checker.php

    r10088 r10089  
    3939    protected $block_assets = array();
    4040    protected $block_scripts = array();
     41    protected $php_function_calls = array();
    4142
    4243    /**
     
    265266        $this->block_assets = $this->find_block_assets( $this->path_to_plugin );
    266267        $this->block_scripts = $this->find_block_scripts( $this->path_to_plugin );
     268
     269        $this->php_function_calls = $this->find_php_functions( $this->path_to_plugin );
    267270    }
    268271
     
    362365    public function find_asset_php_files( $base_dir ) {
    363366        return Filesystem::list_files( $base_dir, true, '!(:^|/)\w+\.asset\.php$!' );
     367    }
     368
     369    /**
     370     * Return a list of functions called in a given PHP file.
     371     * This is not perfect, and will miss some.
     372     *
     373     * @param string $file Path to a PHP file.
     374     * @return array A list of functions found, in (function, line, file) form.
     375     */
     376    public static function find_called_functions_in_file($file) {
     377        $source = file_get_contents($file);
     378        $tokens = token_get_all($source, TOKEN_PARSE);
     379
     380        $function_calls = array();
     381        $context = array();
     382
     383        foreach($tokens as $token) {
     384            if ( T_STRING === $token[0] ) {
     385                $context[] = $token;
     386            } elseif ( '(' === $token[0] ) {
     387
     388                while ( $last = array_pop( $context ) ) {
     389                    if ( T_STRING === $last[0] && function_exists( $last[1] ) ) {
     390                        $function_calls[] = array( $last[1], $last[2], $file );
     391                    }
     392                }
     393                $context[] = array();
     394            } elseif ( ';' === $token[0] || '}' === $token[0] || T_COMMENT === $token[0] ) {
     395                $context = array();
     396            } elseif ( T_WHITESPACE === $token[0] ) {
     397                $context[] = ' ';
     398            } else {
     399                $context[] = $token[0];
     400            }   
     401        }
     402
     403        return $function_calls;
     404    }
     405
     406    public function find_php_functions( $base_dir ) {
     407        $all_calls = array();
     408
     409        foreach ( Filesystem::list_files( $base_dir, true, '!\.php$!i' ) as $filename ) {
     410            $php_calls = self::find_called_functions_in_file( $filename );
     411            $all_calls += $php_calls;
     412        }
     413
     414        return $all_calls;
    364415    }
    365416
     
    789840        }
    790841    }
     842
     843    /**
     844     * Does it make PHP function calls that shouldn't be in a block plugin?
     845     */
     846    function check_php_function_calls() {
     847        $warning_functions = array(
     848            'wp_localize_script',
     849        );
     850        $error_functions = array(
     851            'header',
     852            'wp_redirect',
     853            'wp_safe_redirect',
     854        );
     855
     856        foreach ( $this->php_function_calls as $call ) {
     857            if ( in_array( $call[0], $warning_functions ) ) {
     858                $this->record_result(
     859                    __FUNCTION__,
     860                    'warning',
     861                    sprintf( __( 'Found PHP call <a href="%s">%s</a>. This may cause problems.', 'wporg-plugins' ), $this->get_browser_url( $call[2] ) . '#L' . $call[1], $call[0] . '()' ),
     862                    $call
     863                );
     864            } elseif ( in_array( $call[0], $error_functions ) ) {
     865                $this->record_result(
     866                    __FUNCTION__,
     867                    'error',
     868                    sprintf( __( 'Found PHP call <a href="%s">%s</a>. This is likely to prevent your plugin from working as expected.', 'wporg-plugins' ), $this->get_browser_url( $call[2] ) . '#L' . $call[1], $call[0] . '()' ),
     869                    $call
     870                );
     871            }
     872           
     873        }
     874
     875    }
    791876}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-block-validator.php

    r10078 r10089  
    316316            case 'check_for_single_parent':
    317317                return __( 'Block plugins should contain a single main block, which is added to the editor when the block is installed. If multiple blocks are used (ex: list items in a list block), the list items should set the `parent` property in their `block.json` file.', 'wporg-plugins' );
     318            case 'check_php_function_calls':
     319                return __( 'Block plugins should contain minimal PHP with no UI outside the editor. JavaScript should be used instead of PHP where possible.', 'wporg-plugins' );
    318320            // This is a special case, since multiple values may be collapsed.
    319321            case 'check_block_json_is_valid':
Note: See TracChangeset for help on using the changeset viewer.