Compare commits

..
24 Commits
Author SHA1 Message Date
Jérémy BenoistandGitHub 6def743902 Merge pull request #27 from jtojnar/ext-mbstring
Add mbstring as a dependency
2017-03-18 09:16:30 +01:00
Jan Tojnar 8a44926392 Add mbstring as a dependency 2017-03-18 04:02:50 +01:00
Jérémy BenoistandGitHub 8c7740f073 Merge pull request #26 from j0k3r/fix-phpunit-7.x
Fix PHPUnit error on PHP 7+
2017-03-09 09:41:33 +01:00
Jeremy Benoist 6a4720c951 Fix PHPUnit error on PHP 7+ 2017-03-09 09:21:13 +01:00
Jérémy BenoistandGitHub 7a9a82b543 Update README.md 2017-03-09 09:02:04 +01:00
Jérémy BenoistandGitHub 8a91d36294 Merge pull request #25 from jtojnar/patch-1
Add tidy to suggested dependenies
2017-03-09 09:01:05 +01:00
Jan TojnarandGitHub 669adfb20f Add tidy to suggested dependenies 2017-02-16 15:12:45 +01:00
Jeremy BenoistandGitHub 445b889efb Merge pull request #24 from j0k3r/links
Don't be to hard on 'links' attribute
2017-02-02 16:12:48 +01:00
Jeremy Benoist 8b1c3f147d Don't be to hard on 'links' attribute 2017-02-02 15:57:15 +01:00
Jeremy BenoistandGitHub a505a13d0c Merge pull request #22 from jtojnar/master
Depend on psr/log instead of Monolog
2017-01-14 17:09:58 +01:00
Jan Tojnar 9fe0d07805 Depend on psr/log instead of Monolog 2017-01-14 09:08:15 +01:00
Jeremy BenoistandGitHub e5d31b93d1 Merge pull request #21 from j0k3r/childnode-goes-null
Avoid childnode becoming null to generate a warning
2017-01-11 10:54:24 +01:00
Jeremy BenoistandJeremy Benoist 6e24a5d731 Add PHP 7.1 to Travis & fix php-cs-fixer
I don't want to update the .php_cs to be compatible with php-cs-fixer 2.
It works great like that atm.
2017-01-10 11:13:09 +01:00
Jeremy Benoist ff754b80bd Avoid childnode becoming null to generate a warning 2017-01-10 10:58:12 +01:00
Jeremy BenoistandGitHub ade850534c Merge pull request #18 from j0k3r/tool
Don’t be too agressive
2016-10-21 07:24:11 +02:00
Jeremy Benoist d97bece7c5 Don’t be too agressive
Some links got a “tooltip-link” and shouldn’t be removed by php-readability because they are usefull to the content
2016-10-20 23:40:52 +02:00
Jeremy BenoistandGitHub 47ce4fb7f9 Merge pull request #16 from j0k3r/info
“info” is too agressive in unlikelyCandidates
2016-10-03 09:13:35 +02:00
Jeremy Benoist 3de4e918b4 Convert header & section to p
And took `pre` element in score
2016-10-02 14:55:52 +02:00
Jeremy Benoist 5182d6cb11 “info” is too agressive in unlikelyCandidates
Some contents have a `infocontent` node (ot sth different) and they are real content.
Using only `info` as regex is too agressive and remove legitimate content.
Matching the whole word `info` (or `infos`) should be a better choice
2016-10-02 14:49:43 +02:00
Jeremy BenoistandGitHub fb9810a827 Merge pull request #15 from j0k3r/cs
Enable php-cs-fixer
2016-06-24 09:36:50 +02:00
Jeremy Benoist 22aa4c3b31 Fix composer & TLS 2016-06-23 07:44:54 +02:00
Jeremy Benoist 2ef400bf73 Enable php-cs-fixer 2016-06-23 07:28:10 +02:00
Jeremy Benoist dec4514c00 Merge pull request #14 from j0k3r/revert-bc
Revert BC changes
2016-03-01 15:14:36 +01:00
Jeremy Benoist 00f622e9b7 Revert BC changes
- avoid method signature update
- revert moving logic out of the constructor
2016-03-01 15:07:32 +01:00
10 changed files with 337 additions and 112 deletions
+1
View File
@@ -3,6 +3,7 @@
/.gitignore export-ignore /.gitignore export-ignore
/.scrutinizer.yml export-ignore /.scrutinizer.yml export-ignore
/.travis.yml export-ignore /.travis.yml export-ignore
/.php_cs export-ignore
/README.md export-ignore /README.md export-ignore
/phpunit.xml.dist export-ignore /phpunit.xml.dist export-ignore
/tests export-ignore /tests export-ignore
+1
View File
@@ -1,3 +1,4 @@
vendor/ vendor/
coverage/ coverage/
composer.lock composer.lock
.php_cs.cache
+20
View File
@@ -0,0 +1,20 @@
<?php
return Symfony\CS\Config\Config::create()
->setUsingCache(true)
->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL)
// use default SYMFONY_LEVEL and extra fixers:
->fixers(array(
'concat_with_spaces',
'ordered_use',
'phpdoc_order',
'strict',
'strict_param',
'long_array_syntax',
))
->finder(
Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__)
->exclude(array('vendor'))
)
;
+16 -5
View File
@@ -7,12 +7,18 @@ php:
- 5.5 - 5.5
- 5.6 - 5.6
- 7.0 - 7.0
- 7.1
- nightly
- hhvm - hhvm
matrix: matrix:
include:
- php: 7.0
env: CS_FIXER=run
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- php: hhvm - php: hhvm
- php: nightly
# faster builds on new travis setup not using sudo # faster builds on new travis setup not using sudo
sudo: false sudo: false
@@ -23,20 +29,25 @@ cache:
- vendor - vendor
- $HOME/.composer/cache - $HOME/.composer/cache
install: before_install:
- composer self-update
before_script:
- if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi; - if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
# disable TLS for composer because openssl is disabled for PHP 5.3.3 on travis # disable TLS for composer because openssl is disabled for PHP 5.3.3 on travis
# see: https://blog.travis-ci.com/upcoming_ubuntu_11_10_migration/ # see: https://blog.travis-ci.com/upcoming_ubuntu_11_10_migration/
- if [[ $TRAVIS_PHP_VERSION = 5.3.3 ]]; then composer config -g -- disable-tls true; fi; - if [[ $TRAVIS_PHP_VERSION = 5.3.3 ]]; then composer config -g -- disable-tls true; fi;
- if [[ $TRAVIS_PHP_VERSION = 5.3.3 ]]; then composer config -g -- secure-http false; fi; - if [[ $TRAVIS_PHP_VERSION = 5.3.3 ]]; then composer config -g -- secure-http false; fi;
# no version compatible with PHP > 7.1
- if [[ $TRAVIS_PHP_VERSION = 7.2.* ]]; then composer remove friendsofphp/php-cs-fixer; fi;
install:
- composer self-update
before_script:
- composer install --prefer-dist --no-interaction - composer install --prefer-dist --no-interaction
script: script:
- mkdir -p build/logs - mkdir -p build/logs
- phpunit -v --coverage-clover build/logs/clover.xml - php vendor/bin/simple-phpunit -v --coverage-clover build/logs/clover.xml
- if [ "$CS_FIXER" = "run" ]; then php vendor/bin/php-cs-fixer fix --verbose --dry-run ; fi;
after_script: after_script:
- php vendor/bin/coveralls -v - php vendor/bin/coveralls -v
+2 -2
View File
@@ -17,9 +17,9 @@ The default php-readability lib is really old and needs to be improved. I found
## Requirements ## Requirements
By default, this lib will use the [Tidy extension](https://github.com/htacg/tidy-html5) if it's available. Tidy is only used to cleanup the given HTML and avoid problems with bad HTML structure, etc .. By default, this lib will use the [Tidy extension](https://github.com/htacg/tidy-html5) if it's available. Tidy is only used to cleanup the given HTML and avoid problems with bad HTML structure, etc .. It'll be suggested by Composer.
Since Composer doesn't support suggestion on PHP extension, I write this suggestion here. Also, if you got problem from parsing a content without Tidy installed, please install it and try again.
## Usage ## Usage
+9 -2
View File
@@ -25,10 +25,17 @@
}], }],
"require": { "require": {
"php": ">=5.3.3", "php": ">=5.3.3",
"monolog/monolog": "^1.13.1" "ext-mbstring": "*",
"psr/log": "^1.0"
}, },
"require-dev": { "require-dev": {
"satooshi/php-coveralls": "~0.6" "satooshi/php-coveralls": "~0.6",
"friendsofphp/php-cs-fixer": "<2",
"monolog/monolog": "^1.13",
"symfony/phpunit-bridge": "^3.2"
},
"suggest": {
"ext-tidy": "Used to clean up given HTML and to avoid problems with bad HTML structure."
}, },
"autoload": { "autoload": {
"psr-4": { "Readability\\": "src/" } "psr-4": { "Readability\\": "src/" }
+7 -7
View File
@@ -45,14 +45,14 @@ class JSLikeHTMLElement extends \DOMElement
*/ */
public function __set($name, $value) public function __set($name, $value)
{ {
if ($name == 'innerHTML') { if ($name === 'innerHTML') {
// first, empty the element // first, empty the element
for ($x = $this->childNodes->length - 1; $x >= 0; --$x) { for ($x = $this->childNodes->length - 1; $x >= 0; --$x) {
$this->removeChild($this->childNodes->item($x)); $this->removeChild($this->childNodes->item($x));
} }
// $value holds our new inner HTML // $value holds our new inner HTML
if ($value != '') { if ($value !== '') {
$f = $this->ownerDocument->createDocumentFragment(); $f = $this->ownerDocument->createDocumentFragment();
// appendXML() expects well-formed markup (XHTML) // appendXML() expects well-formed markup (XHTML)
@@ -72,7 +72,7 @@ class JSLikeHTMLElement extends \DOMElement
// We use it (and suppress the warning) because an HTML fragment will // We use it (and suppress the warning) because an HTML fragment will
// be wrapped around <html><body> tags which we don't really want to keep. // be wrapped around <html><body> tags which we don't really want to keep.
// Note: despite the warning, if loadHTML succeeds it will return true. // Note: despite the warning, if loadHTML succeeds it will return true.
$result = @$f->loadHTML('<htmlfragment>'.$value.'</htmlfragment>'); $result = @$f->loadHTML('<htmlfragment>' . $value . '</htmlfragment>');
if ($result) { if ($result) {
$import = $f->getElementsByTagName('htmlfragment')->item(0); $import = $f->getElementsByTagName('htmlfragment')->item(0);
@@ -89,7 +89,7 @@ class JSLikeHTMLElement extends \DOMElement
} }
} else { } else {
$trace = debug_backtrace(); $trace = debug_backtrace();
trigger_error('Undefined property via __set(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE); trigger_error('Undefined property via __set(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE);
} }
} }
@@ -102,7 +102,7 @@ class JSLikeHTMLElement extends \DOMElement
*/ */
public function __get($name) public function __get($name)
{ {
if ($name == 'innerHTML') { if ($name === 'innerHTML') {
$inner = ''; $inner = '';
foreach ($this->childNodes as $child) { foreach ($this->childNodes as $child) {
@@ -113,13 +113,13 @@ class JSLikeHTMLElement extends \DOMElement
} }
$trace = debug_backtrace(); $trace = debug_backtrace();
trigger_error('Undefined property via __get(): '.$name.' in '.$trace[0]['file'].' on line '.$trace[0]['line'], E_USER_NOTICE); trigger_error('Undefined property via __get(): ' . $name . ' in ' . $trace[0]['file'] . ' on line ' . $trace[0]['line'], E_USER_NOTICE);
return; return;
} }
public function __toString() public function __toString()
{ {
return '['.$this->tagName.']'; return '[' . $this->tagName . ']';
} }
} }
+91 -65
View File
@@ -66,7 +66,7 @@ class Readability implements LoggerAwareInterface
public $tidied = false; public $tidied = false;
// article domain regexp for calibration // article domain regexp for calibration
protected $domainRegExp = null; protected $domainRegExp = null;
protected $body = null; // protected $body = null;
// Cache the body HTML in case we need to re-use it later // Cache the body HTML in case we need to re-use it later
protected $bodyCache = null; protected $bodyCache = null;
// 1 | 2 | 4; // Start with all processing flags set. // 1 | 2 | 4; // Start with all processing flags set.
@@ -83,11 +83,11 @@ class Readability implements LoggerAwareInterface
* Defined up here so we don't instantiate them repeatedly in loops. * Defined up here so we don't instantiate them repeatedly in loops.
*/ */
public $regexps = array( public $regexps = array(
'unlikelyCandidates' => '/display\s*:\s*none|ignore|\binfo|annoy|clock|date|time|author|intro|links|hidd?e|about|archive|\bprint|bookmark|tags|tag-list|share|search|social|robot|published|combx|comment|mast(?:head)|subscri|community|category|disqus|extra|head|head(?:er|note)|floor|foot(?:er|note)|menu|tool|function|nav|remark|rss|shoutbox|tool|widget|meta|banner|sponsor|adsense|inner-?ad|ad-|sponsor|\badv\b|\bads\b|agr?egate?|pager|sidebar|popup|tweet|twitter/i', 'unlikelyCandidates' => '/display\s*:\s*none|ignore|\binfos?\b|annoy|clock|date|time|author|intro|hidd?e|about|archive|\bprint|bookmark|tags|tag-list|share|search|social|robot|published|combx|comment|mast(?:head)|subscri|community|category|disqus|extra|head|head(?:er|note)|floor|foot(?:er|note)|menu|tool\b|function|nav|remark|rss|shoutbox|widget|meta|banner|sponsor|adsense|inner-?ad|ad-|sponsor|\badv\b|\bads\b|agr?egate?|pager|sidebar|popup|tweet|twitter/i',
'okMaybeItsACandidate' => '/article\b|contain|\bcontent|column|general|detail|shadow|lightbox|blog|body|entry|main|page/i', 'okMaybeItsACandidate' => '/article\b|contain|\bcontent|column|general|detail|shadow|lightbox|blog|body|entry|main|page/i',
'positive' => '/read|full|article|body|\bcontent|contain|entry|main|markdown|page|attach|pagination|post|text|blog|story/i', 'positive' => '/read|full|article|body|\bcontent|contain|entry|main|markdown|page|attach|pagination|post|text|blog|story/i',
'negative' => '/bottom|stat|info|discuss|e[\-]?mail|comment|reply|log.{2}(n|ed)|sign|single|combx|com-|contact|_nav|link|media|\bout|promo|\bad-|related|scroll|shoutbox|sidebar|sponsor|shopping|teaser|recommend/i', 'negative' => '/bottom|stat|info|discuss|e[\-]?mail|comment|reply|log.{2}(n|ed)|sign|single|combx|com-|contact|_nav|link|media|\bout|promo|\bad-|related|scroll|shoutbox|sidebar|sponsor|shopping|teaser|recommend/i',
'divToPElements' => '/<(?:blockquote|code|div|article|footer|aside|img|p|pre|dl|ol|ul)/mi', 'divToPElements' => '/<(?:blockquote|header|section|code|div|article|footer|aside|img|p|pre|dl|ol|ul)/mi',
'killBreaks' => '/(<br\s*\/?>([ \r\n\s]|&nbsp;?)*)+/', 'killBreaks' => '/(<br\s*\/?>([ \r\n\s]|&nbsp;?)*)+/',
'media' => '!//(?:[^\.\?/]+\.)?(?:youtu(?:be)?|soundcloud|dailymotion|vimeo|pornhub|xvideos|twitvid|rutube|viddler)\.(?:com|be|org|net)/!i', 'media' => '!//(?:[^\.\?/]+\.)?(?:youtu(?:be)?|soundcloud|dailymotion|vimeo|pornhub|xvideos|twitvid|rutube|viddler)\.(?:com|be|org|net)/!i',
'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i', 'skipFootnoteLink' => '/^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i',
@@ -174,14 +174,15 @@ class Readability implements LoggerAwareInterface
* @param string (optional) Which parser to use for turning raw HTML into a DOMDocument * @param string (optional) Which parser to use for turning raw HTML into a DOMDocument
* @param bool (optional) Use tidy * @param bool (optional) Use tidy
*/ */
public function __construct($html, $url = null, $parser = 'libxml', $useTidy = true) public function __construct($html, $url = null, $parser = 'libxml', $use_tidy = true)
{ {
$this->url = $url; $this->url = $url;
$this->html = $html; $this->html = $html;
$this->parser = $parser; $this->parser = $parser;
$this->useTidy = $useTidy && function_exists('tidy_parse_string'); $this->useTidy = $use_tidy && function_exists('tidy_parse_string');
$this->logger = new NullLogger(); $this->logger = new NullLogger();
$this->loadHtml();
} }
public function setLogger(LoggerInterface $logger) public function setLogger(LoggerInterface $logger)
@@ -235,15 +236,17 @@ class Readability implements LoggerAwareInterface
* Load HTML in a DOMDocument. * Load HTML in a DOMDocument.
* Apply Pre filters * Apply Pre filters
* Cleanup HTML using Tidy (or not). * Cleanup HTML using Tidy (or not).
*
* @todo This should be called in init() instead of from __construct
*/ */
private function loadHtml() private function loadHtml()
{ {
$this->original_html = $this->html; $this->original_html = $this->html;
$this->logger->debug('Parsing URL: '.$this->url); $this->logger->debug('Parsing URL: ' . $this->url);
if ($this->url) { if ($this->url) {
$this->domainRegExp = '/'.strtr(preg_replace('/www\d*\./', '', parse_url($this->url, PHP_URL_HOST)), array('.' => '\.')).'/'; $this->domainRegExp = '/' . strtr(preg_replace('/www\d*\./', '', parse_url($this->url, PHP_URL_HOST)), array('.' => '\.')) . '/';
} }
mb_internal_encoding('UTF-8'); mb_internal_encoding('UTF-8');
@@ -266,7 +269,6 @@ class Readability implements LoggerAwareInterface
* Use tidy (if it exists). * Use tidy (if it exists).
* This fixes problems with some sites which would otherwise trouble DOMDocument's HTML parsing. * This fixes problems with some sites which would otherwise trouble DOMDocument's HTML parsing.
* Although sometimes it makes matters worse, which is why there is an option to disable it. * Although sometimes it makes matters worse, which is why there is an option to disable it.
*
*/ */
if ($this->useTidy) { if ($this->useTidy) {
$this->logger->debug('Tidying document'); $this->logger->debug('Tidying document');
@@ -282,7 +284,7 @@ class Readability implements LoggerAwareInterface
$this->html = mb_convert_encoding($this->html, 'HTML-ENTITIES', 'UTF-8'); $this->html = mb_convert_encoding($this->html, 'HTML-ENTITIES', 'UTF-8');
if (!($this->parser == 'html5lib' && ($this->dom = \HTML5_Parser::parse($this->html)))) { if (!($this->parser === 'html5lib' && ($this->dom = \HTML5_Parser::parse($this->html)))) {
libxml_use_internal_errors(true); libxml_use_internal_errors(true);
$this->dom = new \DOMDocument(); $this->dom = new \DOMDocument();
@@ -314,8 +316,6 @@ class Readability implements LoggerAwareInterface
*/ */
public function init() public function init()
{ {
$this->loadHtml();
if (!isset($this->dom->documentElement)) { if (!isset($this->dom->documentElement)) {
return false; return false;
} }
@@ -325,7 +325,7 @@ class Readability implements LoggerAwareInterface
$bodyElems = $this->dom->getElementsByTagName('body'); $bodyElems = $this->dom->getElementsByTagName('body');
// WTF multiple body nodes? // WTF multiple body nodes?
if ($this->bodyCache == null) { if ($this->bodyCache === null) {
$this->bodyCache = ''; $this->bodyCache = '';
foreach ($bodyElems as $bodyNode) { foreach ($bodyElems as $bodyNode) {
$this->bodyCache .= trim($bodyNode->innerHTML); $this->bodyCache .= trim($bodyNode->innerHTML);
@@ -372,12 +372,33 @@ class Readability implements LoggerAwareInterface
return $this->success; return $this->success;
} }
/**
* Debug.
*
* @deprecated use $this->logger->debug() instead
* @codeCoverageIgnore
*/
protected function dbg($msg)
{
$this->logger->debug($msg);
}
/**
* Dump debug info.
*
* @deprecated since Monolog gather log, we don't need it
* @codeCoverageIgnore
*/
protected function dump_dbg()
{
}
/** /**
* Run any post-process modifications to article content as necessary. * Run any post-process modifications to article content as necessary.
* *
* @param \DOMElement $articleContent * @param \DOMElement $articleContent
*/ */
public function postProcessContent(\DOMElement $articleContent) public function postProcessContent($articleContent)
{ {
if ($this->convertLinksToFootnotes && !preg_match('/\bwiki/', $this->url)) { if ($this->convertLinksToFootnotes && !preg_match('/\bwiki/', $this->url)) {
$this->addFootnotes($articleContent); $this->addFootnotes($articleContent);
@@ -410,7 +431,7 @@ class Readability implements LoggerAwareInterface
} }
} elseif (mb_strlen($curTitle) > 150 || mb_strlen($curTitle) < 15) { } elseif (mb_strlen($curTitle) > 150 || mb_strlen($curTitle) < 15) {
$hOnes = $this->dom->getElementsByTagName('h1'); $hOnes = $this->dom->getElementsByTagName('h1');
if ($hOnes->length == 1) { if ($hOnes->length === 1) {
$curTitle = $this->getInnerText($hOnes->item(0)); $curTitle = $this->getInnerText($hOnes->item(0));
} }
} }
@@ -462,7 +483,7 @@ class Readability implements LoggerAwareInterface
* *
* @param \DOMElement $articleContent * @param \DOMElement $articleContent
*/ */
public function addFootnotes(\DOMElement $articleContent) public function addFootnotes($articleContent)
{ {
$footnotesWrapper = $this->dom->createElement('footer'); $footnotesWrapper = $this->dom->createElement('footer');
$footnotesWrapper->setAttribute('class', 'readability-footnotes'); $footnotesWrapper->setAttribute('class', 'readability-footnotes');
@@ -491,8 +512,8 @@ class Readability implements LoggerAwareInterface
++$linkCount; ++$linkCount;
// Add a superscript reference after the article link. // Add a superscript reference after the article link.
$refLink->setAttribute('href', '#readabilityFootnoteLink-'.$linkCount); $refLink->setAttribute('href', '#readabilityFootnoteLink-' . $linkCount);
$refLink->innerHTML = '<small><sup>['.$linkCount.']</sup></small>'; $refLink->innerHTML = '<small><sup>[' . $linkCount . ']</sup></small>';
$refLink->setAttribute('class', 'readability-DoNotFootnote'); $refLink->setAttribute('class', 'readability-DoNotFootnote');
$refLink->setAttribute('style', 'color: inherit;'); $refLink->setAttribute('style', 'color: inherit;');
@@ -503,14 +524,14 @@ class Readability implements LoggerAwareInterface
} }
$articleLink->setAttribute('style', 'color: inherit; text-decoration: none;'); $articleLink->setAttribute('style', 'color: inherit; text-decoration: none;');
$articleLink->setAttribute('name', 'readabilityLink-'.$linkCount); $articleLink->setAttribute('name', 'readabilityLink-' . $linkCount);
$footnote->innerHTML = '<small><sup><a href="#readabilityLink-'.$linkCount.'" title="Jump to Link in Article">^</a></sup></small> '; $footnote->innerHTML = '<small><sup><a href="#readabilityLink-' . $linkCount . '" title="Jump to Link in Article">^</a></sup></small> ';
$footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') != '' ? $footnoteLink->getAttribute('title') : $linkText); $footnoteLink->innerHTML = ($footnoteLink->getAttribute('title') !== '' ? $footnoteLink->getAttribute('title') : $linkText);
$footnoteLink->setAttribute('name', 'readabilityFootnoteLink-'.$linkCount); $footnoteLink->setAttribute('name', 'readabilityFootnoteLink-' . $linkCount);
$footnote->appendChild($footnoteLink); $footnote->appendChild($footnoteLink);
if ($linkDomain) { if ($linkDomain) {
$footnote->innerHTML = $footnote->innerHTML.'<small> ('.$linkDomain.')</small>'; $footnote->innerHTML = $footnote->innerHTML . '<small> (' . $linkDomain . ')</small>';
} }
$articleFootnotes->appendChild($footnote); $articleFootnotes->appendChild($footnote);
} }
@@ -526,7 +547,7 @@ class Readability implements LoggerAwareInterface
* *
* @param \DOMElement $articleContent * @param \DOMElement $articleContent
*/ */
public function prepArticle(\DOMElement $articleContent) public function prepArticle($articleContent)
{ {
$this->logger->debug($this->lightClean ? 'Light clean enabled.' : 'Standard clean enabled.'); $this->logger->debug($this->lightClean ? 'Light clean enabled.' : 'Standard clean enabled.');
@@ -567,7 +588,7 @@ class Readability implements LoggerAwareInterface
* already have a header. * already have a header.
*/ */
$h2s = $articleContent->getElementsByTagName('h2'); $h2s = $articleContent->getElementsByTagName('h2');
if ($h2s->length == 1 && mb_strlen($this->getInnerText($h2s->item(0), true, true)) < 100) { if ($h2s->length === 1 && mb_strlen($this->getInnerText($h2s->item(0), true, true)) < 100) {
$this->clean($articleContent, 'h2'); $this->clean($articleContent, 'h2');
} }
@@ -612,7 +633,7 @@ class Readability implements LoggerAwareInterface
} }
unset($search, $replace); unset($search, $replace);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->error('Cleaning output HTML failed. Ignoring: '.$e->getMessage()); $this->logger->error('Cleaning output HTML failed. Ignoring: ' . $e->getMessage());
} }
} }
} }
@@ -623,7 +644,7 @@ class Readability implements LoggerAwareInterface
* *
* @param \DOMElement $node * @param \DOMElement $node
*/ */
protected function initializeNode(\DOMElement $node) protected function initializeNode($node)
{ {
if (!isset($node->tagName)) { if (!isset($node->tagName)) {
return; return;
@@ -694,7 +715,7 @@ class Readability implements LoggerAwareInterface
* *
* @return \DOMElement|bool * @return \DOMElement|bool
*/ */
protected function grabArticle(\DOMElement $page = null) protected function grabArticle($page = null)
{ {
if (!$page) { if (!$page) {
$page = $this->dom; $page = $this->dom;
@@ -711,8 +732,9 @@ class Readability implements LoggerAwareInterface
for ($nodeIndex = 0; ($node = $allElements->item($nodeIndex)); ++$nodeIndex) { for ($nodeIndex = 0; ($node = $allElements->item($nodeIndex)); ++$nodeIndex) {
$tagName = $node->tagName; $tagName = $node->tagName;
// Some well known site uses sections as paragraphs. // Some well known site uses sections as paragraphs.
if (strcasecmp($tagName, 'p') === 0 || strcasecmp($tagName, 'td') === 0 || strcasecmp($tagName, 'section') === 0) { if (strcasecmp($tagName, 'p') === 0 || strcasecmp($tagName, 'td') === 0 || strcasecmp($tagName, 'pre') === 0 || strcasecmp($tagName, 'section') === 0) {
$nodesToScore[] = $node; $nodesToScore[] = $node;
} }
@@ -729,13 +751,18 @@ class Readability implements LoggerAwareInterface
--$nodeIndex; --$nodeIndex;
$nodesToScore[] = $newNode; $nodesToScore[] = $newNode;
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->error('Could not alter div/article to p, reverting back to div: '.$e->getMessage()); $this->logger->error('Could not alter div/article to p, reverting back to div: ' . $e->getMessage());
} }
} else { } else {
// Will change these P elements back to text nodes after processing. // Will change these P elements back to text nodes after processing.
for ($i = 0, $il = $node->childNodes->length; $i < $il; ++$i) { for ($i = 0, $il = $node->childNodes->length; $i < $il; ++$i) {
$childNode = $node->childNodes->item($i); $childNode = $node->childNodes->item($i);
// it looks like sometimes the loop is going too far and we are retrieving a non-existant child
if (null === $childNode) {
continue;
}
// executable tags (<?php or <?xml) warning // executable tags (<?php or <?xml) warning
if (is_object($childNode) && get_class($childNode) === 'DOMProcessingInstruction') { if (is_object($childNode) && get_class($childNode) === 'DOMProcessingInstruction') {
$childNode->parentNode->removeChild($childNode); $childNode->parentNode->removeChild($childNode);
@@ -743,8 +770,7 @@ class Readability implements LoggerAwareInterface
continue; continue;
} }
// XML_TEXT_NODE if ($childNode->nodeType === XML_TEXT_NODE) {
if ($childNode->nodeType == 3) {
$p = $this->dom->createElement('p'); $p = $this->dom->createElement('p');
$p->innerHTML = $childNode->nodeValue; $p->innerHTML = $childNode->nodeValue;
$p->setAttribute('data-readability-styled', 'true'); $p->setAttribute('data-readability-styled', 'true');
@@ -770,7 +796,7 @@ class Readability implements LoggerAwareInterface
continue; continue;
} }
$grandParentNode = ($parentNode->parentNode instanceof \DOMElement) ? $parentNode->parentNode : null; $grandParentNode = $parentNode->parentNode instanceof \DOMElement ? $parentNode->parentNode : null;
$innerText = $this->getInnerText($nodesToScore[$pt]); $innerText = $this->getInnerText($nodesToScore[$pt]);
// If this paragraph is less than MIN_PARAGRAPH_LENGTH (default:20) characters, don't even count it. // If this paragraph is less than MIN_PARAGRAPH_LENGTH (default:20) characters, don't even count it.
@@ -830,7 +856,7 @@ class Readability implements LoggerAwareInterface
$node = $candidates->item($c); $node = $candidates->item($c);
// node should be readable but not inside of an article otherwise it's probably non-readable block // node should be readable but not inside of an article otherwise it's probably non-readable block
if ($node->hasAttribute('readability') && (int) $node->getAttributeNode('readability')->value < 40 && ($node->parentNode ? strcasecmp($node->parentNode->tagName, 'article') !== 0 : true)) { if ($node->hasAttribute('readability') && (int) $node->getAttributeNode('readability')->value < 40 && ($node->parentNode ? strcasecmp($node->parentNode->tagName, 'article') !== 0 : true)) {
$this->logger->debug('Removing unlikely candidate (using note) '.$node->getNodePath().' by "'.$node->tagName.'" with readability '.($node->hasAttribute('readability') ? (int) $node->getAttributeNode('readability')->value : 0)); $this->logger->debug('Removing unlikely candidate (using note) ' . $node->getNodePath() . ' by "' . $node->tagName . '" with readability ' . ($node->hasAttribute('readability') ? (int) $node->getAttributeNode('readability')->value : 0));
$node->parentNode->removeChild($node); $node->parentNode->removeChild($node);
} }
} }
@@ -842,13 +868,13 @@ class Readability implements LoggerAwareInterface
$node = $candidates->item($c); $node = $candidates->item($c);
// Remove unlikely candidates // Remove unlikely candidates
$unlikelyMatchString = $node->getAttribute('class').' '.$node->getAttribute('id').' '.$node->getAttribute('style'); $unlikelyMatchString = $node->getAttribute('class') . ' ' . $node->getAttribute('id') . ' ' . $node->getAttribute('style');
if (mb_strlen($unlikelyMatchString) > 3 && // don't process "empty" strings if (mb_strlen($unlikelyMatchString) > 3 && // don't process "empty" strings
preg_match($this->regexps['unlikelyCandidates'], $unlikelyMatchString) && preg_match($this->regexps['unlikelyCandidates'], $unlikelyMatchString) &&
!preg_match($this->regexps['okMaybeItsACandidate'], $unlikelyMatchString) !preg_match($this->regexps['okMaybeItsACandidate'], $unlikelyMatchString)
) { ) {
$this->logger->debug('Removing unlikely candidate (using conf) '.$node->getNodePath().' by "'.$unlikelyMatchString.'" with readability '.($node->hasAttribute('readability') ? (int) $node->getAttributeNode('readability')->value : 0)); $this->logger->debug('Removing unlikely candidate (using conf) ' . $node->getNodePath() . ' by "' . $unlikelyMatchString . '" with readability ' . ($node->hasAttribute('readability') ? (int) $node->getAttributeNode('readability')->value : 0));
$node->parentNode->removeChild($node); $node->parentNode->removeChild($node);
--$nodeIndex; --$nodeIndex;
} }
@@ -875,7 +901,7 @@ class Readability implements LoggerAwareInterface
$readability->value = round($readability->value * (1 - $this->getLinkDensity($item)), 0, PHP_ROUND_HALF_UP); $readability->value = round($readability->value * (1 - $this->getLinkDensity($item)), 0, PHP_ROUND_HALF_UP);
if (!$topCandidate || $readability->value > (int) $topCandidate->getAttribute('readability')) { if (!$topCandidate || $readability->value > (int) $topCandidate->getAttribute('readability')) {
$this->logger->debug('Candidate: '.$item->getNodePath().' ('.$item->getAttribute('class').':'.$item->getAttribute('id').') with score '.$readability->value); $this->logger->debug('Candidate: ' . $item->getNodePath() . ' (' . $item->getAttribute('class') . ':' . $item->getAttribute('id') . ') with score ' . $readability->value);
$topCandidate = $item; $topCandidate = $item;
} }
} }
@@ -924,7 +950,7 @@ class Readability implements LoggerAwareInterface
} }
} }
$this->logger->debug('Top candidate: '.$topCandidate->getNodePath()); $this->logger->debug('Top candidate: ' . $topCandidate->getNodePath());
/* /*
* Now that we have the top candidate, look through its siblings for content that might also be related. * Now that we have the top candidate, look through its siblings for content that might also be related.
@@ -944,7 +970,7 @@ class Readability implements LoggerAwareInterface
$siblingNode = $siblingNodes->item($s); $siblingNode = $siblingNodes->item($s);
$siblingNodeName = $siblingNode->nodeName; $siblingNodeName = $siblingNode->nodeName;
$append = false; $append = false;
$this->logger->debug('Looking at sibling node: '.$siblingNode->getNodePath().(($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('readability')) ? (' with score '.$siblingNode->getAttribute('readability')) : '')); $this->logger->debug('Looking at sibling node: ' . $siblingNode->getNodePath() . (($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->hasAttribute('readability')) ? (' with score ' . $siblingNode->getAttribute('readability')) : ''));
if ($siblingNode->isSameNode($topCandidate)) { if ($siblingNode->isSameNode($topCandidate)) {
$append = true; $append = true;
@@ -953,7 +979,7 @@ class Readability implements LoggerAwareInterface
$contentBonus = 0; $contentBonus = 0;
// Give a bonus if sibling nodes and top candidates have the same classname. // Give a bonus if sibling nodes and top candidates have the same classname.
if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->getAttribute('class') == $topCandidate->getAttribute('class') && $topCandidate->getAttribute('class') != '') { if ($siblingNode->nodeType === XML_ELEMENT_NODE && $siblingNode->getAttribute('class') === $topCandidate->getAttribute('class') && $topCandidate->getAttribute('class') !== '') {
$contentBonus += ((int) $topCandidate->getAttribute('readability')) * 0.2; $contentBonus += ((int) $topCandidate->getAttribute('readability')) * 0.2;
} }
@@ -973,18 +999,18 @@ class Readability implements LoggerAwareInterface
} }
if ($append) { if ($append) {
$this->logger->debug('Appending node: '.$siblingNode->getNodePath()); $this->logger->debug('Appending node: ' . $siblingNode->getNodePath());
if (strcasecmp($siblingNodeName, 'div') !== 0 && strcasecmp($siblingNodeName, 'p') !== 0) { if (strcasecmp($siblingNodeName, 'div') !== 0 && strcasecmp($siblingNodeName, 'p') !== 0) {
// We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. // We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident.
$this->logger->debug('Altering siblingNode "'.$siblingNodeName.'" to "div".'); $this->logger->debug('Altering siblingNode "' . $siblingNodeName . '" to "div".');
$nodeToAppend = $this->dom->createElement('div'); $nodeToAppend = $this->dom->createElement('div');
try { try {
$nodeToAppend->setAttribute('alt', $siblingNodeName); $nodeToAppend->setAttribute('alt', $siblingNodeName);
$nodeToAppend->innerHTML = $siblingNode->innerHTML; $nodeToAppend->innerHTML = $siblingNode->innerHTML;
} catch (\Exception $e) { } catch (\Exception $e) {
$this->logger->debug('Could not alter siblingNode "'.$siblingNodeName.'" to "div", reverting to original.'); $this->logger->debug('Could not alter siblingNode "' . $siblingNodeName . '" to "div", reverting to original.');
$nodeToAppend = $siblingNode; $nodeToAppend = $siblingNode;
--$s; --$s;
--$sl; --$sl;
@@ -1020,17 +1046,17 @@ class Readability implements LoggerAwareInterface
if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) { if ($this->flagIsActive(self::FLAG_STRIP_UNLIKELYS)) {
$this->removeFlag(self::FLAG_STRIP_UNLIKELYS); $this->removeFlag(self::FLAG_STRIP_UNLIKELYS);
$this->logger->debug('...content is shorter than '.self::MIN_ARTICLE_LENGTH." letters, trying not to strip unlikely content.\n"); $this->logger->debug('...content is shorter than ' . self::MIN_ARTICLE_LENGTH . " letters, trying not to strip unlikely content.\n");
return $this->grabArticle($this->body); return $this->grabArticle($this->body);
} elseif ($this->flagIsActive(self::FLAG_WEIGHT_ATTRIBUTES)) { } elseif ($this->flagIsActive(self::FLAG_WEIGHT_ATTRIBUTES)) {
$this->removeFlag(self::FLAG_WEIGHT_ATTRIBUTES); $this->removeFlag(self::FLAG_WEIGHT_ATTRIBUTES);
$this->logger->debug('...content is shorter than '.self::MIN_ARTICLE_LENGTH." letters, trying not to weight attributes.\n"); $this->logger->debug('...content is shorter than ' . self::MIN_ARTICLE_LENGTH . " letters, trying not to weight attributes.\n");
return $this->grabArticle($this->body); return $this->grabArticle($this->body);
} elseif ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) { } elseif ($this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
$this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY); $this->removeFlag(self::FLAG_CLEAN_CONDITIONALLY);
$this->logger->debug('...content is shorter than '.self::MIN_ARTICLE_LENGTH." letters, trying not to clean at all.\n"); $this->logger->debug('...content is shorter than ' . self::MIN_ARTICLE_LENGTH . " letters, trying not to clean at all.\n");
return $this->grabArticle($this->body); return $this->grabArticle($this->body);
} }
@@ -1051,7 +1077,7 @@ class Readability implements LoggerAwareInterface
* *
* @return string * @return string
*/ */
public function getInnerText(\DOMElement $e = null, $normalizeSpaces = true, $flattenLines = false) public function getInnerText($e, $normalizeSpaces = true, $flattenLines = false)
{ {
if (null === $e || !isset($e->textContent) || $e->textContent === '') { if (null === $e || !isset($e->textContent) || $e->textContent === '') {
return ''; return '';
@@ -1073,7 +1099,7 @@ class Readability implements LoggerAwareInterface
* *
* @param \DOMElement $e * @param \DOMElement $e
*/ */
public function cleanStyles(\DOMElement $e) public function cleanStyles($e)
{ {
if (!is_object($e)) { if (!is_object($e)) {
return; return;
@@ -1121,7 +1147,7 @@ class Readability implements LoggerAwareInterface
* *
* @return int * @return int
*/ */
public function getLinkDensity(\DOMElement $e, $excludeExternal = false) public function getLinkDensity($e, $excludeExternal = false)
{ {
$links = $e->getElementsByTagName('a'); $links = $e->getElementsByTagName('a');
$textLength = mb_strlen($this->getInnerText($e, true, true)); $textLength = mb_strlen($this->getInnerText($e, true, true));
@@ -1150,7 +1176,7 @@ class Readability implements LoggerAwareInterface
* *
* @return int * @return int
*/ */
protected function weightAttribute(\DOMElement $element, $attribute) protected function weightAttribute($element, $attribute)
{ {
if (!$element->hasAttribute($attribute)) { if (!$element->hasAttribute($attribute)) {
return 0; return 0;
@@ -1160,7 +1186,7 @@ class Readability implements LoggerAwareInterface
// $attributeValue = trim($element->getAttribute('class')." ".$element->getAttribute('id')); // $attributeValue = trim($element->getAttribute('class')." ".$element->getAttribute('id'));
$attributeValue = trim($element->getAttribute($attribute)); $attributeValue = trim($element->getAttribute($attribute));
if ($attributeValue != '') { if ($attributeValue !== '') {
if (preg_match($this->regexps['negative'], $attributeValue)) { if (preg_match($this->regexps['negative'], $attributeValue)) {
$weight -= 25; $weight -= 25;
} }
@@ -1185,7 +1211,7 @@ class Readability implements LoggerAwareInterface
* *
* @return int * @return int
*/ */
public function getWeight(\DOMElement $e) public function getWeight($e)
{ {
if (!$this->flagIsActive(self::FLAG_WEIGHT_ATTRIBUTES)) { if (!$this->flagIsActive(self::FLAG_WEIGHT_ATTRIBUTES)) {
return 0; return 0;
@@ -1205,7 +1231,7 @@ class Readability implements LoggerAwareInterface
* *
* @param \DOMElement $node * @param \DOMElement $node
*/ */
public function killBreaks(\DOMElement $node) public function killBreaks($node)
{ {
$html = $node->innerHTML; $html = $node->innerHTML;
$html = preg_replace($this->regexps['killBreaks'], '<br />', $html); $html = preg_replace($this->regexps['killBreaks'], '<br />', $html);
@@ -1221,7 +1247,7 @@ class Readability implements LoggerAwareInterface
* @param \DOMElement $e * @param \DOMElement $e
* @param string $tag * @param string $tag
*/ */
public function clean(\DOMElement $e, $tag) public function clean($e, $tag)
{ {
$currentItem = null; $currentItem = null;
$targetList = $e->getElementsByTagName($tag); $targetList = $e->getElementsByTagName($tag);
@@ -1232,7 +1258,7 @@ class Readability implements LoggerAwareInterface
$currentItem = $targetList->item($y); $currentItem = $targetList->item($y);
if ($isEmbed) { if ($isEmbed) {
$attributeValues = $currentItem->getAttribute('src').' '.$currentItem->getAttribute('href'); $attributeValues = $currentItem->getAttribute('src') . ' ' . $currentItem->getAttribute('href');
// First, check the elements attributes to see if any of them contain known media hosts // First, check the elements attributes to see if any of them contain known media hosts
if (preg_match($this->regexps['media'], $attributeValues)) { if (preg_match($this->regexps['media'], $attributeValues)) {
@@ -1257,7 +1283,7 @@ class Readability implements LoggerAwareInterface
* @param \DOMElement $e * @param \DOMElement $e
* @param string $tag * @param string $tag
*/ */
public function cleanConditionally(\DOMElement $e, $tag) public function cleanConditionally($e, $tag)
{ {
if (!$this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) { if (!$this->flagIsActive(self::FLAG_CLEAN_CONDITIONALLY)) {
return; return;
@@ -1277,7 +1303,7 @@ class Readability implements LoggerAwareInterface
$node = $tagsList->item($i); $node = $tagsList->item($i);
$weight = $this->getWeight($node); $weight = $this->getWeight($node);
$contentScore = ($node->hasAttribute('readability')) ? (int) $node->getAttribute('readability') : 0; $contentScore = ($node->hasAttribute('readability')) ? (int) $node->getAttribute('readability') : 0;
$this->logger->debug('Start conditional cleaning of '.$node->getNodePath().' (class='.$node->getAttribute('class').'; id='.$node->getAttribute('id').')'.(($node->hasAttribute('readability')) ? (' with score '.$node->getAttribute('readability')) : '')); $this->logger->debug('Start conditional cleaning of ' . $node->getNodePath() . ' (class=' . $node->getAttribute('class') . '; id=' . $node->getAttribute('id') . ')' . (($node->hasAttribute('readability')) ? (' with score ' . $node->getAttribute('readability')) : ''));
if ($weight + $contentScore < 0) { if ($weight + $contentScore < 0) {
$this->logger->debug('Removing...'); $this->logger->debug('Removing...');
@@ -1313,7 +1339,7 @@ class Readability implements LoggerAwareInterface
$toRemove = false; $toRemove = false;
if ($this->lightClean) { if ($this->lightClean) {
if ($li > $p && $tag != 'ul' && $tag != 'ol') { if ($li > $p && $tag !== 'ul' && $tag !== 'ol') {
$this->logger->debug(' too many <li> elements, and parent is not <ul> or <ol>'); $this->logger->debug(' too many <li> elements, and parent is not <ul> or <ol>');
$toRemove = true; $toRemove = true;
} elseif ($input > floor($p / 3)) { } elseif ($input > floor($p / 3)) {
@@ -1323,10 +1349,10 @@ class Readability implements LoggerAwareInterface
$this->logger->debug(' content length less than 6 chars, 0 embeds and either 0 images or more than 2 images'); $this->logger->debug(' content length less than 6 chars, 0 embeds and either 0 images or more than 2 images');
$toRemove = true; $toRemove = true;
} elseif ($weight < 25 && $linkDensity > 0.25) { } elseif ($weight < 25 && $linkDensity > 0.25) {
$this->logger->debug(' weight is '.$weight.' < 25 and link density is '.sprintf('%.2f', $linkDensity).' > 0.25'); $this->logger->debug(' weight is ' . $weight . ' < 25 and link density is ' . sprintf('%.2f', $linkDensity) . ' > 0.25');
$toRemove = true; $toRemove = true;
} elseif ($a > 2 && ($weight >= 25 && $linkDensity > 0.5)) { } elseif ($a > 2 && ($weight >= 25 && $linkDensity > 0.5)) {
$this->logger->debug(' more than 2 links and weight is '.$weight.' > 25 but link density is '.sprintf('%.2f', $linkDensity).' > 0.5'); $this->logger->debug(' more than 2 links and weight is ' . $weight . ' > 25 but link density is ' . sprintf('%.2f', $linkDensity) . ' > 0.5');
$toRemove = true; $toRemove = true;
} elseif ($embedCount > 3) { } elseif ($embedCount > 3) {
$this->logger->debug(' more than 3 embeds'); $this->logger->debug(' more than 3 embeds');
@@ -1336,7 +1362,7 @@ class Readability implements LoggerAwareInterface
if ($img > $p) { if ($img > $p) {
$this->logger->debug(' more image elements than paragraph elements'); $this->logger->debug(' more image elements than paragraph elements');
$toRemove = true; $toRemove = true;
} elseif ($li > $p && $tag != 'ul' && $tag != 'ol') { } elseif ($li > $p && $tag !== 'ul' && $tag !== 'ol') {
$this->logger->debug(' too many <li> elements, and parent is not <ul> or <ol>'); $this->logger->debug(' too many <li> elements, and parent is not <ul> or <ol>');
$toRemove = true; $toRemove = true;
} elseif ($input > floor($p / 3)) { } elseif ($input > floor($p / 3)) {
@@ -1346,12 +1372,12 @@ class Readability implements LoggerAwareInterface
$this->logger->debug(' content length less than 10 chars and 0 images, or more than 2 images'); $this->logger->debug(' content length less than 10 chars and 0 images, or more than 2 images');
$toRemove = true; $toRemove = true;
} elseif ($weight < 25 && $linkDensity > 0.2) { } elseif ($weight < 25 && $linkDensity > 0.2) {
$this->logger->debug(' weight is '.$weight.' lower than 0 and link density is '.sprintf('%.2f', $linkDensity).' > 0.2'); $this->logger->debug(' weight is ' . $weight . ' lower than 0 and link density is ' . sprintf('%.2f', $linkDensity) . ' > 0.2');
$toRemove = true; $toRemove = true;
} elseif ($weight >= 25 && $linkDensity > 0.5) { } elseif ($weight >= 25 && $linkDensity > 0.5) {
$this->logger->debug(' weight above 25 but link density is '.sprintf('%.2f', $linkDensity).' > 0.5'); $this->logger->debug(' weight above 25 but link density is ' . sprintf('%.2f', $linkDensity) . ' > 0.5');
$toRemove = true; $toRemove = true;
} elseif (($embedCount == 1 && $contentLength < 75) || $embedCount > 1) { } elseif (($embedCount === 1 && $contentLength < 75) || $embedCount > 1) {
$this->logger->debug(' 1 embed and content length smaller than 75 chars, or more than one embed'); $this->logger->debug(' 1 embed and content length smaller than 75 chars, or more than one embed');
$toRemove = true; $toRemove = true;
} }
@@ -1370,10 +1396,10 @@ class Readability implements LoggerAwareInterface
* *
* @param \DOMElement $e * @param \DOMElement $e
*/ */
public function cleanHeaders(\DOMElement $e) public function cleanHeaders($e)
{ {
for ($headerIndex = 1; $headerIndex < 3; ++$headerIndex) { for ($headerIndex = 1; $headerIndex < 3; ++$headerIndex) {
$headers = $e->getElementsByTagName('h'.$headerIndex); $headers = $e->getElementsByTagName('h' . $headerIndex);
for ($i = $headers->length - 1; $i >= 0; --$i) { for ($i = $headers->length - 1; $i >= 0; --$i) {
if ($this->getWeight($headers->item($i)) < 0 || $this->getLinkDensity($headers->item($i)) > 0.33) { if ($this->getWeight($headers->item($i)) < 0 || $this->getLinkDensity($headers->item($i)) > 0.33) {
+53 -31
View File
@@ -2,9 +2,9 @@
namespace Tests\Readability; namespace Tests\Readability;
use Readability\Readability;
use Monolog\Logger;
use Monolog\Handler\TestHandler; use Monolog\Handler\TestHandler;
use Monolog\Logger;
use Readability\Readability;
class ReadabilityTest extends \PHPUnit_Framework_TestCase class ReadabilityTest extends \PHPUnit_Framework_TestCase
{ {
@@ -22,40 +22,47 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
return $readability; return $readability;
} }
/**
* @requires extension tidy
*/
public function testConstructDefault()
{
$readability = $this->getReadability('');
$this->assertNull($readability->url);
$this->assertInstanceOf('DomDocument', $readability->dom);
}
/**
* @requires extension tidy
*/
public function testConstructSimple() public function testConstructSimple()
{ {
$readability = $this->getReadability('<html/>', 'http://0.0.0.0'); $readability = $this->getReadability('<html/>', 'http://0.0.0.0');
$readability->init();
$this->assertEquals('http://0.0.0.0', $readability->url); $this->assertEquals('http://0.0.0.0', $readability->url);
$this->assertInstanceOf('DomDocument', $readability->dom);
$this->assertEquals('<html/>', $readability->original_html); $this->assertEquals('<html/>', $readability->original_html);
$this->assertTrue($readability->tidied); $this->assertTrue($readability->tidied);
$this->assertTrue($this->logHandler->hasDebugThatContains('Parsing URL: http://0.0.0.0'));
$this->assertTrue($this->logHandler->hasDebugThatContains('Tidying document'));
$this->assertTrue($this->logHandler->hasDebugThatContains('Light clean enabled.'));
} }
public function testConstructDefaultWithoutTidy() public function testConstructDefaultWithoutTidy()
{ {
$readability = $this->getReadability('', null, 'libxml', false); $readability = $this->getReadability('', null, 'libxml', false);
$readability->init();
$this->assertNull($readability->url); $this->assertNull($readability->url);
$this->assertEquals('', $readability->original_html); $this->assertEquals('', $readability->original_html);
$this->assertFalse($readability->tidied); $this->assertFalse($readability->tidied);
$this->assertTrue($this->logHandler->hasDebugThatContains('Parsing URL: ')); $this->assertInstanceOf('DomDocument', $readability->dom);
$this->assertFalse($this->logHandler->hasDebugThatContains('Tidying document'));
$this->assertTrue($this->logHandler->hasDebugThatContains('Light clean enabled.'));
} }
public function testConstructSimpleWithoutTidy() public function testConstructSimpleWithoutTidy()
{ {
$readability = $this->getReadability('<html/>', 'http://0.0.0.0', 'libxml', false); $readability = $this->getReadability('<html/>', 'http://0.0.0.0', 'libxml', false);
$readability->init();
$this->assertEquals('http://0.0.0.0', $readability->url); $this->assertEquals('http://0.0.0.0', $readability->url);
$this->assertInstanceOf('DomDocument', $readability->dom);
$this->assertEquals('<html/>', $readability->original_html); $this->assertEquals('<html/>', $readability->original_html);
$this->assertFalse($readability->tidied); $this->assertFalse($readability->tidied);
} }
@@ -87,7 +94,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testInitDivP() public function testInitDivP()
{ {
$readability = $this->getReadability('<div>'.str_repeat('<p>This is the awesome content :)</p>', 7).'</div>', 'http://0.0.0.0'); $readability = $this->getReadability('<div>' . str_repeat('<p>This is the awesome content :)</p>', 7) . '</div>', 'http://0.0.0.0');
$res = $readability->init(); $res = $readability->init();
$this->assertTrue($res); $this->assertTrue($res);
@@ -100,7 +107,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testInitDiv() public function testInitDiv()
{ {
$readability = $this->getReadability('<div>'.str_repeat('This is the awesome content :)', 7).'</div>', 'http://0.0.0.0'); $readability = $this->getReadability('<div>' . str_repeat('This is the awesome content :)', 7) . '</div>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -114,7 +121,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithFootnotes() public function testWithFootnotes()
{ {
$readability = $this->getReadability('<div>'.str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7).'</div>', 'http://0.0.0.0'); $readability = $this->getReadability('<div>' . str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7) . '</div>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$readability->convertLinksToFootnotes = true; $readability->convertLinksToFootnotes = true;
$res = $readability->init(); $res = $readability->init();
@@ -131,7 +138,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testStandardClean() public function testStandardClean()
{ {
$readability = $this->getReadability('<div><h2>Title</h2>'.str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7).'<a href="#nofollow" rel="nofollow">will NOT be removed</a></div>', 'http://0.0.0.0'); $readability = $this->getReadability('<div><h2>Title</h2>' . str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7) . '<a href="#nofollow" rel="nofollow">will NOT be removed</a></div>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$readability->lightClean = false; $readability->lightClean = false;
$res = $readability->init(); $res = $readability->init();
@@ -148,7 +155,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithIframe() public function testWithIframe()
{ {
$readability = $this->getReadability('<div><h2>Title</h2>'.str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7).'<p>This is an awesome text with some links, here there are <iframe src="http://youtube.com/test" href="#nofollow" rel="nofollow"></iframe><iframe>http://soundcloud.com/test</iframe></p></div>', 'http://0.0.0.0'); $readability = $this->getReadability('<div><h2>Title</h2>' . str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7) . '<p>This is an awesome text with some links, here there are <iframe src="http://youtube.com/test" href="#nofollow" rel="nofollow"></iframe><iframe>http://soundcloud.com/test</iframe></p></div>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -163,7 +170,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithArticle() public function testWithArticle()
{ {
$readability = $this->getReadability('<article><p>'.str_repeat('This is an awesome text with some links, here there are: the awesome', 20).'</p><p>This is an awesome text with some links, here there are <iframe src="http://youtube.com/test" href="#nofollow" rel="nofollow"></iframe></p></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<article><p>' . str_repeat('This is an awesome text with some links, here there are: the awesome', 20) . '</p><p>This is an awesome text with some links, here there are <iframe src="http://youtube.com/test" href="#nofollow" rel="nofollow"></iframe></p></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -178,7 +185,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithAside() public function testWithAside()
{ {
$readability = $this->getReadability('<article>'.str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7).'<footer><aside>'.str_repeat('<p>This is an awesome text with some links, here there are</p>', 8).'</aside></footer></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<article>' . str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7) . '<footer><aside>' . str_repeat('<p>This is an awesome text with some links, here there are</p>', 8) . '</aside></footer></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -193,7 +200,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithClasses() public function testWithClasses()
{ {
$readability = $this->getReadability('<article>'.str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7).'<div style="display:none">'.str_repeat('<p class="clock">This text should be removed</p>', 10).'</div></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<article>' . str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7) . '<div style="display:none">' . str_repeat('<p class="clock">This text should be removed</p>', 10) . '</div></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -208,7 +215,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithClassesWithoutLightClean() public function testWithClassesWithoutLightClean()
{ {
$readability = $this->getReadability('<article>'.str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7).'<div style="display:none">'.str_repeat('<p class="clock">This text should be removed</p>', 10).'</div></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<article>' . str_repeat('<p>This is an awesome text with some links, here there are: <a href="http://0.0.0.0/test.html">the awesome</a></p>', 7) . '<div style="display:none">' . str_repeat('<p class="clock">This text should be removed</p>', 10) . '</div></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$readability->lightClean = false; $readability->lightClean = false;
$res = $readability->init(); $res = $readability->init();
@@ -224,7 +231,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithTd() public function testWithTd()
{ {
$readability = $this->getReadability('<table><tr>'.str_repeat('<td><p>This is an awesome text with some links, here there are the awesome</td>', 7).'</tr></table>', 'http://0.0.0.0'); $readability = $this->getReadability('<table><tr>' . str_repeat('<td><p>This is an awesome text with some links, here there are the awesome</td>', 7) . '</tr></table>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -237,7 +244,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithSameClasses() public function testWithSameClasses()
{ {
$readability = $this->getReadability('<article class="awesomecontent">'.str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7).'<div class="awesomecontent">This text is also an awesome text and you should know that !</div></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<article class="awesomecontent">' . str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7) . '<div class="awesomecontent">This text is also an awesome text and you should know that !</div></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -251,7 +258,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testWithScript() public function testWithScript()
{ {
$readability = $this->getReadability('<article class="awesomecontent">'.str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7).'<p><script>This text is also an awesome text and you should know that !</script></p></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<article class="awesomecontent">' . str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7) . '<p><script>This text is also an awesome text and you should know that !</script></p></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -265,7 +272,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testTitle() public function testTitle()
{ {
$readability = $this->getReadability('<title>this is my title</title><article class="awesomecontent">'.str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7).'<p></p></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<title>this is my title</title><article class="awesomecontent">' . str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7) . '<p></p></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -279,7 +286,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testTitleWithDash() public function testTitleWithDash()
{ {
$readability = $this->getReadability('<title> title2 - title3 </title><article class="awesomecontent">'.str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7).'<p></p></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<title> title2 - title3 </title><article class="awesomecontent">' . str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7) . '<p></p></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -293,7 +300,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testTitleWithDoubleDot() public function testTitleWithDoubleDot()
{ {
$readability = $this->getReadability('<title> title2 : title3 </title><article class="awesomecontent">'.str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7).'<p></p></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<title> title2 : title3 </title><article class="awesomecontent">' . str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7) . '<p></p></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -307,7 +314,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testTitleTooShortUseH1() public function testTitleTooShortUseH1()
{ {
$readability = $this->getReadability('<title>too short</title><h1>this is my h1 title !</h1><article class="awesomecontent">'.str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7).'<p></p></article>', 'http://0.0.0.0'); $readability = $this->getReadability('<title>too short</title><h1>this is my h1 title !</h1><article class="awesomecontent">' . str_repeat('<p>This is an awesome text with some links, here there are the awesome</p>', 7) . '<p></p></article>', 'http://0.0.0.0');
$readability->debug = true; $readability->debug = true;
$res = $readability->init(); $res = $readability->init();
@@ -376,7 +383,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* This should generate an Exception "DOMElement::setAttribute(): ID post-60 already defined" * This should generate an Exception "DOMElement::setAttribute(): ID post-60 already defined".
*/ */
public function testAppendIdAlreadyHere() public function testAppendIdAlreadyHere()
{ {
@@ -436,7 +443,7 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testPostFilters() public function testPostFilters()
{ {
$readability = $this->getReadability('<div>'.str_repeat('<p>This <b>is</b> the awesome content :)</p>', 7).'</div>', 'http://0.0.0.0'); $readability = $this->getReadability('<div>' . str_repeat('<p>This <b>is</b> the awesome content :)</p>', 7) . '</div>', 'http://0.0.0.0');
$readability->addPostFilter('!<strong[^>]*>(.*?)</strong>!is', ''); $readability->addPostFilter('!<strong[^>]*>(.*?)</strong>!is', '');
$res = $readability->init(); $res = $readability->init();
@@ -447,7 +454,9 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
public function testPreFilters() public function testPreFilters()
{ {
$readability = $this->getReadability('<div>'.str_repeat('<p>This <b>is</b> the awesome and WONDERFUL content :)</p>', 7).'</div>', 'http://0.0.0.0'); $this->markTestSkipped('Won\'t work until loadHtml() is moved in init() instead of __construct()');
$readability = $this->getReadability('<div>' . str_repeat('<p>This <b>is</b> the awesome and WONDERFUL content :)</p>', 7) . '</div>', 'http://0.0.0.0');
$readability->addPreFilter('!<b[^>]*>(.*?)</b>!is', ''); $readability->addPreFilter('!<b[^>]*>(.*?)</b>!is', '');
$res = $readability->init(); $res = $readability->init();
@@ -455,4 +464,17 @@ class ReadabilityTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($res); $this->assertTrue($res);
$this->assertContains('This the awesome and WONDERFUL content :)', $readability->getContent()->innerHTML); $this->assertContains('This the awesome and WONDERFUL content :)', $readability->getContent()->innerHTML);
} }
public function testChildNodeGoneNull()
{
// from http://www.ayyaantuu.net/ethiopia-targets-opposition-lawmakers/
$html = file_get_contents('tests/fixtures/childNodeGoesNull.html');
$readability = $this->getReadability($html, 'http://0.0.0.0');
$readability->debug = true;
$readability->convertLinksToFootnotes = true;
$res = $readability->init();
$this->assertTrue($res);
}
} }
+137
View File
@@ -0,0 +1,137 @@
<div id="main-sidebar-container">
<!-- #main Starts -->
<section id="main">
<?php if (function_exists ('adinserter')) echo adinserter (1); ?><article class="post-23842 post type-post status-publish format-standard hentry category-ethiopia">
<header>
<h1 class="title entry-title">Ethiopia targets opposition who met with European lawmakers</h1> </header>
<div class="post-meta"><span class="Small"><abbr class="date time published updated" title="2017-01-09T15:25:17-0500">January 9, 2017</abbr> <span class="Small">in</span> <span class="categories"><a href="http://www.ayyaantuu.net/category/horn-of-africa/ethiopia/" title="View all items in Ethiopia">Ethiopia</a></span> </div>
<section class="entry">
<div id="fb-root"></div>
<p><strong>Ethiopia targets opposition who met with European lawmakers</strong></p>
<p><span class="dateline"><img class="alignleft wp-image-22789 size-full" src="http://www.ayyaantuu.net/wp-content/uploads/2016/12/Ana-Gomes-Merera-Gudina.jpg" alt="Ethiopia targets opposition who met with European lawmakers" width="300" height="160" srcset="http://www.ayyaantuu.net/wp-content/uploads/2016/12/Ana-Gomes-Merera-Gudina.jpg 300w, http://www.ayyaantuu.net/wp-content/uploads/2016/12/Ana-Gomes-Merera-Gudina-200x107.jpg 200w" sizes="(max-width: 300px) 100vw, 300px" />ADDIS ABABA (<a href="http://www.foxnews.com/world/2017/01/09/ethiopia-targets-opposition-who-met-with-european-lawmakers.html">Fox News</a>) – </span>Ethiopia says it will not release a leading opposition figure detained under the country’s state of emergency after meeting with European lawmakers in Belgium.</p>
<!-- WP QUADS Content Ad Plugin v. 1.3.9 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:left;margin:2px 2px 2px 0;">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Ad2016_12_14_3 -->
<ins class="adsbygoogle"
style="display:inline-block;width:336px;height:280px"
data-ad-client="ca-pub-6953193962442323"
data-ad-slot="4950645476"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
<p>Prime Minister Hailemariam Desalegn told reporters on Monday that Merara Gudina of the Oromo Federalist Congress party instead will face justice.</p>
<p>The prime minister says “individuals in the European Parliament who are harboring anti-peace elements cannot save those who trespass the law of the country.”</p>
<p>Merara is one of 22,000 people the prime minister says were detained under the state of emergency declared in October after widespread anti-government protests.</p>
<p>Merara was arrested immediately after he returned from Belgium. He was accused of meeting with members of an armed Ethiopian opposition group in Brussels, an act banned under the emergency law.</p>
<div style="font-size:0px;height:0px;line-height:0px;margin:0;padding:0;clear:both"></div><aside class="mashsb-container mashsb-main "><div class="mashsb-box"><div class="mashsb-count mash-small" style="float:left;"><div class="counts mashsbcount">0</div><span class="mashsb-sharetext">SHARES</span></div><div class="mashsb-buttons"><a class="mashicon-facebook mash-small" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.ayyaantuu.net%2Fethiopia-targets-opposition-lawmakers%2F" target="_blank" rel="nofollow"><span class="icon"></span><span class="text">Share</span></a><a class="mashicon-twitter mash-small" href="https://twitter.com/intent/tweet?text=Ethiopia%20targets%20opposition%20who%20met%20with%20European%20lawmakers&url=http://www.ayyaantuu.net/?p=23842&via= ayyaantuu" target="_blank" rel="nofollow"><span class="icon"></span><span class="text">Tweet</span></a><div class="onoffswitch mash-small"></div><div class="secondary-shares" style="display:none;"><a class="mashicon-subscribe mash-small" href="#" target="_blank" rel="nofollow"><span class="icon"></span><span class="text">Subscribe</span></a><div class="onoffswitch2 mash-small" style="display:none;"></div></div></div>
</div>
<div style="clear:both;"></div><div class="mashsb-toggle-container"></div></aside>
<!-- Share buttons by mashshare.net - Version: 3.3.6--> </section><!-- /.entry -->
<div class="fix"></div>
<aside id="connect">
<h3>Subscribe</h3>
<div class="col-left">
<p>Subscribe to our e-mail newsletter to receive updates.</p>
<div class="social">
<a href="http://www.ayyaantuu.net/feed/" class="subscribe" title="RSS"></a>
<a target="_blank" href="https://twitter.com/ayyaantuu" class="twitter" title="Twitter"></a>
<a target="_blank" href="https://www.facebook.com/ayyaantuu.oromiyaa" class="facebook" title="Facebook"></a>
</div>
</div><!-- col-left -->
<div class="related-posts col-right">
<h4>Related Posts:</h4>
<div class="woo-sc-related-posts">
<ul>
<li class="post-id-23812">
<a href="http://www.ayyaantuu.net/country-new-african-millionaire/" title="Africa Business: The life of TPLF millionaire in Oromia/Ethiopia?" class="related-title"><span>Africa Business: The life of TPLF millionaire in Oromia/Ethiopia?</span></a>
</li>
<li class="post-id-23794">
<a href="http://www.ayyaantuu.net/ethiopian-girl-band-funding-axed-uk/" title="Ethiopian girl band Yegna&#8217;s funding axed by UK &#8211; BBC News" class="related-title"><span>Ethiopian girl band Yegna&#8217;s funding axed by UK &#8211; BBC News</span></a>
</li>
<li class="post-id-23783">
<a href="http://www.ayyaantuu.net/infrastructure-led-chinese-approach/" title="Ethiopia’s political ripple a big test for infrastructure-led Chinese approach" class="related-title"><span>Ethiopia’s political ripple a big test for infrastructure-led Chinese approach</span></a>
</li>
<li class="post-id-23766">
<a href="http://www.ayyaantuu.net/defense-witness-testimonials/" title="Defense Witness Testimonials on Yonatan Tesfaye’s Terrorism Charges" class="related-title"><span>Defense Witness Testimonials on Yonatan Tesfaye’s Terrorism Charges</span></a>
</li>
<li class="post-id-23745">
<a href="http://www.ayyaantuu.net/foreign-government-internet-shutdowns-soared-2016/" title="Foreign government internet shutdowns soared in 2016" class="related-title"><span>Foreign government internet shutdowns soared in 2016</span></a>
</li>
</ul>
<div class="fix"></div><!--/.fix-->
</div><!--/.woo-sc-related-posts--> </div><!-- col-right -->
<div class="fix"></div>
</aside>
<div class="post-utility"></div>
</article><!-- /.post -->
<div class="post-entries">
<div class="nav-prev fl"><a href="http://www.ayyaantuu.net/many-bombs-united-states-dropped-2016/" rel="prev"><i class="fa fa-angle-left"></i> How Many Bombs the United States Dropped in 2016?</a></div>
<div class="nav-next fr"><a href="http://www.ayyaantuu.net/rockefeller-conspiracy-one-world-order/" rel="next">David Rockefeller Says Conspiracy About ‘One World Order’ Is True <i class="fa fa-angle-right"></i></a></div>
<div class="fix"></div>
</div>
<?php if (function_exists ('adinserter')) echo adinserter (1); ?><div id="comments"> <h3 id="comments-title">One Response to <em>Ethiopia targets opposition who met with European lawmakers</em></h3>
<ol class="commentlist">
<li id="comment-30772" class="comment even thread-even depth-1">
<div id="li-comment-30772" class="comment-container">
<div class="avatar"></div>
<div class="comment-head">
<span class="name">Addis Zemen</span>
<span class="date">January 9, 2017 at 5:57 pm</span>
<span class="perma"><a href="http://www.ayyaantuu.net/ethiopia-targets-opposition-lawmakers/#comment-30772" title="Direct link to this comment">#</a></span>
<span class="edit"></span>
</div><!-- /.comment-head -->
<div class="comment-entry">
<p>10,000 people that were areested in Oromia got released. When the people were arrested it was under the assumption “Violence broke out during an Oromo religious festival, and in some instances foreigners seem to have been targeted. ”</p>
<p>But now many prosecutors agree Violence was not the case. The people at the Erecha celebration thought aliens invaded their country. They thought the foreigners were aliens from another planet.<br />
Close to a thousand threw themselves of a cliff just because they saw a helicopter flying near them. Many are paralized hundreds died. Now the injured are trying to blame the helicopter pilot for their injuries by saying the pilot caused their injuries by scaring them, flying like an alien abductor UFO would . After the prosecutor agreed it was an accident or suicide that caused the deaths of hundreds of people at the Erecha celebration, the suspected 10,000 prisoners got released. The prosecutors are blaming those that spoke with the European parliament for spreading false information about what really happened at the Erecha celebration.</p>
<div class="reply">
<a rel='nofollow' class='comment-reply-link' href='http://www.ayyaantuu.net/ethiopia-targets-opposition-lawmakers/?replytocom=30772#respond' onclick='return addComment.moveForm( "comment-30772", "30772", "respond", "23842" )' aria-label='Reply to Addis Zemen'>Reply</a> </div><!-- /.reply -->
</div><!-- /comment-entry -->
</div><!-- /.comment-container -->
</li><!-- #comment-## -->
</ol>
</div> <div id="respond" class="comment-respond">
<h3 id="reply-title" class="comment-reply-title">Leave a Reply <small><a rel="nofollow" id="cancel-comment-reply-link" href="/ethiopia-targets-opposition-lawmakers/#respond" style="display:none;">Click here to cancel reply.</a></small></h3> <form action="http://www.ayyaantuu.net/wp-comments-post.php" method="post" id="commentform" class="comment-form">
<p class="comment-form-comment"><label class="hide" for="comment">Comment</label> <textarea tabindex="4" id="comment" name="comment" cols="50" rows="10" maxlength="65525" aria-required="true" required="required"></textarea></p><p class="comment-form-author"><input id="author" name="author" type="text" class="txt" tabindex="1" value="" size="30" aria-required='true' /><label for="author">Name <span class="required">(required)</span></label> </p>
<p class="comment-form-email"><input id="email" name="email" type="text" class="txt" tabindex="2" value="" size="30" aria-required='true' /><label for="email">Email (will not be published) <span class="required">(required)</span></label> </p>
<p class="comment-form-url"><input id="url" name="url" type="text" class="txt" tabindex="3" value="" size="30" /><label for="url">Website</label></p>
<p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Submit Comment" /> <input type='hidden' name='comment_post_ID' value='23842' id='comment_post_ID' />
<input type='hidden' name='comment_parent' id='comment_parent' value='0' />
</p><p style="display: none;"><input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="39bacbf69e" /></p><p style="display: none;"><input type="hidden" id="ak_js" name="ak_js" value="66"/></p> </form>
</div><!-- #respond -->
</section><!-- /#main -->