<?php

/*  Copyright 2010 Simon Wheatley

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

/**
 * Check the plugins directory and retrieve all plugin files with plugin data.
 *
 * WordPress only supports plugin files in the base plugins directory
 * (wp-content/plugins) and in one directory above the plugins directory
 * (wp-content/plugins/my-plugin). The file it looks for has the plugin data and
 * must be found in those two locations. It is recommended that do keep your
 * plugin files in directories.
 *
 * The file with the plugin data is the file that will be included and therefore
 * needs to have the main execution for the plugin. This does not mean
 * everything must be contained in the file and it is recommended that the file
 * be split for maintainability. Keep everything in one file for extreme
 * optimization purposes.
 *
 * @since unknown
 *
 * @param string $plugin_folder Optional. Relative path to single plugin folder.
 * @return array Key is the plugin file path and the value is an array of the plugin data.
 */
function get_plugins$plugin_root ) {

    
// if ( ! $cache_plugins = wp_cache_get('plugins', 'plugins') )
    // $cache_plugins = array();
    // 
    // if ( isset($cache_plugins[ $plugin_folder ]) )
    //     return $cache_plugins[ $plugin_folder ];

    
$wp_plugins = array();
    
// $plugin_root = WP_PLUGIN_DIR;
    // if ( !empty($plugin_folder) )
    //     $plugin_root .= $plugin_folder;

    // Files in wp-content/plugins directory
    
$plugins_dir = @ opendir$plugin_root);
    
$plugin_files = array();
    if ( 
$plugins_dir ) {
        while ((
$file readdir$plugins_dir ) ) !== false ) {
            if ( 
substr($file01) == '.' )
                continue;
            if ( 
is_dir$plugin_root.'/'.$file ) ) {
                
$plugins_subdir = @ opendir$plugin_root.'/'.$file );
                if ( 
$plugins_subdir ) {
                    while ((
$subfile readdir$plugins_subdir ) ) !== false ) {
                        if ( 
substr($subfile01) == '.' )
                            continue;
                        if ( 
substr($subfile, -4) == '.php' )
                            
$plugin_files[] = "$file/$subfile";
                    }
                }
            } else {
                if ( 
substr($file, -4) == '.php' )
                    
$plugin_files[] = $file;
            }
        }
    } else {
        return 
$wp_plugins;
    }

    @
closedir$plugins_dir );
    @
closedir$plugins_subdir );

    if ( empty(
$plugin_files) )
        return 
$wp_plugins;

    foreach ( 
$plugin_files as $plugin_file ) {
        if ( !
is_readable"$plugin_root/$plugin_file) )
            continue;

        
$extracted_data get_plugin_data"$plugin_root/$plugin_file"falsefalse ); //Do not apply markup/translate as it'll be cached.
        
$plugin_data = array( $plugin_root$plugin_file ) + $extracted_data;

        if ( empty ( 
$plugin_data['Name'] ) )
            continue;

        
// $wp_plugins[plugin_basename( $plugin_file )] = $plugin_data;
        
$wp_plugins$plugin_file ] = $plugin_data;
    }

    
uasort$wp_pluginscreate_function'$a, $b''return strnatcasecmp( $a["Name"], $b["Name"] );' ));

    
// $cache_plugins[ $plugin_folder ] = $wp_plugins;
    // wp_cache_set('plugins', $cache_plugins, 'plugins');

    
return $wp_plugins;
}


