Making WordPress.org

Changeset 12521


Ignore:
Timestamp:
03/31/2023 03:51:19 AM (13 months ago)
Author:
dd32
Message:

Theme Directory: Parse style.css files using the same parsing functions as WP_Theme uses to avoid picking up stray Template: headers past the first 8KB of CSS.

Fixes #6049.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/theme-directory/theme-directory.php

    r12354 r12521  
    742742
    743743/**
    744  * Custom version of core's deprecated `get_theme_data()` function.
    745  *
    746  * @param string $theme_file Path to the file.
     744 * Custom version of core's deprecated `get_theme_data()` function merged with some WP_Theme changes.
     745 *
     746 * This function exists purely because we can't create a `WP_Theme` instance
     747 * from a style.css as a string. We need a very small selection of the data,
     748 * so this is better than complex workarounds.
     749 *
     750 * @param string $theme_file URL or Path to the file.
    747751 * @return array|false File headers, or false on failure.
    748752 */
    749753function wporg_themes_get_header_data( $theme_file ) {
     754
     755    // WP_Theme::$file_headers, which is private.
     756    $file_headers = array(
     757        'Name'        => 'Theme Name',
     758        'ThemeURI'    => 'Theme URI',
     759        'Description' => 'Description',
     760        'Author'      => 'Author',
     761        'AuthorURI'   => 'Author URI',
     762        'Version'     => 'Version',
     763        'Template'    => 'Template',
     764        'Status'      => 'Status',
     765        'Tags'        => 'Tags',
     766        'TextDomain'  => 'Text Domain',
     767        'DomainPath'  => 'Domain Path',
     768        'RequiresWP'  => 'Requires at least',
     769        'RequiresPHP' => 'Requires PHP',
     770        'UpdateURI'   => 'Update URI',
     771    );
     772
    750773    $themes_allowed_tags = array(
    751774        'a'       => array(
     
    764787    );
    765788
    766     $context = stream_context_create( array(
    767         'http' => array(
    768             'user_agent' => 'WordPress.org Theme Directory'
    769         )
    770     ) );
    771 
    772     $theme_data = file_get_contents( $theme_file, false, $context );
    773     if ( ! $theme_data ) {
    774         // Failure reading, or empty style.css file.
     789    /*
     790     * If it's a remote file, download it first.
     791     *
     792     * While get_file_data() can operate on a http:// url, we can't
     793     * guarantee that the server will be happy with the User Agent.
     794     */
     795    if ( str_contains( $theme_file, '://' ) ) {
     796        $request = wp_remote_get(
     797            $theme_file,
     798            [
     799                'user-agent' => 'WordPress.org Theme Directory',
     800                'stream'     => true,
     801            ]
     802        );
     803        $theme_file = $request['filename'] ?? false;
     804    }
     805
     806    if ( ! $theme_file || ! file_exists( $theme_file ) ) {
    775807        return false;
    776808    }
    777809
    778     $theme_data = str_replace( '\r', '\n', $theme_data );
    779 
    780     // Set defaults.
    781     $author_uri  = '';
    782     $template    = '';
    783     $version     = '';
    784     $status      = 'publish';
    785     $tags        = array();
    786     $author      = 'Anonymous';
    787     $name        = '';
    788     $theme_uri   = '';
    789     $description = '';
    790 
    791     if ( preg_match( '|^[ \t\/*#@]*Theme Name:(.*)$|mi', $theme_data, $m ) ) {
    792         $name = wp_strip_all_tags( trim( $m[1] ) );
    793     }
    794 
    795     if ( preg_match( '|^[ \t\/*#@]*Theme URI:(.*)$|mi', $theme_data, $m ) ) {
    796         $theme_uri = esc_url( trim( $m[1] ) );
    797     }
    798 
    799     if ( preg_match( '|^[ \t\/*#@]*Description:(.*)$|mi', $theme_data, $m ) ) {
    800         $description = wp_kses( trim( $m[1] ), $themes_allowed_tags );
    801     }
    802 
    803     if ( preg_match( '|^[ \t\/*#@]*Author:(.*)$|mi', $theme_data, $m ) ) {
    804         $author = wp_kses( trim( $m[1] ), $themes_allowed_tags );
    805     }
    806 
    807     if ( preg_match( '|^[ \t\/*#@]*Author URI:(.*)$|mi', $theme_data, $m ) ) {
    808         $author_uri = esc_url( trim( $m[1] ) );
    809     }
    810 
    811     if ( preg_match( '|^[ \t\/*#@]*Version:(.*)$|mi', $theme_data, $m ) ) {
    812         $version = wp_strip_all_tags( trim( $m[1] ) );
    813     }
    814 
    815     if ( preg_match( '|^[ \t\/*#@]*Template:(.*)$|mi', $theme_data, $m ) ) {
    816         $template = wp_strip_all_tags( trim( $m[1] ) );
    817     }
    818 
    819     if ( preg_match( '|^[ \t\/*#@]*Status:(.*)$|mi', $theme_data, $m ) ) {
    820         $status = wp_strip_all_tags( trim( $meta_key[1] ) );
    821     }
    822 
    823     if ( preg_match( '|^[ \t\/*#@]*Tags:(.*)$|mi', $theme_data, $m ) ) {
    824         $tags = array_map( 'trim', explode( ',', wp_strip_all_tags( trim( $m[1] ) ) ) );
    825     }
     810    $theme_data = get_file_data( $theme_file, $file_headers, 'theme' );
     811
     812    $name        = wp_strip_all_tags( trim( $theme_data['Name'] ) );
     813    $theme_uri   = esc_url( trim( $theme_data['ThemeURI'] ) );
     814    $description = wp_kses( trim( $theme_data['Description'] ), $themes_allowed_tags );
     815    $author      = wp_kses( trim( $theme_data['Author'] ), $themes_allowed_tags ) ?: 'Anonymous';
     816    $author_uri  = esc_url( trim( $theme_data['AuthorURI'] ) );
     817    $version     = wp_strip_all_tags( trim( $theme_data['Version'] ) );
     818    $template    = wp_strip_all_tags( trim( $theme_data['Template'] ) );
     819    $status      = wp_strip_all_tags( trim( $theme_data['Status'] ) ) ?: 'publish';
     820    $tags        = array_map( 'trim', explode( ',', wp_strip_all_tags( trim( $theme_data['Tags'] ) ) ) ) ?: [];
    826821
    827822    return array(
Note: See TracChangeset for help on using the changeset viewer.