License updated to GPLv3

🧲 New features
Custom user role permissions
Employee edit form updated
Employee daily task list
Attendance and employee distribution charts on dashboard
Improvements to company structure and company assets module
Improved tables for displaying data in several modules
Faster data loading (specially for employee module)
Initials based profile pictures
Re-designed login page
Re-designed user profile page
Improvements to filtering
New REST endpoints for employee qualifications

🐛 Bug fixes
Fixed, issue with managers being able to create performance reviews for employees who are not their direct reports
Fixed, issues related to using full profile image instead of using smaller version of profile image
Changing third gender to other
Improvements and fixes for internal frontend data caching
This commit is contained in:
Thilina Pituwala
2020-10-31 19:02:37 +01:00
parent 86b8345505
commit b1df0037db
29343 changed files with 867614 additions and 2191082 deletions

View File

@@ -1,81 +0,0 @@
<?php
$header = <<<'EOF'
This file is part of the Comparator package.
(c) Sebastian Bergmann <sebastian@phpunit.de>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOF;
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules(
[
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => [
'align_double_arrow' => true,
'align_equals' => true
],
'blank_line_after_namespace' => true,
'blank_line_before_return' => true,
'braces' => true,
'cast_spaces' => true,
'concat_space' => ['spacing' => 'one'],
'elseif' => true,
'encoding' => true,
'full_opening_tag' => true,
'function_declaration' => true,
'header_comment' => ['header' => $header, 'separate' => 'none'],
'indentation_type' => true,
'line_ending' => true,
'lowercase_constants' => true,
'lowercase_keywords' => true,
'method_argument_space' => true,
//'native_function_invocation' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_closing_tag' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_consecutive_blank_lines' => true,
'no_leading_namespace_whitespace' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_after_function_name' => true,
'no_spaces_inside_parenthesis' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_whitespace' => true,
'no_unused_imports' => true,
'no_whitespace_in_blank_line' => true,
'phpdoc_align' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_scalar' => true,
//'phpdoc_separation' => true,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'self_accessor' => true,
'simplified_null_return' => true,
'single_blank_line_at_eof' => true,
'single_import_per_statement' => true,
'single_line_after_imports' => true,
'single_quote' => true,
'strict_param' => true,
'ternary_operator_spaces' => true,
'trim_array_spaces' => true,
'visibility_required' => true,
]
)
->setFinder(
PhpCsFixer\Finder::create()
->files()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
->exclude(__DIR__.'/tests/_fixture')
->name('*.php')
);

View File

@@ -1,6 +1,6 @@
<?php
$header = <<<'EOF'
This file is part of the exporter package.
This file is part of sebastian/comparator.
(c) Sebastian Bergmann <sebastian@phpunit.de>
@@ -18,7 +18,15 @@ return PhpCsFixer\Config::create()
'align_equals' => true
],
'blank_line_after_namespace' => true,
'blank_line_before_return' => true,
'blank_line_before_statement' => [
'statements' => [
'break',
'continue',
'return',
'throw',
'try',
],
],
'braces' => true,
'cast_spaces' => true,
'concat_space' => ['spacing' => 'one'],
@@ -32,6 +40,7 @@ return PhpCsFixer\Config::create()
'lowercase_constants' => true,
'lowercase_keywords' => true,
'method_argument_space' => true,
'native_function_invocation' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
@@ -47,6 +56,7 @@ return PhpCsFixer\Config::create()
'no_trailing_whitespace' => true,
'no_unused_imports' => true,
'no_whitespace_in_blank_line' => true,
'ordered_imports' => true,
'phpdoc_align' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
@@ -73,5 +83,6 @@ return PhpCsFixer\Config::create()
PhpCsFixer\Finder::create()
->files()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
->name('*.php')
);

View File

@@ -2,6 +2,18 @@
All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [2.1.3] - 2018-02-01
### Changed
* This component is now compatible with version 3 of `sebastian/diff`
## [2.1.2] - 2018-01-12
### Fixed
* Fix comparison of DateTimeImmutable objects
## [2.1.1] - 2017-12-22
### Fixed
@@ -15,5 +27,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* Added `SebastianBergmann\Comparator\Factory::reset()` to unregister all non-default comparators
* Added support for `phpunit/phpunit-mock-objects` version `^5.0`
[2.1.3]: https://github.com/sebastianbergmann/comparator/compare/2.1.2...2.1.3
[2.1.2]: https://github.com/sebastianbergmann/comparator/compare/2.1.1...2.1.2
[2.1.1]: https://github.com/sebastianbergmann/comparator/compare/2.1.0...2.1.1
[2.1.0]: https://github.com/sebastianbergmann/comparator/compare/2.0.2...2.1.0

View File