/**
 * Parse the plugin contents to retrieve plugin's metadata.
 *
 * The metadata of the plugin's data searches for the following in the plugin's
 * header. All plugin data must be on its own line. For plugin description, it
 * must not have any newlines or only parts of the description will be displayed
 * and the same goes for the plugin data. The below is formatted for printing.
 *
 * <code>
 * /*
 * Plugin Name: Name of Plugin
 * Plugin URI: Link to plugin information
 * Description: Plugin Description
 * Author: Plugin author's name
 * Author URI: Link to the author's web site
 * Version: Must be set in the plugin for WordPress 2.3+
 * Text Domain: Optional. Unique identifier, should be same as the one used in
 *        plugin_text_domain()
 * Domain Path: Optional. Only useful if the translations are located in a
 *        folder above the plugin's base path. For example, if .mo files are
 *        located in the locale folder then Domain Path will be "/locale/" and
 *        must have the first slash. Defaults to the base folder the plugin is
 *        located in.
 * Network: Optional. Specify "Network: true" to require that a plugin is activated
 *        across all sites in an installation. This will prevent a plugin from being
 *        activated on a single site when Multisite is enabled.
 *  * / # Remove the space to close comment
 * </code>
 *
 * Plugin data returned array contains the following:
 *        'Name' - Name of the plugin, must be unique.
 *        'Title' - Title of the plugin and the link to the plugin's web site.
 *        'Description' - Description of what the plugin does and/or notes
 *        from the author.
 *        'Author' - The author's name
 *        'AuthorURI' - The authors web site address.
 *        'Version' - The plugin version number.
 *        'PluginURI' - Plugin web site address.
 *        'TextDomain' - Plugin's text domain for localization.
 *        'DomainPath' - Plugin's relative directory path to .mo files.
 *        'Network' - Boolean. Whether the plugin can only be activated network wide.
 *
 * Some users have issues with opening large files and manipulating the contents
 * for want is usually the first 1kiB or 2kiB. This function stops pulling in
 * the plugin contents when it has all of the required plugin data.
 *
 * The first 8kiB of the file will be pulled in and if the plugin data is not
 * within that first 8kiB, then the plugin author should correct their plugin
 * and move the plugin data headers to the top.
 *
 * The plugin file is assumed to have permissions to allow for scripts to read
 * the file. This is not checked however and the file is only opened for
 * reading.
 *
 * @link http://trac.wordpress.org/ticket/5651 Previous Optimizations.
 * @link http://trac.wordpress.org/ticket/7372 Further and better Optimizations.
 * @since 1.5.0
 *
 * @param string $plugin_file Path to the plugin file
 * @param bool $markup If the returned data should have HTML markup applied
 * @param bool $translate If the returned data should be translated
 * @return array See above for description.
 */
function get_plugin_data$plugin_file$markup true$translate true ) {

    
$default_headers = array(
        
'Name' => 'Plugin Name',
        
'PluginURI' => 'Plugin URI',
        
'Version' => 'Version',
        
'Description' => 'Description',
        
'Author' => 'Author',
        
'AuthorURI' => 'Author URI',
        
'TextDomain' => 'Text Domain',
        
'DomainPath' => 'Domain Path',
        
'Network' => 'Network',
        
// Site Wide Only is deprecated in favor of Network.
        
'_sitewide' => 'Site Wide Only',
    );

    
$plugin_data get_file_data$plugin_file$default_headers'plugin' );

    
$plugin_data['Network'] = ( 'true' == strtolower$plugin_data['Network'] ) );
    unset( 
$plugin_data['_sitewide'] );

    
//For backward compatibility by default Title is the same as Name.
    
$plugin_data['Title'] = $plugin_data['Name'];

    if ( 
$markup || $translate )
        
$plugin_data _get_plugin_data_markup_translate$plugin_file$plugin_data$markup$translate );

    return 
$plugin_data;
}

/**
 * undocumented function
 *
 * @author WordPress
 **/
function _get_plugin_data_markup_translate($plugin_file$plugin_data$markup true$translate true) {

    
//Translate fields30
    
if ( $translate && ! empty($plugin_data['TextDomain']) ) {
        if ( ! empty( 
$plugin_data['DomainPath'] ) )
            
load_plugin_textdomain($plugin_data['TextDomain'], falsedirname($plugin_file). $plugin_data['DomainPath']);
        else
            
load_plugin_textdomain($plugin_data['TextDomain'], falsedirname($plugin_file));

        foreach ( array(
'Name''PluginURI''Description''Author''AuthorURI''Version') as $field )
            
$plugin_data$field ] = translate($plugin_data$field ], $plugin_data['TextDomain']);
    }

    
//Apply Markup
    
if ( $markup ) {
        if ( ! empty(
$plugin_data['PluginURI']) && ! empty($plugin_data['Name']) )
            
$plugin_data['Title'] = '<a href="' $plugin_data['PluginURI'] . '" title="' __'Visit plugin homepage' ) . '">' $plugin_data['Name'] . '</a>';
        else
            
$plugin_data['Title'] = $plugin_data['Name'];

        if ( ! empty(
$plugin_data['AuthorURI']) && ! empty($plugin_data['Author']) )
            
