/**
 * Get a list of folders to ignores.
 * @return array of paths.
 */
function local_codesniffer_get_ignores()
{
    global $CFG;
    $paths = array();
    $thirdparty = simplexml_load_file($CFG->libdir . '/thirdpartylibs.xml');
    foreach ($thirdparty->xpath('/libraries/library/location') as $lib) {
        $paths[] = preg_quote(local_codechecker_clean_path('/lib/' . $lib));
    }
    $paths[] = preg_quote(local_codechecker_clean_path('/local/codechecker' . DIRECTORY_SEPARATOR . 'pear'));
    return $paths;
}
 * @package    local_codechecker
 * @copyright  2011 The Open University
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
define('CLI_SCRIPT', true);
require dirname(__FILE__) . '/../../config.php';
require_once $CFG->libdir . '/clilib.php';
require_once $CFG->dirroot . '/local/codechecker/locallib.php';
// Get the command-line options.
list($options, $unrecognized) = cli_get_params(array('help' => false, 'interactive' => false), array('h' => 'help', 'i' => 'interactive'));
if (count($unrecognized) != 1) {
    $options['help'] = true;
} else {
    $path = clean_param(reset($unrecognized), PARAM_PATH);
}
if ($options['help']) {
    echo get_string('clihelp', 'local_codechecker'), "\n";
    die;
}
$interactive = false;
if ($options['interactive']) {
    $interactive = true;
}
raise_memory_limit(MEMORY_HUGE);
$standard = $CFG->dirroot . str_replace('/', DIRECTORY_SEPARATOR, '/local/codechecker/moodle');
$cli = new local_codechecker_codesniffer_cli();
$phpcs = new PHP_CodeSniffer(1, 0, 'utf-8', $interactive);
$phpcs->setCli($cli);
$phpcs->setIgnorePatterns(local_codesniffer_get_ignores());
$phpcs->process(local_codechecker_clean_path($CFG->dirroot . '/' . trim($path, '/')), local_codechecker_clean_path($standard));
$phpcs->reporting->printReport('full', false, $cli->getCommandLineValues(), null);
if ($path) {
    $fullpath = $CFG->dirroot . '/' . trim($path, '/');
    if (!is_file($fullpath) && !is_dir($fullpath)) {
        $fullpath = null;
    }
}
$output = $PAGE->get_renderer('local_codechecker');
echo $OUTPUT->header();
if ($path) {
    if ($fullpath) {
        $phpcs = new PHP_CodeSniffer();
        $phpcs->setCli(new local_codechecker_codesniffer_cli());
        $phpcs->setIgnorePatterns(local_codesniffer_get_ignores());
        $phpcs->process(local_codechecker_clean_path($fullpath), local_codechecker_clean_path($CFG->dirroot . '/local/codechecker/moodle'));
        $problems = $phpcs->getFilesErrors();
        local_codechecker_check_other_files(local_codechecker_clean_path($fullpath), $problems);
        ksort($problems);
        $errors = 0;
        $warnings = 0;
        foreach ($problems as $file => $info) {
            $errors += $info['numErrors'];
            $warnings += $info['numWarnings'];
        }
        if ($errors + $warnings > 0) {
            $summary = get_string('numerrorswarnings', 'local_codechecker', array('numErrors' => $errors, 'numWarnings' => $warnings));
        } else {
            $summary = '';
        }
        echo $output->report($problems, $phpcs, $summary);
    } else {
        echo $output->invald_path_message($path);
/**
 * Get a list of folders to ignores.
 *
 * @param string $extraignorelist optional comma separated list of substring matching paths to ignore.
 * @return array of paths.
 */
function local_codesniffer_get_ignores($extraignorelist = '')
{
    global $CFG;
    $files = array();
    // XML files to be processed.
    $paths = array();
    // Absolute paths to be excluded.
    $files['core'] = $CFG->libdir . DIRECTORY_SEPARATOR . '/thirdpartylibs.xml';
    // This one always exists.
    // With MDL-42148, for 2.6 and upwards, the general 'thirdpartylibs.xml' file
    // has been split so any plugin with dependencies can have its own. In order to
    // keep master compatibility with older branches we are doing some
    // conditional coding here.
    if (file_exists($CFG->dirroot . '/' . $CFG->admin . '/' . 'thirdpartylibs.php')) {
        // New behavior, distributed XML files, let's look for them.
        $plugintypes = core_component::get_plugin_types();
        foreach ($plugintypes as $type => $ignored) {
            $plugins = core_component::get_plugin_list_with_file($type, 'thirdpartylibs.xml', false);
            foreach ($plugins as $plugin => $path) {
                $files[$type . '_' . $plugin] = $path;
            }
        }
    }
    // Let's extract all the paths from the XML files.
    foreach ($files as $file) {
        $base = realpath(dirname($file));
        $thirdparty = simplexml_load_file($file);
        foreach ($thirdparty->xpath('/libraries/library/location') as $location) {
            $location = substr($base, strlen($CFG->dirroot)) . '/' . $location;
            // This was happening since ages ago, leading to incorrect excluded
            // paths like: "/lib/theme/bootstrapbase/less/bootstrap", so we try
            // reducing it. Note this does not affect 2.6 and up, where all
            // locations are relative to their xml file so this problem cannot happen.
            if (!file_exists(dirname($CFG->dirroot . DIRECTORY_SEPARATOR . $location))) {
                // Only if it starts with '/lib'.
                if (strpos($location, DIRECTORY_SEPARATOR . 'lib') === 0) {
                    $candidate = substr($location, strlen(DIRECTORY_SEPARATOR . 'lib'));
                    // Only modify the original location if the candidate exists.
                    if (file_exists(dirname($CFG->dirroot . DIRECTORY_SEPARATOR . $candidate))) {
                        $location = $candidate;
                    }
                }
            }
            // Accept only correct paths from XML files.
            if (file_exists(dirname($CFG->dirroot . DIRECTORY_SEPARATOR . $location))) {
                $paths[] = preg_quote(local_codechecker_clean_path($location));
            } else {
                debugging("Processing {$file} for exclussions, incorrect {$location} path found. Please fix it");
            }
        }
    }
    // Manually add our own pear stuff to be excluded.
    $paths[] = preg_quote(local_codechecker_clean_path('/local/codechecker' . DIRECTORY_SEPARATOR . 'pear'));
    // Changed in PHP_CodeSniffer 1.4.4 and upwards, so we apply the
    // same here: Paths go to keys and mark all them as 'absolute'.
    $finalpaths = array();
    foreach ($paths as $pattern) {
        $finalpaths[$pattern] = 'absolute';
    }
    // Let's add any substring matching path passed in $extraignorelist.
    if ($extraignorelist) {
        $extraignorearr = explode(',', $extraignorelist);
        foreach ($extraignorearr as $extraignore) {
            $extrapath = trim($extraignore);
            $finalpaths[$extrapath] = 'absolute';
        }
    }
    return $finalpaths;
}
$output = $PAGE->get_renderer('local_codechecker');
echo $OUTPUT->header();
if ($path) {
    if ($fullpath) {
        $reportfile = make_temp_directory('phpcs') . '/phpcs_' . random_string(10) . '.xml';
        $phpcs = new PHP_CodeSniffer();
        $cli = new local_codechecker_codesniffer_cli();
        $cli->setReport('local_codechecker');
        // Using own custom xml format for easier handling later.
        $cli->setReportFile($reportfile);
        // Send the report to dataroot temp.
        $phpcs->setCli($cli);
        $phpcs->setIgnorePatterns(local_codesniffer_get_ignores($exclude));
        $phpcs->process(local_codechecker_clean_path($fullpath), local_codechecker_clean_path($CFG->dirroot . '/local/codechecker/moodle'));
        // Save the xml report file to dataroot/temp.
        $phpcs->reporting->printReport('local_codechecker', false, $reportfile);
        // Load the XML file to proceed with the rest of checks.
        $xml = simplexml_load_file($reportfile);
        // Look for other problems, not handled by codesniffer.
        local_codechecker_check_other_files(local_codechecker_clean_path($fullpath), $xml);
        list($numerrors, $numwarnings) = local_codechecker_count_problems($xml);
        // Output the results report.
        echo $output->report($xml, $numerrors, $numwarnings);
        // And clean the report temp file.
        @unlink($reportfile);
    } else {
        echo $output->invald_path_message($path);
    }
}
$mform->display();
echo $OUTPUT->footer();