@@ -25,7 +25,7 @@
"prefer-stable": true,
"require": {
"php": "^7.0",
"sebastian/diff": "^2.0",
"sebastian/diff": "^2.0 || ^3.0",
"sebastian/exporter": "^3.1"
},
"require-dev": {

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -25,7 +25,7 @@ class ArrayComparator extends Comparator
*/
public function accepts($expected, $actual)
{
return is_array($expected) && is_array($actual);
return \is_array($expected) && \is_array($actual);
}
/**
@@ -43,8 +43,8 @@ class ArrayComparator extends Comparator
public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [])
{
if ($canonicalize) {
sort($expected);
sort($actual);
\sort($expected);
\sort($actual);
}
$remaining = $actual;
@@ -55,8 +55,8 @@ class ArrayComparator extends Comparator
foreach ($expected as $key => $value) {
unset($remaining[$key]);
if (!array_key_exists($key, $actual)) {
$expectedAsString .= sprintf(
if (!\array_key_exists($key, $actual)) {
$expectedAsString .= \sprintf(
" %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
@@ -71,25 +71,25 @@ class ArrayComparator extends Comparator
$comparator = $this->factory->getComparatorFor($value, $actual[$key]);
$comparator->assertEquals($value, $actual[$key], $delta, $canonicalize, $ignoreCase, $processed);
$expectedAsString .= sprintf(
$expectedAsString .= \sprintf(
" %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
);
$actualAsString .= sprintf(
$actualAsString .= \sprintf(
" %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($actual[$key])
);
} catch (ComparisonFailure $e) {
$expectedAsString .= sprintf(
$expectedAsString .= \sprintf(
" %s => %s\n",
$this->exporter->export($key),
$e->getExpectedAsString() ? $this->indent($e->getExpectedAsString()) : $this->exporter->shortenedExport($e->getExpected())
);
$actualAsString .= sprintf(
$actualAsString .= \sprintf(
" %s => %s\n",
$this->exporter->export($key),
$e->getActualAsString() ? $this->indent($e->getActualAsString()) : $this->exporter->shortenedExport($e->getActual())
@@ -100,7 +100,7 @@ class ArrayComparator extends Comparator
}
foreach ($remaining as $key => $value) {
$actualAsString .= sprintf(
$actualAsString .= \sprintf(
" %s => %s\n",
$this->exporter->export($key),
$this->exporter->shortenedExport($value)
@@ -110,7 +110,7 @@ class ArrayComparator extends Comparator
}
$expectedAsString .= ')';
$actualAsString .= ')';
$actualAsString .= ')';
if (!$equal) {
throw new ComparisonFailure(
@@ -126,6 +126,6 @@ class ArrayComparator extends Comparator
protected function indent($lines)
{
return trim(str_replace("\n", "\n ", $lines));
return \trim(\str_replace("\n", "\n ", $lines));
}
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -57,7 +57,7 @@ class DOMNodeComparator extends ObjectComparator
$expectedAsString,
$actualAsString,
false,
sprintf("Failed asserting that two DOM %s are equal.\n", $type)
\sprintf("Failed asserting that two DOM %s are equal.\n", $type)
);
}
}
@@ -82,6 +82,6 @@ class DOMNodeComparator extends ObjectComparator
$text = $node instanceof DOMDocument ? $node->saveXML() : $document->saveXML($node);
return $ignoreCase ? $text : strtolower($text);
return $ignoreCase ? $text : \strtolower($text);
}
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -45,21 +45,20 @@ class DateTimeComparator extends ObjectComparator
{
/** @var \DateTimeInterface $expected */
/** @var \DateTimeInterface $actual */
$delta = new \DateInterval(\sprintf('PT%dS', \abs($delta)));
$delta = new \DateInterval(sprintf('PT%dS', abs($delta)));
$actualClone = (clone $actual)
->setTimezone(new \DateTimeZone('UTC'));
$actualClone = clone $actual;
$actualClone->setTimezone(new \DateTimeZone('UTC'));
$expectedLower = (clone $expected)
->setTimezone(new \DateTimeZone('UTC'))
->sub($delta);
$expectedLower = clone $expected;
$expectedLower->setTimezone(new \DateTimeZone('UTC'));
$expectedLower->sub($delta);
$expectedUpper = (clone $expected)
->setTimezone(new \DateTimeZone('UTC'))
->add($delta);
$expectedUpper = clone $expected;
$expectedUpper->setTimezone(new \DateTimeZone('UTC'));
$expectedUpper->add($delta);
if ($actual < $expectedLower || $actual > $expectedUpper) {
if ($actualClone < $expectedLower || $actualClone > $expectedUpper) {
throw new ComparisonFailure(
$expected,
$actual,

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -32,7 +32,7 @@ class DoubleComparator extends NumericComparator
*/
public function accepts($expected, $actual)
{
return (is_float($expected) || is_float($actual)) && is_numeric($expected) && is_numeric($actual);
return (\is_float($expected) || \is_float($actual)) && \is_numeric($expected) && \is_numeric($actual);
}
/**

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -85,7 +85,7 @@ class Factory
*/
public function register(Comparator $comparator)
{
array_unshift($this->customComparators, $comparator);
\array_unshift($this->customComparators, $comparator);
$comparator->setFactory($this);
}
@@ -132,7 +132,7 @@ class Factory
private function registerDefaultComparator(Comparator $comparator)
{
array_unshift($this->defaultComparators, $comparator);
\array_unshift($this->defaultComparators, $comparator);
$comparator->setFactory($this);
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -27,9 +27,9 @@ class NumericComparator extends ScalarComparator
{
// all numerical values, but not if one of them is a double
// or both of them are strings
return is_numeric($expected) && is_numeric($actual) &&
!(is_float($expected) || is_float($actual)) &&
!(is_string($expected) && is_string($actual));
return \is_numeric($expected) && \is_numeric($actual) &&
!(\is_float($expected) || \is_float($actual)) &&
!(\is_string($expected) && \is_string($actual));
}
/**
@@ -45,20 +45,20 @@ class NumericComparator extends ScalarComparator
*/
public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
if (is_infinite($actual) && is_infinite($expected)) {
if (\is_infinite($actual) && \is_infinite($expected)) {
return;
}
if ((is_infinite($actual) xor is_infinite($expected)) ||
(is_nan($actual) or is_nan($expected)) ||
abs($actual - $expected) > $delta) {
if ((\is_infinite($actual) xor \is_infinite($expected)) ||
(\is_nan($actual) or \is_nan($expected)) ||
\abs($actual - $expected) > $delta) {
throw new ComparisonFailure(
$expected,
$actual,
'',
'',
false,
sprintf(
\sprintf(
'Failed asserting that %s matches expected %s.',
$this->exporter->export($actual),
$this->exporter->export($expected)

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -25,7 +25,7 @@ class ObjectComparator extends ArrayComparator
*/
public function accepts($expected, $actual)
{
return is_object($expected) && is_object($actual);
return \is_object($expected) && \is_object($actual);
}
/**
@@ -42,24 +42,24 @@ class ObjectComparator extends ArrayComparator
*/
public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [])
{
if (get_class($actual) !== get_class($expected)) {
if (\get_class($actual) !== \get_class($expected)) {
throw new ComparisonFailure(
$expected,
$actual,
$this->exporter->export($expected),
$this->exporter->export($actual),
false,
sprintf(
\sprintf(
'%s is not instance of expected class "%s".',
$this->exporter->export($actual),
get_class($expected)
\get_class($expected)
)
);
}
// don't compare twice to allow for cyclic dependencies
if (in_array([$actual, $expected], $processed, true) ||
in_array([$expected, $actual], $processed, true)) {
if (\in_array([$actual, $expected], $processed, true) ||
\in_array([$expected, $actual], $processed, true)) {
return;
}
@@ -83,8 +83,8 @@ class ObjectComparator extends ArrayComparator
$expected,
$actual,
// replace "Array" with "MyClass object"
substr_replace($e->getExpectedAsString(), get_class($expected) . ' Object', 0, 5),
substr_replace($e->getActualAsString(), get_class($actual) . ' Object', 0, 5),
\substr_replace($e->getExpectedAsString(), \get_class($expected) . ' Object', 0, 5),
\substr_replace($e->getActualAsString(), \get_class($actual) . ' Object', 0, 5),
false,
'Failed asserting that two objects are equal.'
);

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -25,7 +25,7 @@ class ResourceComparator extends Comparator
*/
public function accepts($expected, $actual)
{
return is_resource($expected) && is_resource($actual);
return \is_resource($expected) && \is_resource($actual);
}
/**

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -27,11 +27,11 @@ class ScalarComparator extends Comparator
*/
public function accepts($expected, $actual)
{
return ((is_scalar($expected) xor null === $expected) &&
(is_scalar($actual) xor null === $actual))
return ((\is_scalar($expected) xor null === $expected) &&
(\is_scalar($actual) xor null === $actual))
// allow comparison between strings and objects featuring __toString()
|| (is_string($expected) && is_object($actual) && method_exists($actual, '__toString'))
|| (is_object($expected) && method_exists($expected, '__toString') && is_string($actual));
|| (\is_string($expected) && \is_object($actual) && \method_exists($actual, '__toString'))
|| (\is_object($expected) && \method_exists($expected, '__toString') && \is_string($actual));
}
/**
@@ -52,18 +52,18 @@ class ScalarComparator extends Comparator
// always compare as strings to avoid strange behaviour
// otherwise 0 == 'Foobar'
if (is_string($expected) || is_string($actual)) {
if (\is_string($expected) || \is_string($actual)) {
$expectedToCompare = (string) $expectedToCompare;
$actualToCompare = (string) $actualToCompare;
if ($ignoreCase) {
$expectedToCompare = strtolower($expectedToCompare);
$actualToCompare = strtolower($actualToCompare);
$expectedToCompare = \strtolower($expectedToCompare);
$actualToCompare = \strtolower($actualToCompare);
}
}
if ($expectedToCompare != $actualToCompare) {
if (is_string($expected) && is_string($actual)) {
if (\is_string($expected) && \is_string($actual)) {
throw new ComparisonFailure(
$expected,
$actual,
@@ -81,7 +81,7 @@ class ScalarComparator extends Comparator
'',
'',
false,
sprintf(
\sprintf(
'Failed asserting that %s matches expected %s.',
$this->exporter->export($actual),
$this->exporter->export($expected)

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -41,7 +41,7 @@ class TypeComparator extends Comparator
*/
public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false)
{
if (gettype($expected) != gettype($actual)) {
if (\gettype($expected) != \gettype($actual)) {
throw new ComparisonFailure(
$expected,
$actual,
@@ -49,10 +49,10 @@ class TypeComparator extends Comparator
'',
'',
false,
sprintf(
\sprintf(
'%s does not match expected type "%s".',
$this->exporter->shortenedExport($actual),
gettype($expected)
\gettype($expected)
)
);
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\ArrayComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -10,12 +10,13 @@
namespace SebastianBergmann\Comparator;
use DOMNode;
use DOMDocument;
use DOMNode;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\DOMNodeComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -17,6 +17,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\DateTimeComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure
@@ -47,100 +48,101 @@ class DateTimeComparatorTest extends TestCase
public function assertEqualsSucceedsProvider()
{
return [
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:25', new DateTimeZone('America/New_York')),
10
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:14:40', new DateTimeZone('America/New_York')),
65
],
[
new DateTime('2013-03-29', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:49', new DateTimeZone('America/Chicago')),
15
],
[
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 23:00:00', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 23:01:30', new DateTimeZone('America/Chicago')),
100
],
[
new DateTime('@1364616000'),
new DateTime('2013-03-29 23:00:00', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-29T05:13:35-0500'),
new DateTime('2013-03-29T04:13:35-0600')
]
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:25', new DateTimeZone('America/New_York')),
10
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:14:40', new DateTimeZone('America/New_York')),
65
],
[
new DateTime('2013-03-29', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:49', new DateTimeZone('America/Chicago')),
15
],
[
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 23:00:00', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 23:01:30', new DateTimeZone('America/Chicago')),
100
],
[
new DateTime('@1364616000'),
new DateTime('2013-03-29 23:00:00', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-29T05:13:35-0500'),
new DateTime('2013-03-29T04:13:35-0600')
],
[
new DateTimeImmutable('2013-03-30', new DateTimeZone('America/New_York')),
new DateTimeImmutable('2013-03-29 23:01:30', new DateTimeZone('America/Chicago')),
100
],
];
}
public function assertEqualsFailsProvider()
{
return [
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/New_York')),
3500
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 05:13:35', new DateTimeZone('America/New_York')),
3500
],
[
new DateTime('2013-03-29', new DateTimeZone('America/New_York')),
new DateTime('2013-03-30', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29', new DateTimeZone('America/New_York')),
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
43200
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/Chicago')),
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/Chicago')),
3500
],
[
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
new DateTime('2013-03-30', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-29T05:13:35-0600'),
new DateTime('2013-03-29T04:13:35-0600')
],
[
new DateTime('2013-03-29T05:13:35-0600'),
new DateTime('2013-03-29T05:13:35-0500')
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 03:13:35', new DateTimeZone('America/New_York')),
3500
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 05:13:35', new DateTimeZone('America/New_York')),
3500
],
[
new DateTime('2013-03-29', new DateTimeZone('America/New_York')),
new DateTime('2013-03-30', new DateTimeZone('America/New_York'))
],
[
new DateTime('2013-03-29', new DateTimeZone('America/New_York')),
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
43200
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/Chicago')),
],
[
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/New_York')),
new DateTime('2013-03-29 04:13:35', new DateTimeZone('America/Chicago')),
3500
],
[
new DateTime('2013-03-30', new DateTimeZone('America/New_York')),
new DateTime('2013-03-30', new DateTimeZone('America/Chicago'))
],
[
new DateTime('2013-03-29T05:13:35-0600'),
new DateTime('2013-03-29T04:13:35-0600')
],
[
new DateTime('2013-03-29T05:13:35-0600'),
new DateTime('2013-03-29T05:13:35-0500')
],
];
}
@@ -150,10 +152,10 @@ class DateTimeComparatorTest extends TestCase
public function testAcceptsSucceeds()
{
$this->assertTrue(
$this->comparator->accepts(
new DateTime,
new DateTime
)
$this->comparator->accepts(
new DateTime,
new DateTime
)
);
}
@@ -164,7 +166,7 @@ class DateTimeComparatorTest extends TestCase
public function testAcceptsFails($expected, $actual)
{
$this->assertFalse(
$this->comparator->accepts($expected, $actual)
$this->comparator->accepts($expected, $actual)
);
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\DoubleComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure
@@ -34,9 +35,9 @@ class DoubleComparatorTest extends TestCase
[5.0, 0],
['5', 4.5],
[1.2e3, 7E-10],
[3, acos(8)],
[acos(8), 3],
[acos(8), acos(8)]
[3, \acos(8)],
[\acos(8), 3],
[\acos(8), \acos(8)]
];
}
@@ -78,9 +79,9 @@ class DoubleComparatorTest extends TestCase
[1.2e3, 1201],
[2.3, 2.5, 0.2],
[3, 3.05, 0.04],
[3, acos(8)],
[acos(8), 3],
[acos(8), acos(8)]
[3, \acos(8)],
[\acos(8), 3],
[\acos(8), \acos(8)]
];
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -16,6 +16,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\ExceptionComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\Factory
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure
@@ -22,7 +23,7 @@ class FactoryTest extends TestCase
{
public function instanceProvider()
{
$tmpfile = tmpfile();
$tmpfile = \tmpfile();
return [
[null, null, 'SebastianBergmann\\Comparator\\ScalarComparator'],

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -15,6 +15,7 @@ use stdClass;
/**
* @coversDefaultClass SebastianBergmann\Comparator\MockObjectComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\NumericComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -10,11 +10,12 @@
namespace SebastianBergmann\Comparator;
use stdClass;
use PHPUnit\Framework\TestCase;
use stdClass;
/**
* @coversDefaultClass SebastianBergmann\Comparator\ObjectComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\ResourceComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure
@@ -29,8 +30,8 @@ class ResourceComparatorTest extends TestCase
public function acceptsSucceedsProvider()
{
$tmpfile1 = tmpfile();
$tmpfile2 = tmpfile();
$tmpfile1 = \tmpfile();
$tmpfile2 = \tmpfile();
return [
[$tmpfile1, $tmpfile1],
@@ -41,7 +42,7 @@ class ResourceComparatorTest extends TestCase
public function acceptsFailsProvider()
{
$tmpfile1 = tmpfile();
$tmpfile1 = \tmpfile();
return [
[$tmpfile1, null],
@@ -52,8 +53,8 @@ class ResourceComparatorTest extends TestCase
public function assertEqualsSucceedsProvider()
{
$tmpfile1 = tmpfile();
$tmpfile2 = tmpfile();
$tmpfile1 = \tmpfile();
$tmpfile2 = \tmpfile();
return [
[$tmpfile1, $tmpfile1],
@@ -63,8 +64,8 @@ class ResourceComparatorTest extends TestCase
public function assertEqualsFailsProvider()
{
$tmpfile1 = tmpfile();
$tmpfile2 = tmpfile();
$tmpfile1 = \tmpfile();
$tmpfile2 = \tmpfile();
return [
[$tmpfile1, $tmpfile2],

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\ScalarComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure
@@ -54,7 +55,7 @@ class ScalarComparatorTest extends TestCase
['string', []],
[new ClassWithToString, new ClassWithToString],
[false, new ClassWithToString],
[tmpfile(), tmpfile()]
[\tmpfile(), \tmpfile()]
];
}

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -10,12 +10,13 @@
namespace SebastianBergmann\Comparator;
use PHPUnit\Framework\TestCase;
use SplObjectStorage;
use stdClass;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass SebastianBergmann\Comparator\SplObjectStorageComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
@@ -10,11 +10,12 @@
namespace SebastianBergmann\Comparator;
use stdClass;
use PHPUnit\Framework\TestCase;
use stdClass;
/**
* @coversDefaultClass SebastianBergmann\Comparator\TypeComparator
*
* @uses SebastianBergmann\Comparator\Comparator
* @uses SebastianBergmann\Comparator\Factory
* @uses SebastianBergmann\Comparator\ComparisonFailure

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -1,6 +1,6 @@
<?php
/*
* This file is part of the Comparator package.
* This file is part of sebastian/comparator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*

View File

@@ -0,0 +1 @@
patreon: s_bergmann

View File

@@ -1,4 +1,5 @@
/.idea
/composer.lock
/vendor
/.php_cs
/.php_cs.cache

View File

@@ -0,0 +1,190 @@
<?php declare(strict_types=1);
$header = <<<'EOF'
This file is part of exporter package.
(c) Sebastian Bergmann <sebastian@phpunit.de>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOF;
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules(
[
'align_multiline_comment' => true,
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => [
'operators' => [
'=' => 'align',
'=>' => 'align',
],
],
'blank_line_after_namespace' => true,
'blank_line_before_statement' => [
'statements' => [
'break',
'continue',
'declare',
'do',
'for',
'foreach',
'if',
'include',
'include_once',
'require',
'require_once',
'return',
'switch',
'throw',
'try',
'while',
'yield',
],
],
'braces' => true,
'cast_spaces' => true,
'class_attributes_separation' => ['elements' => ['const', 'method', 'property']],
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'compact_nullable_typehint' => true,
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'declare_strict_types' => true,
'dir_constant' => true,
'elseif' => true,
'encoding' => true,
'full_opening_tag' => true,
'function_declaration' => true,
'header_comment' => ['header' => $header, 'separate' => 'none'],
'indentation_type' => true,
'is_null' => true,
'line_ending' => true,
'list_syntax' => ['syntax' => 'short'],
'logical_operators' => true,
'lowercase_cast' => true,
'lowercase_constants' => true,
'lowercase_keywords' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'method_argument_space' => ['ensure_fully_multiline' => true],
'modernize_types_casting' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => true,
'native_constant_invocation' => true,
'native_function_casing' => true,
'native_function_invocation' => true,
'new_with_braces' => false,
'no_alias_functions' => true,
'no_alternative_syntax' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_blank_lines_before_namespace' => true,
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => true,
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'print'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_null_property_initialization' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_short_echo_tag' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_after_function_name' => true,
'no_spaces_inside_parenthesis' => true,
'no_superfluous_elseif' => true,
'no_superfluous_phpdoc_tags' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_unneeded_control_parentheses' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_final_method' => true,
'no_unreachable_default_argument_value' => true,
'no_unset_on_property' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'non_printable_character' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
'ordered_class_elements' => [
'order' => [
'use_trait',
'constant_public',
'constant_protected',
'constant_private',
'property_public_static',
'property_protected_static',
'property_private_static',
'property_public',
'property_protected',
'property_private',
'method_public_static',
'construct',
'destruct',
'magic',
'phpunit',
'method_public',
'method_protected',
'method_private',
'method_protected_static',
'method_private_static',
],
],
'ordered_imports' => true,
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_align' => true,
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_order' => true,
'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_separation' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => true,
'phpdoc_types_order' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'protected_to_private' => true,
'return_assignment' => true,
'return_type_declaration' => ['space_before' => 'none'],
'self_accessor' => true,
'semicolon_after_instruction' => true,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'simplified_null_return' => true,
'single_blank_line_at_eof' => true,
'single_import_per_statement' => true,
'single_line_after_imports' => true,
'single_quote' => true,
'standardize_not_equals' => true,
'ternary_to_null_coalescing' => true,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'visibility_required' => true,
//'void_return' => true,
'whitespace_after_comma_in_array' => true,
]
)
->setFinder(
PhpCsFixer\Finder::create()
->files()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
);

View File

@@ -2,12 +2,10 @@ language: php
php:
- 7.0
- 7.0snapshot
- 7.1
- 7.1snapshot
- master
sudo: false
- 7.2
- 7.3
- 7.4snapshot
before_install:
- composer self-update

View File

@@ -0,0 +1,15 @@
# ChangeLog
All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
## [3.1.2] - 2019-09-14
### Fixed
* Fixed [#29](https://github.com/sebastianbergmann/exporter/pull/29): Second parameter for `str_repeat()` must be an integer
### Removed
* Remove HHVM-specific code that is no longer needed
[3.1.2]: https://github.com/sebastianbergmann/exporter/compare/3.1.1...3.1.2

View File

@@ -1,6 +1,6 @@
Exporter
Copyright (c) 2002-2017, Sebastian Bergmann <sebastian@phpunit.de>.
Copyright (c) 2002-2019, Sebastian Bergmann <sebastian@phpunit.de>.
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -22,7 +22,6 @@ Exception Object &0000000078de0f0d000000002003a261 (
'code' => 0
'file' => '/home/sebastianbergmann/test.php'
'line' => 34
'trace' => Array &0 ()
'previous' => null
)
*/

View File

@@ -14,8 +14,6 @@
<arg value="--no-progress"/>
<arg value="--no-ansi"/>
<arg value="--no-suggest"/>
<arg value="--optimize-autoloader"/>
<arg value="--prefer-stable"/>
</exec>
</target>
</project>

View File

@@ -23,9 +23,14 @@
},
{
"name": "Bernhard Schussek",
"email": "bschussek@2bepublished.at"
"email": "bschussek@gmail.com"
}
],
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"prefer-stable": true,
"require": {
"php": "^7.0",
"sebastian/recursion-context": "^3.0"

View File

@@ -1,13 +1,12 @@
<?php
<?php declare(strict_types=1);
/*
* This file is part of the exporter package.
* This file is part of exporter package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;
use SebastianBergmann\RecursionContext\Context;
@@ -38,8 +37,7 @@ class Exporter
* - Carriage returns and newlines are normalized to \n
* - Recursion and repeated rendering is treated properly
*
* @param mixed $value
* @param int $indentation The indentation level of the 2nd+ line
* @param int $indentation The indentation level of the 2nd+ line
*
* @return string
*/
@@ -49,8 +47,8 @@ class Exporter
}
/**
* @param mixed $data
* @param Context $context
* @param array<mixed> $data
* @param Context $context
*
* @return string
*/
@@ -67,11 +65,11 @@ class Exporter
$context->add($data);
foreach ($array as $key => $value) {
if (is_array($value)) {
if (\is_array($value)) {
if ($context->contains($data[$key]) !== false) {
$result[] = '*RECURSION*';
} else {
$result[] = sprintf(
$result[] = \sprintf(
'array(%s)',
$this->shortenedRecursiveExport($data[$key], $context)
);
@@ -81,7 +79,7 @@ class Exporter
}
}
return implode(', ', $result);
return \implode(', ', $result);
}
/**
@@ -93,42 +91,40 @@ class Exporter
* Newlines are replaced by the visible string '\n'.
* Contents of arrays and objects (if any) are replaced by '...'.
*
* @param mixed $value
*
* @return string
*
* @see SebastianBergmann\Exporter\Exporter::export
*/
public function shortenedExport($value)
{
if (is_string($value)) {
$string = str_replace("\n", '', $this->export($value));
if (\is_string($value)) {
$string = \str_replace("\n", '', $this->export($value));
if (function_exists('mb_strlen')) {
if (mb_strlen($string) > 40) {
$string = mb_substr($string, 0, 30) . '...' . mb_substr($string, -7);
if (\function_exists('mb_strlen')) {
if (\mb_strlen($string) > 40) {
$string = \mb_substr($string, 0, 30) . '...' . \mb_substr($string, -7);
}
} else {
if (strlen($string) > 40) {
$string = substr($string, 0, 30) . '...' . substr($string, -7);
if (\strlen($string) > 40) {
$string = \substr($string, 0, 30) . '...' . \substr($string, -7);
}
}
return $string;
}
if (is_object($value)) {
return sprintf(
if (\is_object($value)) {
return \sprintf(
'%s Object (%s)',
get_class($value),
count($this->toArray($value)) > 0 ? '...' : ''
\get_class($value),
\count($this->toArray($value)) > 0 ? '...' : ''
);
}
if (is_array($value)) {
return sprintf(
if (\is_array($value)) {
return \sprintf(
'Array (%s)',
count($value) > 0 ? '...' : ''
\count($value) > 0 ? '...' : ''
);
}
@@ -139,24 +135,29 @@ class Exporter
* Converts an object to an array containing all of its private, protected
* and public properties.
*
* @param mixed $value
*
* @return array
*/
public function toArray($value)
{
if (!is_object($value)) {
if (!\is_object($value)) {
return (array) $value;
}
$array = [];
foreach ((array) $value as $key => $val) {
// Exception traces commonly reference hundreds to thousands of
// objects currently loaded in memory. Including them in the result
// has a severe negative performance impact.
if ("\0Error\0trace" === $key || "\0Exception\0trace" === $key) {
continue;
}
// properties are transformed to keys in the following way:
// private $property => "\0Classname\0property"
// protected $property => "\0*\0property"
// public $property => "property"
if (preg_match('/^\0.+\0(.+)$/', $key, $matches)) {
if (\preg_match('/^\0.+\0(.+)$/', (string) $key, $matches)) {
$key = $matches[1];
}
@@ -172,20 +173,8 @@ class Exporter
// above (fast) mechanism nor with reflection in Zend.
// Format the output similarly to print_r() in this case
if ($value instanceof \SplObjectStorage) {
// However, the fast method does work in HHVM, and exposes the
// internal implementation. Hide it again.
if (property_exists('\SplObjectStorage', '__storage')) {
unset($array['__storage']);
} elseif (property_exists('\SplObjectStorage', 'storage')) {
unset($array['storage']);
}
if (property_exists('\SplObjectStorage', '__key')) {
unset($array['__key']);
}
foreach ($value as $key => $val) {
$array[spl_object_hash($val)] = [
$array[\spl_object_hash($val)] = [
'obj' => $val,
'inf' => $value->getInfo(),
];
@@ -220,27 +209,29 @@ class Exporter
return 'false';
}
if (is_float($value) && floatval(intval($value)) === $value) {
if (\is_float($value) && (float) ((int) $value) === $value) {
return "$value.0";
}
if (is_resource($value)) {
return sprintf(
if (\is_resource($value)) {
return \sprintf(
'resource(%d) of type (%s)',
$value,
get_resource_type($value)
\get_resource_type($value)
);
}
if (is_string($value)) {
if (\is_string($value)) {
// Match for most non printable chars somewhat taking multibyte chars into account
if (preg_match('/[^\x09-\x0d\x1b\x20-\xff]/', $value)) {
return 'Binary String: 0x' . bin2hex($value);
if (\preg_match('/[^\x09-\x0d\x1b\x20-\xff]/', $value)) {
return 'Binary String: 0x' . \bin2hex($value);
}
return "'" .
str_replace('<lf>', "\n",
str_replace(
\str_replace(
'<lf>',
"\n",
\str_replace(
["\r\n", "\n\r", "\r", "\n"],
['\r\n<lf>', '\n\r<lf>', '\r<lf>', '\n<lf>'],
$value
@@ -249,13 +240,13 @@ class Exporter
"'";
}
$whitespace = str_repeat(' ', 4 * $indentation);
$whitespace = \str_repeat(' ', (int)(4 * $indentation));
if (!$processed) {
$processed = new Context;
}
if (is_array($value)) {
if (\is_array($value)) {
if (($key = $processed->contains($value)) !== false) {
return 'Array &' . $key;
}
@@ -264,9 +255,9 @@ class Exporter
$key = $processed->add($value);
$values = '';
if (count($array) > 0) {
if (\count($array) > 0) {
foreach ($array as $k => $v) {
$values .= sprintf(
$values .= \sprintf(
'%s %s => %s' . "\n",
$whitespace,
$this->recursiveExport($k, $indentation),
@@ -277,23 +268,23 @@ class Exporter
$values = "\n" . $values . $whitespace;
}
return sprintf('Array &%s (%s)', $key, $values);
return \sprintf('Array &%s (%s)', $key, $values);
}
if (is_object($value)) {
$class = get_class($value);
if (\is_object($value)) {
$class = \get_class($value);
if ($hash = $processed->contains($value)) {
return sprintf('%s Object &%s', $class, $hash);
return \sprintf('%s Object &%s', $class, $hash);
}
$hash = $processed->add($value);
$values = '';
$array = $this->toArray($value);
if (count($array) > 0) {
if (\count($array) > 0) {
foreach ($array as $k => $v) {
$values .= sprintf(
$values .= \sprintf(
'%s %s => %s' . "\n",
$whitespace,
$this->recursiveExport($k, $indentation),
@@ -304,9 +295,9 @@ class Exporter
$values = "\n" . $values . $whitespace;
}
return sprintf('%s Object &%s (%s)', $class, $hash, $values);
return \sprintf('%s Object &%s (%s)', $class, $hash, $values);
}
return var_export($value, true);
return \var_export($value, true);
}
}

View File

@@ -1,16 +1,16 @@
<?php
<?php declare(strict_types=1);
/*
* This file is part of the Exporter package.
* This file is part of exporter package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\Exporter;
use PHPUnit\Framework\TestCase;
use SebastianBergmann\RecursionContext\Context;
/**
* @covers SebastianBergmann\Exporter\Exporter
@@ -29,40 +29,40 @@ class ExporterTest extends TestCase
public function exportProvider()
{
$obj2 = new \stdClass;
$obj2 = new \stdClass;
$obj2->foo = 'bar';
$obj3 = (object)array(1,2,"Test\r\n",4,5,6,7,8);
$obj3 = (object) [1, 2, "Test\r\n", 4, 5, 6, 7, 8];
$obj = new \stdClass;
//@codingStandardsIgnoreStart
$obj->null = null;
//@codingStandardsIgnoreEnd
$obj->boolean = true;
$obj->integer = 1;
$obj->double = 1.2;
$obj->string = '1';
$obj->text = "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext";
$obj->object = $obj2;
$obj->boolean = true;
$obj->integer = 1;
$obj->double = 1.2;
$obj->string = '1';
$obj->text = "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext";
$obj->object = $obj2;
$obj->objectagain = $obj2;
$obj->array = array('foo' => 'bar');
$obj->self = $obj;
$obj->array = ['foo' => 'bar'];
$obj->self = $obj;
$storage = new \SplObjectStorage;
$storage->attach($obj2);
$storage->foo = $obj2;
return array(
'export null' => array(null, 'null'),
'export boolean true' => array(true, 'true'),
'export boolean false' => array(false, 'false'),
'export int 1' => array(1, '1'),
'export float 1.0' => array(1.0, '1.0'),
'export float 1.2' => array(1.2, '1.2'),
'export stream' => array(fopen('php://memory', 'r'), 'resource(%d) of type (stream)'),
'export numeric string' => array('1', "'1'"),
'export multidimentional array' => array(array(array(1,2,3), array(3,4,5)),
<<<EOF
return [
'export null' => [null, 'null'],
'export boolean true' => [true, 'true'],
'export boolean false' => [false, 'false'],
'export int 1' => [1, '1'],
'export float 1.0' => [1.0, '1.0'],
'export float 1.2' => [1.2, '1.2'],
'export stream' => [\fopen('php://memory', 'r'), 'resource(%d) of type (stream)'],
'export numeric string' => ['1', "'1'"],
'export multidimentional array' => [[[1, 2, 3], [3, 4, 5]],
<<<EOF
Array &0 (
0 => Array &1 (
0 => 1
@@ -76,10 +76,10 @@ Array &0 (
)
)
EOF
),
],
// \n\r and \r is converted to \n
'export multiline text' => array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
<<<EOF
'export multiline text' => ["this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
<<<EOF
'this\\n
is\\n
a\\n
@@ -92,10 +92,10 @@ very\\r
long\\n\\r
text'
EOF
),
'export empty stdclass' => array(new \stdClass, 'stdClass Object &%x ()'),
'export non empty stdclass' => array($obj,
<<<EOF
],
'export empty stdclass' => [new \stdClass, 'stdClass Object &%x ()'],
'export non empty stdclass' => [$obj,
<<<EOF
stdClass Object &%x (
'null' => null
'boolean' => true
@@ -123,10 +123,10 @@ text'
'self' => stdClass Object &%x
)
EOF
),
'export empty array' => array(array(), 'Array &%d ()'),
'export splObjectStorage' => array($storage,
<<<EOF
],
'export empty array' => [[], 'Array &%d ()'],
'export splObjectStorage' => [$storage,
<<<EOF
SplObjectStorage Object &%x (
'foo' => stdClass Object &%x (
'foo' => 'bar'
@@ -137,9 +137,9 @@ SplObjectStorage Object &%x (
)
)
EOF
),
'export stdClass with numeric properties' => array($obj3,
<<<EOF
],
'export stdClass with numeric properties' => [$obj3,
<<<EOF
stdClass Object &%x (
0 => 1
1 => 2
@@ -152,24 +152,50 @@ stdClass Object &%x (
7 => 8
)
EOF
),
array(
chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5),
],
[
\chr(0) . \chr(1) . \chr(2) . \chr(3) . \chr(4) . \chr(5),
'Binary String: 0x000102030405'
),
array(
implode('', array_map('chr', range(0x0e, 0x1f))),
],
[
\implode('', \array_map('chr', \range(0x0e, 0x1f))),
'Binary String: 0x0e0f101112131415161718191a1b1c1d1e1f'
),
array(
chr(0x00) . chr(0x09),
],
[
\chr(0x00) . \chr(0x09),
'Binary String: 0x0009'
),
array(
],
[
'',
"''"
),
);
],
'export Exception without trace' => [
new \Exception('The exception message', 42),
<<<EOF
Exception Object &%x (
'message' => 'The exception message'
'string' => ''
'code' => 42
'file' => '%s/tests/ExporterTest.php'
'line' => %d
'previous' => null
)
EOF
],
'export Error without trace' => [
new \Error('The exception message', 42),
<<<EOF
Error Object &%x (
'message' => 'The exception message'
'string' => ''
'code' => 42
'file' => '%s/tests/ExporterTest.php'
'line' => %d
'previous' => null
)
EOF
],
];
}
/**
@@ -185,25 +211,25 @@ EOF
public function testExport2()
{
if (PHP_VERSION === '5.3.3') {
if (\PHP_VERSION === '5.3.3') {
$this->markTestSkipped('Skipped due to "Nesting level too deep - recursive dependency?" fatal error');
}
$obj = new \stdClass;
$obj = new \stdClass;
$obj->foo = 'bar';
$array = array(
0 => 0,
'null' => null,
'boolean' => true,
'integer' => 1,
'double' => 1.2,
'string' => '1',
'text' => "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
'object' => $obj,
$array = [
0 => 0,
'null' => null,
'boolean' => true,
'integer' => 1,
'double' => 1.2,
'string' => '1',
'text' => "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
'object' => $obj,
'objectagain' => $obj,
'array' => array('foo' => 'bar'),
);
'array' => ['foo' => 'bar'],
];
$array['self'] = &$array;
@@ -269,27 +295,27 @@ EOF;
public function shortenedExportProvider()
{
$obj = new \stdClass;
$obj = new \stdClass;
$obj->foo = 'bar';
$array = array(
$array = [
'foo' => 'bar',
);
];
return array(
'shortened export null' => array(null, 'null'),
'shortened export boolean true' => array(true, 'true'),
'shortened export integer 1' => array(1, '1'),
'shortened export float 1.0' => array(1.0, '1.0'),
'shortened export float 1.2' => array(1.2, '1.2'),
'shortened export numeric string' => array('1', "'1'"),
return [
'shortened export null' => [null, 'null'],
'shortened export boolean true' => [true, 'true'],
'shortened export integer 1' => [1, '1'],
'shortened export float 1.0' => [1.0, '1.0'],
'shortened export float 1.2' => [1.2, '1.2'],
'shortened export numeric string' => ['1', "'1'"],
// \n\r and \r is converted to \n
'shortened export multilinestring' => array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", "'this\\nis\\na\\nvery\\nvery\\nvery...\\rtext'"),
'shortened export empty stdClass' => array(new \stdClass, 'stdClass Object ()'),
'shortened export not empty stdClass' => array($obj, 'stdClass Object (...)'),
'shortened export empty array' => array(array(), 'Array ()'),
'shortened export not empty array' => array($array, 'Array (...)'),
);
'shortened export multilinestring' => ["this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", "'this\\nis\\na\\nvery\\nvery\\nvery...\\rtext'"],
'shortened export empty stdClass' => [new \stdClass, 'stdClass Object ()'],
'shortened export not empty stdClass' => [$obj, 'stdClass Object (...)'],
'shortened export empty array' => [[], 'Array ()'],
'shortened export not empty array' => [$array, 'Array (...)'],
];
}
/**
@@ -308,10 +334,10 @@ EOF;
*/
public function testShortenedExportForMultibyteCharacters()
{
$oldMbLanguage = mb_language();
mb_language('Japanese');
$oldMbInternalEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
$oldMbLanguage = \mb_language();
\mb_language('Japanese');
$oldMbInternalEncoding = \mb_internal_encoding();
\mb_internal_encoding('UTF-8');
try {
$this->assertSame(
@@ -319,25 +345,25 @@ EOF;
$this->trimNewline($this->exporter->shortenedExport('いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす'))
);
} catch (\Exception $e) {
mb_internal_encoding($oldMbInternalEncoding);
mb_language($oldMbLanguage);
\mb_internal_encoding($oldMbInternalEncoding);
\mb_language($oldMbLanguage);
throw $e;
}
mb_internal_encoding($oldMbInternalEncoding);
mb_language($oldMbLanguage);
\mb_internal_encoding($oldMbInternalEncoding);
\mb_language($oldMbLanguage);
}
public function provideNonBinaryMultibyteStrings()
{
return array(
array(implode('', array_map('chr', range(0x09, 0x0d))), 9),
array(implode('', array_map('chr', range(0x20, 0x7f))), 96),
array(implode('', array_map('chr', range(0x80, 0xff))), 128),
);
return [
[\implode('', \array_map('chr', \range(0x09, 0x0d))), 9],
[\implode('', \array_map('chr', \range(0x20, 0x7f))), 96],
[\implode('', \array_map('chr', \range(0x80, 0xff))), 128],
];
}
/**
* @dataProvider provideNonBinaryMultibyteStrings
*/
@@ -351,11 +377,56 @@ EOF;
public function testNonObjectCanBeReturnedAsArray()
{
$this->assertEquals(array(true), $this->exporter->toArray(true));
$this->assertEquals([true], $this->exporter->toArray(true));
}
public function testIgnoreKeysInValue()
{
// Find out what the actual use case was with the PHP bug
$array = [];
$array["\0gcdata"] = '';
$this->assertEquals([], $this->exporter->toArray((object) $array));
}
private function trimNewline($string)
{
return preg_replace('/[ ]*\n/', "\n", $string);
return \preg_replace('/[ ]*\n/', "\n", $string);
}
/**
* @dataProvider shortenedRecursiveExportProvider
*/
public function testShortenedRecursiveExport(array $value, string $expected)
{
$this->assertEquals($expected, $this->exporter->shortenedRecursiveExport($value));
}
public function shortenedRecursiveExportProvider()
{
return [
'export null' => [[null], 'null'],
'export boolean true' => [[true], 'true'],
'export boolean false' => [[false], 'false'],
'export int 1' => [[1], '1'],
'export float 1.0' => [[1.0], '1.0'],
'export float 1.2' => [[1.2], '1.2'],
'export numeric string' => [['1'], "'1'"],
'export with numeric array key' => [[2 => 1], '1'],
'export with assoc array key' => [['foo' => 'bar'], '\'bar\''],
'export multidimentional array' => [[[1, 2, 3], [3, 4, 5]], 'array(1, 2, 3), array(3, 4, 5)'],
'export object' => [[new \stdClass], 'stdClass Object ()'],
];
}
public function testShortenedRecursiveOccurredRecursion()
{
$recursiveValue = [1];
$context = new Context();
$context->add($recursiveValue);
$value = [$recursiveValue];
$this->assertEquals('*RECURSION*', $this->exporter->shortenedRecursiveExport($value, $context));
}
}

View File

@@ -0,0 +1 @@
*.php diff=php

View File

@@ -0,0 +1,4 @@
/.idea
/composer.lock
/composer.phar
/vendor

View File

@@ -0,0 +1,33 @@
FinderFacade
Copyright (c) 2012-2016, Sebastian Bergmann <sebastian@phpunit.de>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Sebastian Bergmann nor the names of his
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,13 @@
# FinderFacade
**FinderFacade** is a convenience wrapper for Symfony's [Finder](http://symfony.com/doc/2.2/components/finder.html) component.
## Installation
To add this package as a local, per-project dependency to your project, simply add a dependency on `sebastian/finder-facade` to your project's `composer.json` file. Here is a minimal example of a `composer.json` file that just defines a dependency on FinderFacade 1.1:
{
"require": {
"sebastian/finder-facade": "~1.1"
}
}

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="finder-facade">
<target name="clean" description="Cleanup build artifacts">
<delete dir="${basedir}/vendor"/>
<delete file="${basedir}/composer.lock"/>
</target>
<target name="composer" depends="clean" description="Install dependencies with Composer">
<tstamp>
<format property="thirty.days.ago" pattern="MM/dd/yyyy hh:mm aa" offset="-30" unit="day"/>
</tstamp>
<delete>
<fileset dir="${basedir}">
<include name="composer.phar" />
<date datetime="${thirty.days.ago}" when="before"/>
</fileset>
</delete>
<get src="https://getcomposer.org/composer.phar" dest="${basedir}/composer.phar" skipexisting="true"/>
<exec executable="php">
<arg value="composer.phar"/>
<arg value="install"/>
</exec>
</target>
</project>

View File

@@ -0,0 +1,25 @@
{
"name": "sebastian/finder-facade",
"description": "FinderFacade is a convenience wrapper for Symfony's Finder component.",
"homepage": "https://github.com/sebastianbergmann/finder-facade",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/finder-facade/issues"
},
"require": {
"theseer/fdomdocument": "~1.3",
"symfony/finder": "~2.3|~3.0|~4.0"
},
"autoload": {
"classmap": [
"src/"
]
}
}

View File

@@ -0,0 +1,114 @@
<?php
/*
* This file is part of the Finder Facade package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FinderFacade;
use TheSeer\fDOM\fDOMDocument;
/**
* <code>
* <fileset>
* <include>
* <directory>/path/to/directory</directory>
* <file>/path/to/file</file>
* </include>
* <exclude>/path/to/directory</exclude>
* <name>*.php</name>
* </fileset>
* </code>
*
* @since Class available since Release 1.0.0
*/
class Configuration
{
/**
* @var string
*/
protected $basePath;
/**
* @var fDOMDocument
*/
protected $xml;
/**
* @param string $file
*/
public function __construct($file)
{
$this->basePath = dirname($file);
$this->xml = new fDOMDocument;
$this->xml->load($file);
}
/**
* @param string $xpath
*
* @return array
*/
public function parse($xpath = '')
{
$result = array(
'items' => array(),
'excludes' => array(),
'names' => array(),
'notNames' => array(),
'regularExpressionExcludes' => array()
);
foreach ($this->xml->getDOMXPath()->query($xpath . 'include/directory') as $item) {
$result['items'][] = $this->toAbsolutePath($item->nodeValue);
}
foreach ($this->xml->getDOMXPath()->query($xpath . 'include/file') as $item) {
$result['items'][] = $this->toAbsolutePath($item->nodeValue);
}
foreach ($this->xml->getDOMXPath()->query($xpath . 'exclude') as $exclude) {
$result['excludes'][] = $exclude->nodeValue;
}
foreach ($this->xml->getDOMXPath()->query($xpath . 'name') as $name) {
$result['names'][] = $name->nodeValue;
}
foreach ($this->xml->getDOMXPath()->query($xpath . 'notName') as $notName) {
$result['notNames'][] = $notName->nodeValue;
}
foreach ($this->xml->getDOMXPath()->query($xpath . 'regularExpressionExcludes') as $regularExpressionExclude) {
$result['regularExpressionExcludes'][] = $regularExpressionExclude->nodeValue;
}
return $result;
}
/**
* @param string $path
*
* @return string
*/
protected function toAbsolutePath($path)
{
// Check whether the path is already absolute.
if ($path[0] === '/' || $path[0] === '\\' || (strlen($path) > 3 && ctype_alpha($path[0]) &&
$path[1] === ':' && ($path[2] === '\\' || $path[2] === '/'))) {
return $path;
}
// Check whether a stream is used.
if (strpos($path, '://') !== false) {
return $path;
}
return $this->basePath . DIRECTORY_SEPARATOR . $path;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of the Finder Facade package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FinderFacade;
use Symfony\Component\Finder\Finder;
/**
* Convenience wrapper for Symfony's Finder component.
*
* @since Class available since Release 1.0.0
*/
class FinderFacade
{
/**
* @var array
*/
protected $items = array();
/**
* @var array
*/
protected $excludes = array();
/**
* @var array
*/
protected $names = array();
/**
* @var array
*/
protected $notNames = array();
/**
* @var array
*/
protected $regularExpressionsExcludes = array();
/**
* @param array $items
* @param array $excludes
* @param array $names
* @param array $notNames
* @param array $regularExpressionsExcludes
*/
public function __construct(array $items = array(), array $excludes = array(), array $names = array(), array $notNames = array(), $regularExpressionsExcludes = array())
{
$this->items = $items;
$this->excludes = $excludes;
$this->names = $names;
$this->notNames = $notNames;
$this->regularExpressionsExcludes = $regularExpressionsExcludes;
}
/**
* @return array
*/
public function findFiles()
{
$files = array();
$finder = new Finder;
$iterate = false;
$finder->ignoreUnreadableDirs();
foreach ($this->items as $item) {
if (!is_file($item)) {
$finder->in($item);
$iterate = true;
} else {
$files[] = realpath($item);
}
}
foreach ($this->excludes as $exclude) {
$finder->exclude($exclude);
}
foreach ($this->names as $name) {
$finder->name($name);
}
foreach ($this->notNames as $notName) {
$finder->notName($notName);
}
foreach ($this->regularExpressionsExcludes as $regularExpressionExclude) {
$finder->notPath($regularExpressionExclude);
}
if ($iterate) {
foreach ($finder as $file) {
$files[] = $file->getRealpath();
}
}
return $files;
}
/**
* @param string $file
*/
public function loadConfiguration($file)
{
$configuration = new Configuration($file);
$configuration = $configuration->parse();
$this->items = $configuration['items'];
$this->excludes = $configuration['excludes'];
$this->names = $configuration['names'];
$this->notNames = $configuration['notNames'];
$this->regularExpressionsExcludes = $configuration['regularExpressionExcludes'];
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* This file is part of the Finder Facade package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FinderFacade;
class ConfigurationTest extends \PHPUnit_Framework_TestCase
{
protected $fixtureDir;
protected function setUp()
{
$this->fixtureDir = __DIR__ . DIRECTORY_SEPARATOR . 'fixture' . DIRECTORY_SEPARATOR;
}
/**
* @covers SebastianBergmann\FinderFacade\Configuration::__construct
* @covers SebastianBergmann\FinderFacade\Configuration::parse
* @covers SebastianBergmann\FinderFacade\Configuration::toAbsolutePath
*/
public function testXmlFileCanBeParsed()
{
$configuration = new Configuration($this->fixtureDir . 'test.xml');
$this->assertEquals(
array(
'items' => array(
$this->fixtureDir . 'foo',
$this->fixtureDir . 'bar.phtml'
),
'excludes' => array('bar'),
'names' => array('*.php'),
'notNames' => array('*.fail.php'),
'regularExpressionExcludes' => array()
),
$configuration->parse()
);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Finder Facade package.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FinderFacade;
class FinderFacadeTest extends \PHPUnit_Framework_TestCase
{
protected $fixtureDir;
protected function setUp()
{
$this->fixtureDir = __DIR__ . DIRECTORY_SEPARATOR . 'fixture' . DIRECTORY_SEPARATOR;
}
/**
* @covers SebastianBergmann\FinderFacade\FinderFacade::__construct
* @covers SebastianBergmann\FinderFacade\FinderFacade::findFiles
*/
public function testFilesCanBeFoundBasedOnConstructorArguments()
{
$facade = new FinderFacade(
array($this->fixtureDir, $this->fixtureDir . 'bar.phtml'),
array('bar'),
array('*.php'),
array('*.fail.php')
);
$this->assertEquals(
array(
$this->fixtureDir . 'bar.phtml',
$this->fixtureDir . 'foo' . DIRECTORY_SEPARATOR . 'bar.php'
),
$facade->findFiles()
);
}
/**
* @covers SebastianBergmann\FinderFacade\FinderFacade::loadConfiguration
*/
public function testFilesCanBeFoundBasedOnXmlConfiguration()
{
$facade = new FinderFacade;
$facade->loadConfiguration($this->fixtureDir . 'test.xml');
$this->assertEquals(
array(
$this->fixtureDir . 'bar.phtml',
$this->fixtureDir . 'foo' . DIRECTORY_SEPARATOR . 'bar.php'
),
$facade->findFiles()
);
}
}

View File

@@ -0,0 +1,9 @@
<fileset>
<include>
<directory>foo</directory>
<file>bar.phtml</file>
</include>
<exclude>bar</exclude>
<name>*.php</name>
<notName>*.fail.php</notName>
</fileset>

View File

@@ -0,0 +1 @@
*.php diff=php

View File

@@ -0,0 +1,14 @@
build/api
build/code-browser
build/coverage
build/logs
build/pdepend
build/phar
build/phpdox
build/SebastianBergmann
build/phpcpd.bat
build/phpcpd.php
build/*.phar
build/*.tgz
cache.properties
phpunit.xml

View File

@@ -0,0 +1,29 @@
phpcpd
======
This is the list of changes for the phpcpd 1.4 release series.
phpcpd 1.4.2
------------
* Upgraded bundled Version component for PHAR distribution.
phpcpd 1.4.2
------------
* Fixed `composer.json`.
phpcpd 1.4.1
------------
* The [Version](http://github.com/sebastianbergmann/version) component is now used to manage the version number.
phpcpd 1.4.0
------------
* The `--verbose` switch now enables printing of the duplicated code lines.
* The progress bar is no longer enabled with `--verbose` but with `--progress`.
* The [Finder](http://symfony.com/doc/2.0/components/finder.html) component of the Symfony project is now used to find files.
* Fixed #4: Incorrect reporting of duplicated lines when duplication occurs near end of tokens.
* Fixed #18: Wrong result when `mbstring.func_overload` is enabled.
* PHP 5.3.3 is now required to use PHPCPD.

View File

@@ -0,0 +1,33 @@
phpcpd
Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Sebastian Bergmann nor the names of his
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,51 @@
# PHP Copy/Paste Detector (PHPCPD)
`phpcpd` is a Copy/Paste Detector (CPD) for PHP code.
## Installation
There are three supported ways of installing PHPCPD.
You can use the [PEAR Installer](http://pear.php.net/manual/en/guide.users.commandline.cli.php) or [Composer](http://getcomposer.org/) to download and install PHPUnit as well as its dependencies. You can also download a [PHP Archive (PHAR)](http://php.net/phar) of PHPUnit that has all required (as well as some optional) dependencies of PHPUnit bundled in a single file.
### PEAR Installer
The following two commands (which you may have to run as `root`) are all that is required to install PHPCPD using the PEAR Installer:
pear config-set auto_discover 1
pear install pear.phpunit.de/phpcpd
### Composer
To add PHPCPD as a local, per-project dependency to your project, simply add a dependency on `sebastian/phpcpd` to your project's `composer.json` file. Here is a minimal example of a `composer.json` file that just defines a development-time dependency on PHPCPD 1.4:
{
"require-dev": {
"sebastian/phpcpd": "1.4.*"
}
}
### PHP Archive (PHAR)
wget http://pear.phpunit.de/get/phpcpd.phar
chmod +x phpcpd.phar
## Usage Example
➜ ~ phpcpd /usr/local/src/phpunit/PHPUnit
phpcpd 1.4.1 by Sebastian Bergmann.
Found 3 exact clones with 53 duplicated lines in 5 files:
- /usr/local/src/phpunit/PHPUnit/Framework/Constraint/Or.php:136-157
/usr/local/src/phpunit/PHPUnit/Framework/Constraint/And.php:143-164
- /usr/local/src/phpunit/PHPUnit/Framework/Constraint/Or.php:136-157
/usr/local/src/phpunit/PHPUnit/Framework/Constraint/Xor.php:141-162
- /usr/local/src/phpunit/PHPUnit/Framework/Comparator/Scalar.php:121-132
/usr/local/src/phpunit/PHPUnit/Framework/Comparator/Numeric.php:102-113
0.19% duplicated lines out of 27640 total lines of code.
Time: 0 seconds, Memory: 18.25Mb

View File

@@ -0,0 +1,260 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="PHPCPD" default="build">
<property name="php" value="php"/>
<property name="phpunit" value="phpunit"/>
<target name="build"
depends="prepare,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,phpcb,phpdox"/>
<target name="build-parallel"
depends="prepare,lint,tools-parallel,phpcb"/>
<target name="tools-parallel"
description="Run tools in parallel">
<parallel threadCount="2">
<sequential>
<antcall target="pdepend"/>
<antcall target="phpmd-ci"/>
</sequential>
<antcall target="phpcpd"/>
<antcall target="phpcs-ci"/>
<antcall target="phploc"/>
</parallel>
</target>
<target name="clean" description="Cleanup build artifacts">
<delete dir="${basedir}/build/api"/>
<delete dir="${basedir}/build/code-browser"/>
<delete dir="${basedir}/build/coverage"/>
<delete dir="${basedir}/build/logs"/>
<delete dir="${basedir}/build/pdepend"/>
<delete dir="${basedir}/build/phar"/>
<delete dir="${basedir}/build/phpdox"/>
<delete dir="${basedir}/build/SebastianBergmann"/>
<delete file="${basedir}/build/ChangeLog.md"/>
<delete file="${basedir}/build/LICENSE"/>
<delete file="${basedir}/build/README.md"/>
<delete file="${basedir}/build/phpcpd.bat"/>
<delete file="${basedir}/build/phpcpd.php"/>
<delete>
<fileset dir="${basedir}/build" includes="*.phar"/>
<fileset dir="${basedir}/build" includes="*.tgz"/>
</delete>
</target>
<target name="prepare" depends="clean,phpab"
description="Prepare for build">
<mkdir dir="${basedir}/build/api"/>
<mkdir dir="${basedir}/build/code-browser"/>
<mkdir dir="${basedir}/build/coverage"/>
<mkdir dir="${basedir}/build/logs"/>
<mkdir dir="${basedir}/build/pdepend"/>
</target>
<target name="phpab" description="Generate autoloader scripts">
<exec executable="phpab">
<arg value="--output" />
<arg path="src/autoload.php" />
<arg value="--template" />
<arg path="src/autoload.php.in" />
<arg value="--indent" />
<arg value=" " />
<arg path="src" />
</exec>
</target>
<target name="lint">
<apply executable="${php}" failonerror="true">
<arg value="-l" />
<fileset dir="${basedir}/src">
<include name="**/*.php" />
<modified />
</fileset>
<fileset dir="${basedir}/tests">
<include name="**/*.php" />
<modified />
</fileset>
</apply>
</target>
<target name="phploc" description="Measure project size using PHPLOC">
<exec executable="phploc">
<arg value="--log-csv" />
<arg path="${basedir}/build/logs/phploc.csv" />
<arg path="${basedir}/src" />
</exec>
</target>
<target name="pdepend"
description="Calculate software metrics using PHP_Depend">
<exec executable="pdepend">
<arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" />
<arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" />
<arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
<arg path="${basedir}/src" />
</exec>
</target>
<target name="phpmd"
description="Perform project mess detection using PHPMD">
<exec executable="phpmd">
<arg path="${basedir}/src" />
<arg value="text" />
<arg path="${basedir}/build/phpmd.xml" />
</exec>
</target>
<target name="phpmd-ci"
description="Perform project mess detection using PHPMD">
<exec executable="phpmd">
<arg path="${basedir}/src" />
<arg value="xml" />
<arg path="${basedir}/build/phpmd.xml" />
<arg value="--reportfile" />
<arg path="${basedir}/build/logs/pmd.xml" />
</exec>
</target>
<target name="phpcs"
description="Find coding standard violations using PHP_CodeSniffer">
<exec executable="phpcs">
<arg value="--standard=${basedir}/build/PHPCS" />
<arg value="--extensions=php" />
<arg value="--ignore=Autoload.php" />
<arg path="${basedir}/src" />
</exec>
</target>
<target name="phpcs-ci"
description="Find coding standard violations using PHP_CodeSniffer">
<exec executable="phpcs" output="/dev/null">
<arg value="--report=checkstyle" />
<arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
<arg value="--standard=${basedir}/build/PHPCS" />
<arg value="--extensions=php" />
<arg value="--ignore=Autoload.php" />
<arg path="${basedir}/src" />
</exec>
</target>
<target name="phpcpd" description="Find duplicate code using PHPCPD">
<exec executable="phpcpd">
<arg value="--log-pmd" />
<arg path="${basedir}/build/logs/pmd-cpd.xml" />
<arg path="${basedir}/src" />
</exec>
</target>
<target name="phpunit" description="Run unit tests with PHPUnit">
<condition property="phpunit_cmd" value="${php} ${phpunit}" else="${phpunit}">
<not>
<equals arg1="${phpunit}" arg2="phpunit" />
</not>
</condition>
<exec executable="${phpunit_cmd}" failonerror="true">
<arg value="--configuration" />
<arg path="${basedir}/build/phpunit.xml" />
</exec>
</target>
<target name="phpcb"
description="Aggregate tool output with PHP_CodeBrowser">
<exec executable="phpcb">
<arg value="--log" />
<arg path="${basedir}/build/logs" />
<arg value="--source" />
<arg path="${basedir}/src" />
<arg value="--output" />
<arg path="${basedir}/build/code-browser" />
</exec>
</target>
<target name="phpdox"
description="Generate API documentation using phpDox">
<exec executable="phpdox" dir="${basedir}/build"/>
</target>
<target name="pear">
<mkdir dir="${basedir}/build/SebastianBergmann/PHPCPD"/>
<copy todir="${basedir}/build/SebastianBergmann/PHPCPD">
<fileset dir="${basedir}/src"/>
</copy>
<copy file="ChangeLog.md" todir="${basedir}/build"/>
<copy file="LICENSE" todir="${basedir}/build"/>
<copy file="README.md" todir="${basedir}/build"/>
<copy file="phpcpd.bat" todir="${basedir}/build"/>
<copy file="phpcpd.php" todir="${basedir}/build"/>
<exec executable="pear" dir="${basedir}/build">
<arg value="package" />
</exec>
<delete dir="${basedir}/build/SebastianBergmann"/>
<delete file="${basedir}/build/ChangeLog.md"/>
<delete file="${basedir}/build/LICENSE"/>
<delete file="${basedir}/build/README.md"/>
<delete file="${basedir}/build/phpcpd.bat"/>
<delete file="${basedir}/build/phpcpd.php"/>
</target>
<target name="phar"
description="Create PHAR archive of PHPCPD and all its dependencies"
depends="clean">
<mkdir dir="${basedir}/build/phar"/>
<exec executable="bash" outputproperty="version">
<arg value="-c" />
<arg value="${basedir}/phpcpd.php --version | awk 'BEGIN { ORS = &quot;&quot;; } {print $2}'" />
</exec>
<untar dest="${basedir}/build/phar" compression="gzip">
<fileset dir="${basedir}/build/dependencies">
<include name="**/*.tgz"/>
</fileset>
</untar>
<copy todir="${basedir}/build/phar/PHPCPD">
<fileset dir="${basedir}/src"/>
</copy>
<delete>
<fileset dir="${basedir}/build/phar">
<include name="**/autoload.php" />
<include name="**/Autoload.php" />
<include name="**/Autoload.php.in" />
<include name="**/package.sig" />
<include name="**/package.xml" />
</fileset>
</delete>
<exec executable="phpab">
<arg value="--all" />
<arg value="--phar" />
<arg value="--output" />
<arg path="${basedir}/build/phpcpd-${version}.phar" />
<arg value="--template" />
<arg path="${basedir}/build/phar-autoload.php.in" />
<arg value="--indent" />
<arg value=" " />
<arg path="${basedir}/build/phar" />
</exec>
<chmod file="${basedir}/build/phpcpd-${version}.phar" perm="ugo+rx"/>
<copy file="${basedir}/build/phpcpd-${version}.phar" tofile="${basedir}/build/phpcpd-${version}-compressed.phar"/>
<chmod file="${basedir}/build/phpcpd-${version}-compressed.phar" perm="ugo+rx"/>
<exec executable="phar">
<arg value="compress" />
<arg value="-f" />
<arg path="${basedir}/build/phpcpd-${version}-compressed.phar" />
<arg value="-c" />
<arg value="bzip2" />
</exec>
</target>
</project>

View File

@@ -0,0 +1,22 @@
<?php
class PHPCS_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff
{
public function __construct()
{
parent::__construct(true);
}
protected function getPatterns()
{
return array(
'do {EOL...} while (...);EOL',
'while (...) {EOL',
'for (...) {EOL',
'if (...) {EOL',
'foreach (...) {EOL',
'}EOLelse if (...) {EOL',
'}EOLelse {EOL',
'do {EOL',
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
class PHPCS_Sniffs_Whitespace_ConcatenationSpacingSniff implements PHP_CodeSniffer_Sniff
{
public function register()
{
return array(T_STRING_CONCAT);
}
public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE ||
$tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) {
$phpcsFile->addError(
'Concatenation operator must be surrounded by whitespace',
$stackPtr
);
}
}
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0"?>
<ruleset name="Sebastian">
<description>Sebastian Bergmann's coding standard</description>
<rule ref="Generic.CodeAnalysis.ForLoopShouldBeWhileLoop"/>
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
<rule ref="Generic.CodeAnalysis.JumbledIncrementer"/>
<rule ref="Generic.CodeAnalysis.UnconditionalIfStatement"/>
<rule ref="Generic.CodeAnalysis.UnnecessaryFinalModifier"/>
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
<rule ref="Generic.Commenting.Todo"/>
<rule ref="Generic.ControlStructures.InlineControlStructure"/>
<rule ref="Generic.Files.LineEndings"/>
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<rule ref="Generic.Formatting.NoSpaceAfterCast"/>
<rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="PEAR.Functions.ValidDefaultValue"/>
<rule ref="Generic.NamingConventions.ConstructorName"/>
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<rule ref="PEAR.NamingConventions.ValidClassName"/>
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<rule ref="Generic.PHP.NoSilencedErrors"/>
<rule ref="Generic.PHP.UpperCaseConstant"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<rule ref="Generic.WhiteSpace.ScopeIndent"/>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace"/>
</ruleset>

View File

@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<package packagerversion="1.4.10" version="2.0"
xmlns="http://pear.php.net/dtd/package-2.0"
xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd">
<name>phpcpd</name>
<channel>pear.phpunit.de</channel>
<summary>Copy/Paste Detector (CPD) for PHP code.</summary>
<description>Copy/Paste Detector (CPD) for PHP code.</description>
<lead>
<name>Sebastian Bergmann</name>
<user>sb</user>
<email>sb@sebastian-bergmann.de</email>
<active>yes</active>
</lead>
<date>2013-07-30</date>
<version>
<release>1.4.3</release>
<api>1.4.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license>The BSD 3-Clause License</license>
<notes>http://github.com/sebastianbergmann/phpcpd/tree</notes>
<contents>
<dir name="/">
<dir name="SebastianBergmann">
<dir name="PHPCPD">
<dir name="Detector">
<dir name="Strategy">
<file baseinstalldir="/" name="Abstract.php" role="php" />
<file baseinstalldir="/" name="Default.php" role="php" />
</dir>
<file baseinstalldir="/" name="Detector.php" role="php" />
</dir>
<dir name="Log">
<file baseinstalldir="/" name="AbstractXmlLogger.php" role="php" />
<file baseinstalldir="/" name="PMD.php" role="php" />
</dir>
<dir name="TextUI">
<file baseinstalldir="/" name="Command.php" role="php" />
<file baseinstalldir="/" name="ResultPrinter.php" role="php" />
</dir>
<file baseinstalldir="/" name="autoload.php" role="php" />
<file baseinstalldir="/" name="CodeClone.php" role="php" />
<file baseinstalldir="/" name="CodeCloneMap.php" role="php" />
</dir>
</dir>
<file baseinstalldir="/" name="phpcpd.php" role="script">
<tasks:replace from="/usr/bin/env php" to="php_bin" type="pear-config"/>
<tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
</file>
<file baseinstalldir="/" name="phpcpd.bat" role="script">
<tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
<tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
</file>
<file baseinstalldir="/" name="ChangeLog.md" role="doc"/>
<file baseinstalldir="/" name="LICENSE" role="doc"/>
<file baseinstalldir="/" name="README.md" role="doc"/>
</dir>
</contents>
<dependencies>
<required>
<php>
<min>5.3.3</min>
</php>
<pearinstaller>
<min>1.9.4</min>
</pearinstaller>
<package>
<name>ConsoleTools</name>
<channel>components.ez.no</channel>
<min>1.6</min>
</package>
<package>
<name>FinderFacade</name>
<channel>pear.phpunit.de</channel>
<min>1.0.4</min>
</package>
<package>
<name>PHP_Timer</name>
<channel>pear.phpunit.de</channel>
<min>1.0.4</min>
<max>1.0.99</max>
</package>
<package>
<name>Version</name>
<channel>pear.phpunit.de</channel>
<min>1.0.0</min>
</package>
<extension>
<name>tokenizer</name>
</extension>
</required>
</dependencies>
<phprelease>
<installconditions>
<os>
<name>windows</name>
</os>
</installconditions>
<filelist>
<install as="phpcpd" name="phpcpd.php" />
<install as="phpcpd.bat" name="phpcpd.bat" />
</filelist>
</phprelease>
<phprelease>
<filelist>
<install as="phpcpd" name="phpcpd.php" />
<ignore name="phpcpd.bat" />
</filelist>
</phprelease>
</package>

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env php
<?php
spl_autoload_register(
function ($class)
{
static $classes = NULL;
if ($classes === NULL) {
$classes = array(
___CLASSLIST___
);
}
$class = strtolower($class);
if (isset($classes[$class])) {
require 'phar://___PHAR___' . $classes[$class];
}
}
);
$textui = new SebastianBergmann\PHPCPD\TextUI\Command;
$textui->main();
__HALT_COMPILER();

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<phpdox xmlns="http://phpdox.de/config">
<project name="PHPCPD" source="../src" workdir="phpdox">
<collector publiconly="false">
<include mask="*.php" />
<exclude mask="*autoload.php" />
</collector>
<generator output=".">
<build engine="html" enabled="true" output="api"/>
</generator>
</project>
</phpdox>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<ruleset name="Sebastian"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>Sebastian Bergmann's ruleset</description>
<rule ref="rulesets/codesize.xml/CyclomaticComplexity" />
<rule ref="rulesets/codesize.xml/NPathComplexity" />
<rule ref="rulesets/codesize.xml/ExcessiveClassComplexity" />
<rule ref="rulesets/codesize.xml/ExcessiveClassLength" />
<rule ref="rulesets/codesize.xml/ExcessiveMethodLength" />
<rule ref="rulesets/codesize.xml/ExcessiveParameterList" />
<rule ref="rulesets/design.xml/EvalExpression" />
<rule ref="rulesets/design.xml/ExitExpression" />
<rule ref="rulesets/design.xml/GotoStatement" />
<rule ref="rulesets/naming.xml/ConstructorWithNameAsEnclosingClass" />
<rule ref="rulesets/unusedcode.xml/UnusedFormalParameter" />
<rule ref="rulesets/unusedcode.xml/UnusedLocalVariable" />
<rule ref="rulesets/unusedcode.xml/UnusedPrivateField" />
<rule ref="rulesets/unusedcode.xml/UnusedPrivateMethod" />
</ruleset>

View File

@@ -0,0 +1,35 @@
{
"name": "sebastian/phpcpd",
"description": "Copy/Paste Detector (CPD) for PHP code.",
"homepage": "https://github.com/sebastianbergmann/phpcpd",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpcpd/issues"
},
"require": {
"php": ">=5.3.3",
"zetacomponents/base": ">=1.8",
"zetacomponents/console-tools": ">=1.6",
"sebastian/finder-facade": "~1.1",
"phpunit/php-timer": ">=1.0.4,<1.1.0",
"symfony/finder": ">=2.1.2",
"theseer/fdomdocument": "~1.4",
"sebastian/version": ">=1.0.0"
},
"minimum-stability": "dev",
"autoload": {
"classmap": [
"src/"
]
},
"bin": [
"composer/bin/phpcpd"
]
}

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env php
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2012, Sebastian Bergmann <sb@sebastian-bergmann.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sb@sebastian-bergmann.de>
* @copyright 2009-2012 Sebastian Bergmann <sb@sebastian-bergmann.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
$files = array(
__DIR__ . '/../../vendor/autoload.php',
__DIR__ . '/../../../../autoload.php'
);
$found = FALSE;
foreach ($files as $file) {
if (file_exists($file)) {
require $file;
$found = TRUE;
break;
}
}
if (!$found) {
die(
'You need to set up the project dependencies using the following commands:' . PHP_EOL .
'curl -s http://getcomposer.org/installer | php' . PHP_EOL .
'php composer.phar install' . PHP_EOL
);
}
$textui = new SebastianBergmann\PHPCPD\TextUI\Command;
$textui->main();

View File

@@ -0,0 +1,38 @@
@echo off
REM phpcpd
REM
REM Copyright (c) 2009-2010, Sebastian Bergmann <sb@sebastian-bergmann.de>.
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions
REM are met:
REM
REM * Redistributions of source code must retain the above copyright
REM notice, this list of conditions and the following disclaimer.
REM
REM * Redistributions in binary form must reproduce the above copyright
REM notice, this list of conditions and the following disclaimer in
REM the documentation and/or other materials provided with the
REM distribution.
REM
REM * Neither the name of Sebastian Bergmann nor the names of his
REM contributors may be used to endorse or promote products derived
REM from this software without specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
REM FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
REM COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
REM INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
REM BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
REM ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
REM POSSIBILITY OF SUCH DAMAGE.
REM
set PHPBIN=@php_bin@
"@php_bin@" "@bin_dir@\phpcpd" %*

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env php
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
// @see https://github.com/sebastianbergmann/phpcpd/issues/18
ini_set('mbstring.func_overload', 0);
ini_set('mbstring.internal_encoding', NULL);
if (strpos('@php_bin@', '@php_bin') === 0) {
require __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'autoload.php';
} else {
require 'SebastianBergmann/PHPCPD/autoload.php';
}
$textui = new SebastianBergmann\PHPCPD\TextUI\Command;
$textui->main();

View File

@@ -0,0 +1,153 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.1.0
*/
namespace SebastianBergmann\PHPCPD
{
/**
* Represents an exact code clone.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.1.0
*/
class CodeClone
{
/**
* @var string Name of the first file
*/
public $aFile;
/**
* @var integer Start line in the first file
*/
public $aStartLine;
/**
* @var string Name of the second file
*/
public $bFile;
/**
* @var integer Start line in the second file
*/
public $bStartLine;
/**
* @var integer Size of the clone (lines)
*/
public $size;
/**
* @var integer Size of the clone (tokens)
*/
public $tokens;
/**
* @var Lines of the clone
*/
protected $lines = '';
/**
* Constructor.
*
* @param string $aFile Name of the first file
* @param integer $aStartLine Start line in the first file
* @param string $bFile Name of the second file
* @param integer $bStartLine Start line in the second file
* @param integer $size Size of the clone (lines)
* @param integer $tokens Size of the clone (tokens)
*/
public function __construct($aFile, $aStartLine, $bFile, $bStartLine, $size, $tokens)
{
$this->aFile = $aFile;
$this->aStartLine = $aStartLine;
$this->bFile = $bFile;
$this->bStartLine = $bStartLine;
$this->size = $size;
$this->tokens = $tokens;
}
/**
* Returns the lines of the clone.
*
* @param string $prefix
* @return string The lines of the clone
*/
public function getLines($prefix = '')
{
if (empty($this->lines)) {
$lines = array_slice(
file($this->aFile), $this->aStartLine - 1, $this->size
);
$indent = array();
foreach ($lines as &$line) {
$line = rtrim($line, " \t\0\x0B");
$line = str_replace("\t", " ", $line);
$_indent = strlen($line) - strlen(ltrim($line));
if ($_indent > 1) {
$indent[] = $_indent;
}
}
$indent = empty($indent) ? 0 : min($indent);
if ($indent > 0) {
foreach ($lines as &$line) {
if (strlen($line > 1)) {
$line = $prefix . substr($line, $indent);
}
}
}
$this->lines = join('', $lines);
}
return $this->lines;
}
}
}

View File

@@ -0,0 +1,217 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.1.0
*/
namespace SebastianBergmann\PHPCPD
{
use SebastianBergmann\PHPCPD\CodeClone;
/**
* A map of exact clones.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.1.0
*/
class CodeCloneMap implements \Countable, \Iterator
{
/**
* @var Clone[] The clones in the clone map
*/
protected $clones = array();
/**
* @var Clone[] The clones in the clone map, stored by file
*/
protected $clonesByFile = array();
/**
* @var integer Current position while iterating the clone map
*/
protected $position = 0;
/**
* @var integer Number of duplicate lines in the clone map
*/
protected $numDuplicateLines = 0;
/**
* @var integer Number of lines analyzed
*/
protected $numLines = 0;
/**
* Adds a clone to the map.
*
* @param Clone $clone
*/
public function addClone(CodeClone $clone)
{
$this->clones[] = $clone;
$this->numDuplicateLines += $clone->size;
if (isset($this->clonesByFile[$clone->aFile])) {
$this->clonesByFile[$clone->aFile][] = $clone;
} else {
$this->clonesByFile[$clone->aFile] = array($clone);
}
if (isset($this->clonesByFile[$clone->bFile])) {
$this->clonesByFile[$clone->bFile][] = $clone;
} else {
$this->clonesByFile[$clone->bFile] = array($clone);
}
}
/**
* Returns the clones stored in this map.
*
* @return Clone[]
*/
public function getClones()
{
return $this->clones;
}
/**
* Returns the files the clones stored in this map occur in.
*
* @return string[]
*/
public function getFilesWithClones()
{
return array_keys($this->clonesByFile);
}
/**
* Returns the percentage of duplicated code lines in the project.
*
* @return string
*/
public function getPercentage()
{
if ($this->numLines > 0) {
$percent = ($this->numDuplicateLines / $this->numLines) * 100;
} else {
$percent = 100;
}
return sprintf('%01.2F%%', $percent);
}
/**
* Returns the number of lines analyzed.
*
* @return integer
*/
public function getNumLines()
{
return $this->numLines;
}
/**
* Sets the number of physical source code lines in the project.
*
* @param integer $numLines
*/
public function setNumLines($numLines)
{
$this->numLines = $numLines;
}
/**
* Returns the number of clones stored in this map.
*/
public function count()
{
return count($this->clones);
}
/**
* Rewinds the Iterator to the first element.
*/
public function rewind()
{
$this->position = 0;
}
/**
* Checks if there is a current element after calls to rewind() or next().
*
* @return boolean
*/
public function valid()
{
return $this->position < count($this->clones);
}
/**
* Returns the key of the current element.
*
* @return integer
*/
public function key()
{
return $this->position;
}
/**
* Returns the current element.
*
* @return Clone
*/
public function current()
{
return $this->clones[$this->position];
}
/**
* Moves forward to next element.
*/
public function next()
{
$this->position++;
}
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
namespace SebastianBergmann\PHPCPD\Detector
{
use SebastianBergmann\PHPCPD\Detector\Strategy\AbstractStrategy;
use SebastianBergmann\PHPCPD\CodeCloneMap;
/**
* PHPCPD code analyser.
*
* @author Johann-Peter Hartmann <johann-peter.hartmann@mayflower.de>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.0.0
*/
class Detector
{
/**
* @var Strategy
*/
protected $strategy;
/**
* @var ezcConsoleOutput
*/
protected $output;
/**
* Constructor.
*
* @param AbstractStrategy $strategy
* @param ezcConsoleOutput $output
* @since Method available since Release 1.3.0
*/
public function __construct(AbstractStrategy $strategy, \ezcConsoleOutput $output = NULL)
{
$this->strategy = $strategy;
$this->output = $output;
}
/**
* Copy & Paste Detection (CPD).
*
* @param Iterator|array $files List of files to process
* @param integer $minLines Minimum number of identical lines
* @param integer $minTokens Minimum number of identical tokens
* @return CodeCloneMap Map of exact clones found in the list of files
*/
public function copyPasteDetection($files, $minLines = 5, $minTokens = 70)
{
$result = new CodeCloneMap;
if ($this->output !== NULL) {
$bar = new \ezcConsoleProgressbar($this->output, count($files));
print "Processing files\n";
}
foreach ($files as $file) {
$this->strategy->processFile(
$file, $minLines, $minTokens, $result
);
if ($this->output !== NULL) {
$bar->advance();
}
}
if ($this->output !== NULL) {
print "\n\n";
}
return $result;
}
}
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.4.0
*/
namespace SebastianBergmann\PHPCPD\Detector\Strategy
{
use SebastianBergmann\PHPCPD\CodeCloneMap;
/**
* Abstract base class for strategies to detect code clones.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.4.0
*/
abstract class AbstractStrategy
{
/**
* @var integer[] List of tokens to ignore
*/
protected $tokensIgnoreList = array(
T_INLINE_HTML => TRUE,
T_COMMENT => TRUE,
T_DOC_COMMENT => TRUE,
T_OPEN_TAG => TRUE,
T_OPEN_TAG_WITH_ECHO => TRUE,
T_CLOSE_TAG => TRUE,
T_WHITESPACE => TRUE
);
/**
* @var string[]
*/
protected $hashes = array();
/**
* Copy & Paste Detection (CPD).
*
* @param string $file
* @param integer $minLines
* @param integer $minTokens
* @param CodeCloneMap $result
*/
abstract public function processFile($file, $minLines, $minTokens, CodeCloneMap $result);
}
}

View File

@@ -0,0 +1,185 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.4.0
*/
namespace SebastianBergmann\PHPCPD\Detector\Strategy
{
use SebastianBergmann\PHPCPD\CodeClone;
use SebastianBergmann\PHPCPD\CodeCloneMap;
/**
* Default strategy for detecting code clones.
*
* @author Johann-Peter Hartmann <johann-peter.hartmann@mayflower.de>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.4.0
*/
class DefaultStrategy extends AbstractStrategy
{
/**
* Copy & Paste Detection (CPD).
*
* @param string $file
* @param integer $minLines
* @param integer $minTokens
* @param CodeCloneMap $result
* @author Johann-Peter Hartmann <johann-peter.hartmann@mayflower.de>
*/
public function processFile($file, $minLines, $minTokens, CodeCloneMap $result)
{
$buffer = file_get_contents($file);
$currentTokenPositions = array();
$currentSignature = '';
$tokens = token_get_all($buffer);
$tokenNr = 0;
$line = 1;
$result->setNumLines(
$result->getNumLines() + substr_count($buffer, "\n")
);
unset($buffer);
foreach (array_keys($tokens) as $key) {
$token = $tokens[$key];
if (is_string($token)) {
$line += substr_count($token, "\n");
} else {
if (!isset($this->tokensIgnoreList[$token[0]])) {
$currentTokenPositions[$tokenNr++] = $line;
$currentSignature .= chr(
$token[0] & 255) . pack('N*', crc32($token[1])
);
}
$line += substr_count($token[1], "\n");
}
}
$count = count($currentTokenPositions);
$firstLine = 0;
$found = FALSE;
$tokenNr = 0;
if ($count > 0) {
do {
$line = $currentTokenPositions[$tokenNr];
$hash = substr(
md5(
substr(
$currentSignature, $tokenNr * 5,
$minTokens * 5
),
TRUE
),
0,
8
);
if (isset($this->hashes[$hash])) {
$found = TRUE;
if ($firstLine === 0) {
$firstLine = $line;
$firstHash = $hash;
$firstToken = $tokenNr;
}
} else {
if ($found) {
$fileA = $this->hashes[$firstHash][0];
$firstLineA = $this->hashes[$firstHash][1];
if ($line + 1 - $firstLine > $minLines &&
($fileA != $file ||
$firstLineA != $firstLine)) {
$result->addClone(
new CodeClone(
$fileA,
$firstLineA,
$file,
$firstLine,
$line + 1 - $firstLine,
$tokenNr + 1 - $firstToken
)
);
}
$found = FALSE;
$firstLine = 0;
}
$this->hashes[$hash] = array($file, $line);
}
$tokenNr++;
} while ($tokenNr <= count($currentTokenPositions) - 1);
}
if ($found) {
$fileA = $this->hashes[$firstHash][0];
$firstLineA = $this->hashes[$firstHash][1];
if ($line + 1 - $firstLine > $minLines &&
($fileA != $file || $firstLineA != $firstLine)) {
$result->addClone(
new CodeClone(
$fileA,
$firstLineA,
$file,
$firstLine,
$line + 1 - $firstLine,
$tokenNr + 1 - $firstToken
)
);
}
$found = FALSE;
}
}
}
}

View File

@@ -0,0 +1,149 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
namespace SebastianBergmann\PHPCPD\Log
{
use SebastianBergmann\PHPCPD\CodeCloneMap;
/**
* Base class for XML loggers.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.0.0
*/
abstract class AbstractXmlLogger
{
protected $document;
/**
* Constructor.
*
* @param string $filename
*/
public function __construct($filename)
{
$this->document = new \DOMDocument('1.0', 'UTF-8');
$this->document->formatOutput = TRUE;
$this->filename = $filename;
}
/**
* Writes the XML document to the file.
*/
protected function flush()
{
file_put_contents($this->filename, $this->document->saveXML());
}
/**
* Converts a string to UTF-8 encoding.
*
* @param string $string
* @return string
*/
protected function convertToUtf8($string)
{
if (!$this->isUtf8($string)) {
if (function_exists('mb_convert_encoding')) {
$string = mb_convert_encoding($string, 'UTF-8');
} else {
$string = utf8_encode($string);
}
}
return $string;
}
/**
* Checks a string for UTF-8 encoding.
*
* @param string $string
* @return boolean
*/
protected function isUtf8($string)
{
$length = strlen($string);
for ($i = 0; $i < $length; $i++) {
if (ord($string[$i]) < 0x80) {
$n = 0;
}
else if ((ord($string[$i]) & 0xE0) == 0xC0) {
$n = 1;
}
else if ((ord($string[$i]) & 0xF0) == 0xE0) {
$n = 2;
}
else if ((ord($string[$i]) & 0xF0) == 0xF0) {
$n = 3;
}
else {
return FALSE;
}
for ($j = 0; $j < $n; $j++) {
if ((++$i == $length) || ((ord($string[$i]) & 0xC0) != 0x80)) {
return FALSE;
}
}
}
return TRUE;
}
/**
* Processes a list of clones.
*
* @param CodeCloneMap $clones
*/
abstract public function processClones(CodeCloneMap $clones);
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
namespace SebastianBergmann\PHPCPD\Log
{
use SebastianBergmann\PHPCPD\CodeCloneMap;
/**
* Implementation of AbstractXmlLogger that writes in PMD-CPD format.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.0.0
*/
class PMD extends AbstractXmlLogger
{
/**
* Processes a list of clones.
*
* @param CodeCloneMap $clones
*/
public function processClones(CodeCloneMap $clones)
{
$cpd = $this->document->createElement('pmd-cpd');
$this->document->appendChild($cpd);
foreach ($clones as $clone) {
$duplication = $cpd->appendChild(
$this->document->createElement('duplication')
);
$duplication->setAttribute('lines', $clone->size);
$duplication->setAttribute('tokens', $clone->tokens);
$file = $duplication->appendChild(
$this->document->createElement('file')
);
$file->setAttribute('path', $clone->aFile);
$file->setAttribute('line', $clone->aStartLine);
$file = $duplication->appendChild(
$this->document->createElement('file')
);
$file->setAttribute('path', $clone->bFile);
$file->setAttribute('line', $clone->bStartLine);
$duplication->appendChild(
$this->document->createElement(
'codefragment',
htmlspecialchars(
$this->convertToUtf8($clone->getLines()),
ENT_COMPAT,
'UTF-8'
)
)
);
}
$this->flush();
}
}
}

View File

@@ -0,0 +1,310 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
namespace SebastianBergmann\PHPCPD\TextUI
{
use SebastianBergmann\FinderFacade\FinderFacade;
use SebastianBergmann\Version;
use SebastianBergmann\PHPCPD\Detector\Detector;
use SebastianBergmann\PHPCPD\Detector\Strategy\DefaultStrategy;
use SebastianBergmann\PHPCPD\Log\PMD;
/**
* TextUI frontend for PHPCPD.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.0.0
*/
class Command
{
private $version;
public function __construct()
{
$version = new Version('1.4.3', __DIR__);
$this->version = $version->getVersion();
}
/**
* Main method.
*/
public function main()
{
$input = new \ezcConsoleInput;
$input->registerOption(
new \ezcConsoleOption(
'',
'exclude',
\ezcConsoleInput::TYPE_STRING,
array(),
TRUE
)
);
$input->registerOption(
new \ezcConsoleOption(
'h',
'help',
\ezcConsoleInput::TYPE_NONE,
NULL,
FALSE,
'',
'',
array(),
array(),
FALSE,
FALSE,
TRUE
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'log-pmd',
\ezcConsoleInput::TYPE_STRING
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'min-lines',
\ezcConsoleInput::TYPE_INT,
5
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'min-tokens',
\ezcConsoleInput::TYPE_INT,
70
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'names',
\ezcConsoleInput::TYPE_STRING,
'*.php',
FALSE
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'quiet',
\ezcConsoleInput::TYPE_NONE,
NULL,
FALSE
)
);
$input->registerOption(
new \ezcConsoleOption(
'v',
'version',
\ezcConsoleInput::TYPE_NONE,
NULL,
FALSE,
'',
'',
array(),
array(),
FALSE,
FALSE,
TRUE
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'progress',
\ezcConsoleInput::TYPE_NONE
)
);
$input->registerOption(
new \ezcConsoleOption(
'',
'verbose',
\ezcConsoleInput::TYPE_NONE
)
);
try {
$input->process();
}
catch (\ezcConsoleOptionException $e) {
print $e->getMessage() . "\n";
exit(1);
}
if ($input->getOption('help')->value) {
$this->showHelp();
exit(0);
}
else if ($input->getOption('version')->value) {
$this->printVersionString();
exit(0);
}
$arguments = $input->getArguments();
if (empty($arguments)) {
$this->showHelp();
exit(1);
}
$excludes = $input->getOption('exclude')->value;
$logPmd = $input->getOption('log-pmd')->value;
$minLines = $input->getOption('min-lines')->value;
$minTokens = $input->getOption('min-tokens')->value;
$names = explode(',', $input->getOption('names')->value);
$quiet = $input->getOption('quiet')->value;
$verbose = $input->getOption('verbose')->value;
array_map('trim', $names);
if ($input->getOption('progress')->value !== FALSE) {
$output = new \ezcConsoleOutput;
} else {
$output = NULL;
}
$this->printVersionString();
$finder = new FinderFacade($arguments, $excludes, $names);
$files = $finder->findFiles();
if (empty($files)) {
$this->showError("No files found to scan.\n");
}
$strategy = new DefaultStrategy;
$detector = new Detector($strategy, $output);
$clones = $detector->copyPasteDetection(
$files, $minLines, $minTokens
);
$printer = new ResultPrinter;
$printer->printResult($clones, !$quiet, $verbose);
unset($printer);
if ($logPmd) {
$pmd = new PMD($logPmd);
$pmd->processClones($clones);
unset($pmd);
}
if (count($clones) > 0) {
exit(1);
}
}
/**
* Shows an error.
*
* @param string $message
*/
protected function showError($message)
{
$this->printVersionString();
print $message;
exit(1);
}
/**
* Shows the help.
*/
protected function showHelp()
{
$this->printVersionString();
print <<<EOT
Usage: phpcpd [switches] <directory|file> ...
--log-pmd <file> Write report in PMD-CPD XML format to file.
--min-lines <N> Minimum number of identical lines (default: 5).
--min-tokens <N> Minimum number of identical tokens (default: 70).
--exclude <dir> Exclude <dir> from code analysis.
--names <names> A comma-separated list of file names to check.
(default: *.php)
--help Prints this usage information.
--version Prints the version and exits.
--progress Show progress bar.
--quiet Only print the final summary.
--verbose Print duplicated code.
EOT;
}
/**
* Prints the version string.
*/
protected function printVersionString()
{
printf(
"phpcpd %s by Sebastian Bergmann.\n\n", $this->version
);
}
}
}

View File

@@ -0,0 +1,121 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.0.0
*/
namespace SebastianBergmann\PHPCPD\TextUI
{
use SebastianBergmann\PHPCPD\CodeCloneMap;
/**
* A ResultPrinter for the TextUI.
*
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://github.com/sebastianbergmann/phpcpd/tree
* @since Class available since Release 1.0.0
*/
class ResultPrinter
{
/**
* Prints a result set from Detector::copyPasteDetection().
*
* @param CodeCloneMap $clones
* @param bool $printClones
* @param bool $verbose
*/
public function printResult(CodeCloneMap $clones, $printClones, $verbose)
{
$numClones = count($clones);
if ($numClones > 0) {
$buffer = '';
$files = array();
$lines = 0;
foreach ($clones as $clone) {
if (!isset($files[$clone->aFile])) {
$files[$clone->aFile] = TRUE;
}
if (!isset($files[$clone->bFile])) {
$files[$clone->bFile] = TRUE;
}
$lines += $clone->size;
if ($printClones) {
$buffer .= sprintf(
"\n - %s:%d-%d\n %s:%d-%d\n",
$clone->aFile,
$clone->aStartLine,
$clone->aStartLine + $clone->size,
$clone->bFile,
$clone->bStartLine,
$clone->bStartLine + $clone->size
);
if ($verbose) {
$buffer .= "\n" . $clone->getLines(' ');
}
}
}
printf(
"Found %d exact clones with %d duplicated lines in %d files%s",
$numClones,
$lines,
count($files),
$printClones ? ":\n" . $buffer : ".\n"
);
}
printf(
"%s%s duplicated lines out of %d total lines of code.\n\n%s\n",
$numClones > 0 ? "\n" : '',
$clones->getPercentage(),
$clones->getNumLines(),
\PHP_Timer::resourceUsage()
);
}
}
}

View File

@@ -0,0 +1,72 @@
<?php
/**
* phpcpd
*
* Copyright (c) 2009-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Sebastian Bergmann nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package phpcpd
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2009-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @since File available since Release 1.1.0
*/
require_once 'SebastianBergmann/FinderFacade/autoload.php';
require_once 'SebastianBergmann/Version/autoload.php';
require_once 'PHP/Timer/Autoload.php';
require_once 'ezc/Base/base.php';
spl_autoload_register(
function($class) {
static $classes = null;
if ($classes === null) {
$classes = array(
'sebastianbergmann\\phpcpd\\codeclone' => '/CodeClone.php',
'sebastianbergmann\\phpcpd\\codeclonemap' => '/CodeCloneMap.php',
'sebastianbergmann\\phpcpd\\detector\\detector' => '/Detector/Detector.php',
'sebastianbergmann\\phpcpd\\detector\\strategy\\abstractstrategy' => '/Detector/Strategy/Abstract.php',
'sebastianbergmann\\phpcpd\\detector\\strategy\\defaultstrategy' => '/Detector/Strategy/Default.php',
'sebastianbergmann\\phpcpd\\log\\abstractxmllogger' => '/Log/AbstractXmlLogger.php',
'sebastianbergmann\\phpcpd\\log\\pmd' => '/Log/PMD.php',
'sebastianbergmann\\phpcpd\\textui\\command' => '/TextUI/Command.php',
'sebastianbergmann\\phpcpd\\textui\\resultprinter' => '/TextUI/ResultPrinter.php'
);
}
$cn = strtolower($class);
if (isset($classes[$cn])) {
require __DIR__ . $classes[$cn];
}
}
);
spl_autoload_register(array('ezcBase', 'autoload'));

Some files were not shown because too many files have changed in this diff Show More