$plugin_data['Author'] = '<a href="' $plugin_data['AuthorURI'] . '" title="' __'Visit author homepage' ) . '">' $plugin_data['Author'] . '</a>';

        
$plugin_data['Description'] = wptexturize$plugin_data['Description'] );
        if ( ! empty(
$plugin_data['Author']) )
            
$plugin_data['Description'] .= ' <cite>' sprintf__('By %s'), $plugin_data['Author'] ) . '.</cite>';
    }

    
$plugins_allowedtags = array('a' => array('href' => array(),'title' => array()),'abbr' => array('title' => array()),'acronym' => array('title' => array()),'code' => array(),'em' => array(),'strong' => array());

    
// Sanitize all displayed data
    // $plugin_data['Title']       = wp_kses($plugin_data['Title'], $plugins_allowedtags);
    // $plugin_data['Version']     = wp_kses($plugin_data['Version'], $plugins_allowedtags);
    // $plugin_data['Description'] = wp_kses($plugin_data['Description'], $plugins_allowedtags);
    // $plugin_data['Author']      = wp_kses($plugin_data['Author'], $plugins_allowedtags);

    
return $plugin_data;
}


/**
 * Parse the file contents to retrieve its metadata.
 *
 * Searches for metadata for a file, such as a plugin or theme.  Each piece of
 * metadata must be on its own line. For a field spanning multple lines, it
 * must not have any newlines or only parts of it will be displayed.
 *
 * Some users have issues with opening large files and manipulating the contents
 * for want is usually the first 1kiB or 2kiB. This function stops pulling in
 * the file contents when it has all of the required data.
 *
 * The first 8kiB of the file will be pulled in and if the file data is not
 * within that first 8kiB, then the author should correct their plugin file
 * and move the data headers to the top.
 *
 * The file is assumed to have permissions to allow for scripts to read
 * the file. This is not checked however and the file is only opened for
 * reading.
 *
 * @since 2.9.0
 *
 * @param string $file Path to the file
 * @param bool $markup If the returned data should have HTML markup applied
 * @param string $context If specified adds filter hook "extra_<$context>_headers"
 */
function get_file_data$file$default_headers$context '' ) {
    
// We don't need to write to the file, so just open for reading.
    
$fp fopen$file'r' );

    
// Pull only the first 8kiB of the file in.
    
$file_data fread$fp8192 );

    
// PHP will close file handle, but we are good citizens.
    
fclose$fp );

    
// if ( $context != '' ) {
    //     $extra_headers = apply_filters( "extra_$context".'_headers', array() );
    // 
    //     $extra_headers = array_flip( $extra_headers );
    //     foreach( $extra_headers as $key=>$value ) {
    //         $extra_headers[$key] = $key;
    //     }
    //     $all_headers = array_merge($extra_headers, $default_headers);
    // } else {
        
$all_headers $default_headers;
    
// }


    
foreach ( $all_headers as $field => $regex ) {
        
preg_match'/' preg_quote$regex'/' ) . ':(.*)$/mi'$file_data, ${$field});
        if ( !empty( ${
$field} ) )
            ${
$field} = _cleanup_header_comment( ${$field}[1] );
        else
            ${
$field} = '';
    }

    
$file_data compactarray_keys$all_headers ) );

    return 
$file_data;
}

/**
 * Strip close comment and close php tags from file headers used by WP
 * See http://core.trac.wordpress.org/ticket/8497
 *
 * @since 2.8.0
 *
 * @param string $str
 * @return string
 */
function _cleanup_header_comment($str) {
    return 
trim(preg_replace("/\s*(?:\*\/|\?>).*/"''$str));
}

// =================================================================================

// Get the plugins from the directory provided in the args
$dir $_SERVER'argv' ][ ];
// error_log( "Searching: $dir " );
if ( ! $dir || ! is_dir$dir ) ) {
    echo 
"[ERROR] The following is not a directory: " addslashes$dir ) . "\n";
    exit;
}
$plugins get_plugins$dir );

$tmp_file tempnamsys_get_temp_dir(), 'sw_' uniqid() );
$f fopen$tmp_file'w+' );

// error_log( "Plugins: " . print_r( $plugins, true ) );

foreach ( $plugins as $p ) {
    
// error_log( $p[ 0 ] . "  " . $p[ 1 ] );
    
fputcsv$f$p );
}

fclose$f );

echo 
file_get_contents$tmp_file );

unlink$tmp_file );

?>