mirror of
				https://github.com/getgrav/grav-plugin-admin.git
				synced 2025-10-31 02:16:26 +01:00 
			
		
		
		
	two factor authentication essental elements
This commit is contained in:
		| @@ -5,6 +5,7 @@ theme: grav | |||||||
| logo_text: '' | logo_text: '' | ||||||
| body_classes: '' | body_classes: '' | ||||||
| content_padding: true | content_padding: true | ||||||
|  | twofa_enabled: true | ||||||
| sidebar: | sidebar: | ||||||
|   activate: tab |   activate: tab | ||||||
|   hover_delay: 100 |   hover_delay: 100 | ||||||
|   | |||||||
| @@ -48,6 +48,18 @@ form: | |||||||
|       validate: |       validate: | ||||||
|           type: bool |           type: bool | ||||||
|  |  | ||||||
|  |     twofa_enabled: | ||||||
|  |       type: toggle | ||||||
|  |       label: PLUGIN_ADMIN.2FA_TITLE | ||||||
|  |       help: PLUGIN_ADMIN.2FA_ENABLED_HELP | ||||||
|  |       default: 0 | ||||||
|  |       highlight: 0 | ||||||
|  |       options: | ||||||
|  |           1: PLUGIN_ADMIN.YES | ||||||
|  |           0: PLUGIN_ADMIN.NO | ||||||
|  |       validate: | ||||||
|  |           type: bool | ||||||
|  |  | ||||||
|     route: |     route: | ||||||
|       type: text |       type: text | ||||||
|       label: Administrator path |       label: Administrator path | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ use RocketTheme\Toolbox\Session\Session; | |||||||
| use Symfony\Component\Yaml\Yaml; | use Symfony\Component\Yaml\Yaml; | ||||||
| use Composer\Semver\Semver; | use Composer\Semver\Semver; | ||||||
| use PicoFeed\Reader\Reader; | use PicoFeed\Reader\Reader; | ||||||
|  | use RobThree\Auth\TwoFactorAuth; | ||||||
|  |  | ||||||
| define('LOGIN_REDIRECT_COOKIE', 'grav-login-redirect'); | define('LOGIN_REDIRECT_COOKIE', 'grav-login-redirect'); | ||||||
|  |  | ||||||
| @@ -377,6 +378,17 @@ class Admin | |||||||
|         $action = []; |         $action = []; | ||||||
|  |  | ||||||
|         if ($user->authorize('admin.login')) { |         if ($user->authorize('admin.login')) { | ||||||
|  |  | ||||||
|  |             $twofa_admin_enabled = $this->grav['config']->get('plugins.admin.twofa_enabled', false); | ||||||
|  |  | ||||||
|  |             if ($twofa_admin_enabled && isset($user->twofa_enabled) && $user->twofa_enabled == true) { | ||||||
|  |                 $twofa = $this->get2FA(); | ||||||
|  |                 $secret = isset($user->twofa_secret) ? $user->twofa_secret : null; | ||||||
|  |                 if (!(isset($data['2fa_code']) && $data['2fa_code'] == $twofa->getCode($secret))) { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|             $this->user = $this->session->user = $user; |             $this->user = $this->session->user = $user; | ||||||
|  |  | ||||||
|             /** @var Grav $grav */ |             /** @var Grav $grav */ | ||||||
| @@ -1709,4 +1721,9 @@ class Admin | |||||||
|  |  | ||||||
|         return $pagesWithFiles; |         return $pagesWithFiles; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function get2FA() | ||||||
|  |     { | ||||||
|  |         return new TwoFactorAuth($this->grav['config']->get('site.title')); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| { | { | ||||||
|     "require": { |     "require": { | ||||||
|         "composer/semver": "^1.4", |         "composer/semver": "^1.4", | ||||||
|         "fguillot/picofeed": "@stable" |         "fguillot/picofeed": "@stable", | ||||||
|  |         "robthree/twofactorauth": "^1.6" | ||||||
|     }, |     }, | ||||||
|     "require-dev": { |     "require-dev": { | ||||||
|         "codeception/codeception": "^2.1", |         "codeception/codeception": "^2.1", | ||||||
|   | |||||||
							
								
								
									
										933
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										933
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -682,3 +682,9 @@ PLUGIN_ADMIN: | |||||||
|   CONTENT_PADDING_HELP: "Enable/Disable content padding around content area to provide more space" |   CONTENT_PADDING_HELP: "Enable/Disable content padding around content area to provide more space" | ||||||
|   ENABLE_AUTO_METADATA: "Auto metadata from Exif" |   ENABLE_AUTO_METADATA: "Auto metadata from Exif" | ||||||
|   ENABLE_AUTO_METADATA_HELP: "Automatically generate metadata files for images with exif information" |   ENABLE_AUTO_METADATA_HELP: "Automatically generate metadata files for images with exif information" | ||||||
|  |   2FA_TITLE: "2-Factor Authentication" | ||||||
|  |   2FA_LABEL: "Admin Access" | ||||||
|  |   2FA_ENABLED: "2FA Enabled" | ||||||
|  |   2FA_CODE_INPUT: "2FA Code (if enabled)" | ||||||
|  |   2FA_SECRET: "2FA Secret" | ||||||
|  |   2FA_SECRET_HELP: "Scan this code into your Authenticator App or enter the code manually.  Check the Grav docs for  more information" | ||||||
|   | |||||||
| @@ -7,16 +7,26 @@ form: | |||||||
|     method: post |     method: post | ||||||
|  |  | ||||||
|     fields: |     fields: | ||||||
|         - name: username |         username: | ||||||
|           type: text |             type: text | ||||||
|           placeholder: PLUGIN_ADMIN.USERNAME_EMAIL |             placeholder: PLUGIN_ADMIN.USERNAME_EMAIL | ||||||
|           autofocus: true |             autofocus: true | ||||||
|           validate: |             validate: | ||||||
|             required: true |                 required: true | ||||||
|  |  | ||||||
|         - name: password |         password: | ||||||
|           type: password |             type: password | ||||||
|           placeholder: PLUGIN_ADMIN.PASSWORD |             placeholder: PLUGIN_ADMIN.PASSWORD | ||||||
|           validate: |             validate: | ||||||
|             required: true |                 required: true | ||||||
|  |              | ||||||
|  |         twofa_check: | ||||||
|  |             type: conditional | ||||||
|  |             condition: config.plugins.admin.twofa_enabled     | ||||||
|  |             | ||||||
|  |             fields: | ||||||
|  |             | ||||||
|  |                 2fa_code: | ||||||
|  |                     type: text | ||||||
|  |                     placeholder: PLUGIN_ADMIN.2FA_CODE_INPUT    | ||||||
| --- | --- | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								themes/grav/css-compiled/preset.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								themes/grav/css-compiled/preset.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								themes/grav/css-compiled/template.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								themes/grav/css-compiled/template.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -967,8 +967,8 @@ form { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     &.switch-toggle input:checked + label { |     &.switch-toggle input:checked + label { | ||||||
|         background: #777; |         color: $content-bg; | ||||||
|         color: #fff; |         background: $content-text; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -635,8 +635,10 @@ textarea.frontmatter { | |||||||
|         height: 39px; |         height: 39px; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     .switch-toggle label { |     .switch-toggle { | ||||||
|         white-space: nowrap; |         line-height: 37px; | ||||||
|  |         margin: 0 5px 5px 0; | ||||||
|  |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -131,3 +131,17 @@ | |||||||
|         padding: 1rem 3rem; |         padding: 1rem 3rem; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .twofa-secret { | ||||||
|  |     position: absolute; | ||||||
|  |     opacity: 0; | ||||||
|  |     visibility: hidden; | ||||||
|  |     transition: opacity 600ms, visibility 600ms; | ||||||
|  |  | ||||||
|  |     &.show { | ||||||
|  |         position: static; | ||||||
|  |         visibility: visible; | ||||||
|  |         opacity: 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ | |||||||
|         display: inline-block; |         display: inline-block; | ||||||
|         cursor: pointer; |         cursor: pointer; | ||||||
|         padding: 0 15px; |         padding: 0 15px; | ||||||
|  |         white-space: nowrap; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,32 @@ | |||||||
|  | {% extends "forms/field.html.twig" %} | ||||||
|  |  | ||||||
|  | {% block input %} | ||||||
|  |     <div class="form-input-wrapper 2fa-wrapper"> | ||||||
|  |         {% set two_fa = admin.get2FA() %} | ||||||
|  |         {% set value = (value is null ? two_fa.createSecret(160) : value) %} | ||||||
|  |  | ||||||
|  |         <img style="border: 1px solid #ddd" src="{{ two_fa.getQRCodeImageAsDataUri(grav.user.email, value) }}" /> | ||||||
|  |         <div class="2fa-secret">{{ value|chunkSplit(4, ' ') }}</div> | ||||||
|  |  | ||||||
|  |         <input type="text" style="display:none;" name="{{ (scope ~ field.name)|fieldName }}" value="{{ value|join(', ') }}" /> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <script> | ||||||
|  |         function twofaVisiblity() { | ||||||
|  |             console.log('clicked'); | ||||||
|  |             if ($('#toggle_twofa_enabled1').is(':checked')) { | ||||||
|  |                 console.log('checked'); | ||||||
|  |                 $('.twofa-secret').addClass("show"); | ||||||
|  |             } else { | ||||||
|  |                 console.log('unchecked'); | ||||||
|  |                 $('.twofa-secret').removeClass("show"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $( document ).ready(function() { | ||||||
|  |             twofaVisiblity(); | ||||||
|  |             $('.twofa-toggle input').click(twofaVisiblity); | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |     </script> | ||||||
|  | {% endblock %} | ||||||
| @@ -22,7 +22,7 @@ | |||||||
|  |  | ||||||
| {% block input %} | {% block input %} | ||||||
|  |  | ||||||
|     <div class="switch-toggle switch-grav {{ field.size }} switch-{{ field.options|length }}"> |     <div class="switch-toggle switch-grav {{ field.size }} switch-{{ field.options|length }} {{ field.classes }}"> | ||||||
|         {% set maxLen = 0 %} |         {% set maxLen = 0 %} | ||||||
|         {% for text in field.options %} |         {% for text in field.options %} | ||||||
|             {% set translation = grav.twig.twig.filters['tu'] is defined ? text|tu : text|t %} |             {% set translation = grav.twig.twig.filters['tu'] is defined ? text|tu : text|t %} | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ class AdminTwigExtension extends \Twig_Extension | |||||||
|             new \Twig_SimpleFilter('toYaml', [$this, 'toYamlFilter']), |             new \Twig_SimpleFilter('toYaml', [$this, 'toYamlFilter']), | ||||||
|             new \Twig_SimpleFilter('fromYaml', [$this, 'fromYamlFilter']), |             new \Twig_SimpleFilter('fromYaml', [$this, 'fromYamlFilter']), | ||||||
|             new \Twig_SimpleFilter('adminNicetime', [$this, 'adminNicetimeFilter']), |             new \Twig_SimpleFilter('adminNicetime', [$this, 'adminNicetimeFilter']), | ||||||
|  |             new \Twig_SimpleFilter('chunkSplit', [$this, 'chunkSplitFilter']), | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -181,4 +181,9 @@ class AdminTwigExtension extends \Twig_Extension | |||||||
|  |  | ||||||
|         return "$difference $periods[$j] {$tense}"; |         return "$difference $periods[$j] {$tense}"; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function chunkSplitFilter($value, $chars, $split = '-') | ||||||
|  |     { | ||||||
|  |         return chunk_split($value, $chars, $split); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								vendor/autoload.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/autoload.php
									
									
									
									
										vendored
									
									
								
							| @@ -2,6 +2,6 @@ | |||||||
|  |  | ||||||
| // autoload.php @generated by Composer | // autoload.php @generated by Composer | ||||||
|  |  | ||||||
| require_once __DIR__ . '/composer' . '/autoload_real.php'; | require_once __DIR__ . '/composer/autoload_real.php'; | ||||||
|  |  | ||||||
| return ComposerAutoloaderInitef6e9937a63bd796f32542b02941ee0e::getLoader(); | return ComposerAutoloaderInitf3438a4bfc092aad40a104edf0a3eb02::getLoader(); | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								vendor/composer/ClassLoader.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								vendor/composer/ClassLoader.php
									
									
									
									
										vendored
									
									
								
							| @@ -53,8 +53,9 @@ class ClassLoader | |||||||
|  |  | ||||||
|     private $useIncludePath = false; |     private $useIncludePath = false; | ||||||
|     private $classMap = array(); |     private $classMap = array(); | ||||||
|  |  | ||||||
|     private $classMapAuthoritative = false; |     private $classMapAuthoritative = false; | ||||||
|  |     private $missingClasses = array(); | ||||||
|  |     private $apcuPrefix; | ||||||
|  |  | ||||||
|     public function getPrefixes() |     public function getPrefixes() | ||||||
|     { |     { | ||||||
| @@ -271,6 +272,26 @@ class ClassLoader | |||||||
|         return $this->classMapAuthoritative; |         return $this->classMapAuthoritative; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * APCu prefix to use to cache found/not-found classes, if the extension is enabled. | ||||||
|  |      * | ||||||
|  |      * @param string|null $apcuPrefix | ||||||
|  |      */ | ||||||
|  |     public function setApcuPrefix($apcuPrefix) | ||||||
|  |     { | ||||||
|  |         $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The APCu prefix in use, or null if APCu caching is not enabled. | ||||||
|  |      * | ||||||
|  |      * @return string|null | ||||||
|  |      */ | ||||||
|  |     public function getApcuPrefix() | ||||||
|  |     { | ||||||
|  |         return $this->apcuPrefix; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Registers this instance as an autoloader. |      * Registers this instance as an autoloader. | ||||||
|      * |      * | ||||||
| @@ -313,29 +334,34 @@ class ClassLoader | |||||||
|      */ |      */ | ||||||
|     public function findFile($class) |     public function findFile($class) | ||||||
|     { |     { | ||||||
|         // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 |  | ||||||
|         if ('\\' == $class[0]) { |  | ||||||
|             $class = substr($class, 1); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // class map lookup |         // class map lookup | ||||||
|         if (isset($this->classMap[$class])) { |         if (isset($this->classMap[$class])) { | ||||||
|             return $this->classMap[$class]; |             return $this->classMap[$class]; | ||||||
|         } |         } | ||||||
|         if ($this->classMapAuthoritative) { |         if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |         if (null !== $this->apcuPrefix) { | ||||||
|  |             $file = apcu_fetch($this->apcuPrefix.$class, $hit); | ||||||
|  |             if ($hit) { | ||||||
|  |                 return $file; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $file = $this->findFileWithExtension($class, '.php'); |         $file = $this->findFileWithExtension($class, '.php'); | ||||||
|  |  | ||||||
|         // Search for Hack files if we are running on HHVM |         // Search for Hack files if we are running on HHVM | ||||||
|         if ($file === null && defined('HHVM_VERSION')) { |         if (false === $file && defined('HHVM_VERSION')) { | ||||||
|             $file = $this->findFileWithExtension($class, '.hh'); |             $file = $this->findFileWithExtension($class, '.hh'); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ($file === null) { |         if (null !== $this->apcuPrefix) { | ||||||
|  |             apcu_add($this->apcuPrefix.$class, $file); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (false === $file) { | ||||||
|             // Remember that this class does not exist. |             // Remember that this class does not exist. | ||||||
|             return $this->classMap[$class] = false; |             $this->missingClasses[$class] = true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $file; |         return $file; | ||||||
| @@ -348,9 +374,13 @@ class ClassLoader | |||||||
|  |  | ||||||
|         $first = $class[0]; |         $first = $class[0]; | ||||||
|         if (isset($this->prefixLengthsPsr4[$first])) { |         if (isset($this->prefixLengthsPsr4[$first])) { | ||||||
|             foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { |             $subPath = $class; | ||||||
|                 if (0 === strpos($class, $prefix)) { |             while (false !== $lastPos = strrpos($subPath, '\\')) { | ||||||
|                     foreach ($this->prefixDirsPsr4[$prefix] as $dir) { |                 $subPath = substr($subPath, 0, $lastPos); | ||||||
|  |                 $search = $subPath.'\\'; | ||||||
|  |                 if (isset($this->prefixDirsPsr4[$search])) { | ||||||
|  |                     foreach ($this->prefixDirsPsr4[$search] as $dir) { | ||||||
|  |                         $length = $this->prefixLengthsPsr4[$first][$search]; | ||||||
|                         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { |                         if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { | ||||||
|                             return $file; |                             return $file; | ||||||
|                         } |                         } | ||||||
| @@ -399,6 +429,8 @@ class ClassLoader | |||||||
|         if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { |         if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { | ||||||
|             return $file; |             return $file; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								vendor/composer/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/composer/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
|  |  | ||||||
| Copyright (c) 2016 Nils Adermann, Jordi Boggiano | Copyright (c) Nils Adermann, Jordi Boggiano | ||||||
|  |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
| of this software and associated documentation files (the "Software"), to deal | of this software and associated documentation files (the "Software"), to deal | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								vendor/composer/autoload_psr4.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/composer/autoload_psr4.php
									
									
									
									
										vendored
									
									
								
							| @@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); | |||||||
| $baseDir = dirname($vendorDir); | $baseDir = dirname($vendorDir); | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|  |     'RobThree\\Auth\\' => array($vendorDir . '/robthree/twofactorauth/lib'), | ||||||
|     'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'), |     'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'), | ||||||
| ); | ); | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| // autoload_real.php @generated by Composer | // autoload_real.php @generated by Composer | ||||||
|  |  | ||||||
| class ComposerAutoloaderInitef6e9937a63bd796f32542b02941ee0e | class ComposerAutoloaderInitf3438a4bfc092aad40a104edf0a3eb02 | ||||||
| { | { | ||||||
|     private static $loader; |     private static $loader; | ||||||
|  |  | ||||||
| @@ -19,15 +19,15 @@ class ComposerAutoloaderInitef6e9937a63bd796f32542b02941ee0e | |||||||
|             return self::$loader; |             return self::$loader; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         spl_autoload_register(array('ComposerAutoloaderInitef6e9937a63bd796f32542b02941ee0e', 'loadClassLoader'), true, true); |         spl_autoload_register(array('ComposerAutoloaderInitf3438a4bfc092aad40a104edf0a3eb02', 'loadClassLoader'), true, true); | ||||||
|         self::$loader = $loader = new \Composer\Autoload\ClassLoader(); |         self::$loader = $loader = new \Composer\Autoload\ClassLoader(); | ||||||
|         spl_autoload_unregister(array('ComposerAutoloaderInitef6e9937a63bd796f32542b02941ee0e', 'loadClassLoader')); |         spl_autoload_unregister(array('ComposerAutoloaderInitf3438a4bfc092aad40a104edf0a3eb02', 'loadClassLoader')); | ||||||
|  |  | ||||||
|         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION'); |         $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); | ||||||
|         if ($useStaticLoader) { |         if ($useStaticLoader) { | ||||||
|             require_once __DIR__ . '/autoload_static.php'; |             require_once __DIR__ . '/autoload_static.php'; | ||||||
|  |  | ||||||
|             call_user_func(\Composer\Autoload\ComposerStaticInitef6e9937a63bd796f32542b02941ee0e::getInitializer($loader)); |             call_user_func(\Composer\Autoload\ComposerStaticInitf3438a4bfc092aad40a104edf0a3eb02::getInitializer($loader)); | ||||||
|         } else { |         } else { | ||||||
|             $map = require __DIR__ . '/autoload_namespaces.php'; |             $map = require __DIR__ . '/autoload_namespaces.php'; | ||||||
|             foreach ($map as $namespace => $path) { |             foreach ($map as $namespace => $path) { | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								vendor/composer/autoload_static.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/composer/autoload_static.php
									
									
									
									
										vendored
									
									
								
							| @@ -4,9 +4,13 @@ | |||||||
|  |  | ||||||
| namespace Composer\Autoload; | namespace Composer\Autoload; | ||||||
|  |  | ||||||
| class ComposerStaticInitef6e9937a63bd796f32542b02941ee0e | class ComposerStaticInitf3438a4bfc092aad40a104edf0a3eb02 | ||||||
| { | { | ||||||
|     public static $prefixLengthsPsr4 = array ( |     public static $prefixLengthsPsr4 = array ( | ||||||
|  |         'R' =>  | ||||||
|  |         array ( | ||||||
|  |             'RobThree\\Auth\\' => 14, | ||||||
|  |         ), | ||||||
|         'C' =>  |         'C' =>  | ||||||
|         array ( |         array ( | ||||||
|             'Composer\\Semver\\' => 16, |             'Composer\\Semver\\' => 16, | ||||||
| @@ -14,6 +18,10 @@ class ComposerStaticInitef6e9937a63bd796f32542b02941ee0e | |||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     public static $prefixDirsPsr4 = array ( |     public static $prefixDirsPsr4 = array ( | ||||||
|  |         'RobThree\\Auth\\' =>  | ||||||
|  |         array ( | ||||||
|  |             0 => __DIR__ . '/..' . '/robthree/twofactorauth/lib', | ||||||
|  |         ), | ||||||
|         'Composer\\Semver\\' =>  |         'Composer\\Semver\\' =>  | ||||||
|         array ( |         array ( | ||||||
|             0 => __DIR__ . '/..' . '/composer/semver/src', |             0 => __DIR__ . '/..' . '/composer/semver/src', | ||||||
| @@ -40,9 +48,9 @@ class ComposerStaticInitef6e9937a63bd796f32542b02941ee0e | |||||||
|     public static function getInitializer(ClassLoader $loader) |     public static function getInitializer(ClassLoader $loader) | ||||||
|     { |     { | ||||||
|         return \Closure::bind(function () use ($loader) { |         return \Closure::bind(function () use ($loader) { | ||||||
|             $loader->prefixLengthsPsr4 = ComposerStaticInitef6e9937a63bd796f32542b02941ee0e::$prefixLengthsPsr4; |             $loader->prefixLengthsPsr4 = ComposerStaticInitf3438a4bfc092aad40a104edf0a3eb02::$prefixLengthsPsr4; | ||||||
|             $loader->prefixDirsPsr4 = ComposerStaticInitef6e9937a63bd796f32542b02941ee0e::$prefixDirsPsr4; |             $loader->prefixDirsPsr4 = ComposerStaticInitf3438a4bfc092aad40a104edf0a3eb02::$prefixDirsPsr4; | ||||||
|             $loader->prefixesPsr0 = ComposerStaticInitef6e9937a63bd796f32542b02941ee0e::$prefixesPsr0; |             $loader->prefixesPsr0 = ComposerStaticInitf3438a4bfc092aad40a104edf0a3eb02::$prefixesPsr0; | ||||||
|  |  | ||||||
|         }, null, ClassLoader::class); |         }, null, ClassLoader::class); | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										172
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,51 +1,4 @@ | |||||||
| [ | [ | ||||||
|     { |  | ||||||
|         "name": "zendframework/zendxml", |  | ||||||
|         "version": "1.0.2", |  | ||||||
|         "version_normalized": "1.0.2.0", |  | ||||||
|         "source": { |  | ||||||
|             "type": "git", |  | ||||||
|             "url": "https://github.com/zendframework/ZendXml.git", |  | ||||||
|             "reference": "7b64507bc35d841c9c5802d67f6f87ef8e1a58c9" |  | ||||||
|         }, |  | ||||||
|         "dist": { |  | ||||||
|             "type": "zip", |  | ||||||
|             "url": "https://api.github.com/repos/zendframework/ZendXml/zipball/7b64507bc35d841c9c5802d67f6f87ef8e1a58c9", |  | ||||||
|             "reference": "7b64507bc35d841c9c5802d67f6f87ef8e1a58c9", |  | ||||||
|             "shasum": "" |  | ||||||
|         }, |  | ||||||
|         "require": { |  | ||||||
|             "php": "^5.3.3 || ^7.0" |  | ||||||
|         }, |  | ||||||
|         "require-dev": { |  | ||||||
|             "phpunit/phpunit": "^3.7 || ^4.0", |  | ||||||
|             "squizlabs/php_codesniffer": "^1.5" |  | ||||||
|         }, |  | ||||||
|         "time": "2016-02-04 21:02:08", |  | ||||||
|         "type": "library", |  | ||||||
|         "extra": { |  | ||||||
|             "branch-alias": { |  | ||||||
|                 "dev-master": "1.0-dev" |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "installation-source": "dist", |  | ||||||
|         "autoload": { |  | ||||||
|             "psr-0": { |  | ||||||
|                 "ZendXml\\": "library/" |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         "notification-url": "https://packagist.org/downloads/", |  | ||||||
|         "license": [ |  | ||||||
|             "BSD-3-Clause" |  | ||||||
|         ], |  | ||||||
|         "description": "Utility library for XML usage, best practices, and security in PHP", |  | ||||||
|         "homepage": "http://packages.zendframework.com/", |  | ||||||
|         "keywords": [ |  | ||||||
|             "security", |  | ||||||
|             "xml", |  | ||||||
|             "zf2" |  | ||||||
|         ] |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|         "name": "composer/semver", |         "name": "composer/semver", | ||||||
|         "version": "1.4.2", |         "version": "1.4.2", | ||||||
| @@ -68,7 +21,7 @@ | |||||||
|             "phpunit/phpunit": "^4.5 || ^5.0.5", |             "phpunit/phpunit": "^4.5 || ^5.0.5", | ||||||
|             "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" |             "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" | ||||||
|         }, |         }, | ||||||
|         "time": "2016-08-30 16:08:34", |         "time": "2016-08-30T16:08:34+00:00", | ||||||
|         "type": "library", |         "type": "library", | ||||||
|         "extra": { |         "extra": { | ||||||
|             "branch-alias": { |             "branch-alias": { | ||||||
| @@ -111,18 +64,65 @@ | |||||||
|         ] |         ] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         "name": "fguillot/picofeed", |         "name": "zendframework/zendxml", | ||||||
|         "version": "v0.1.25", |         "version": "1.0.2", | ||||||
|         "version_normalized": "0.1.25.0", |         "version_normalized": "1.0.2.0", | ||||||
|         "source": { |         "source": { | ||||||
|             "type": "git", |             "type": "git", | ||||||
|             "url": "https://github.com/fguillot/picoFeed.git", |             "url": "https://github.com/zendframework/ZendXml.git", | ||||||
|             "reference": "2bf5bc40361e788eda6b1bd5d444630986721e69" |             "reference": "7b64507bc35d841c9c5802d67f6f87ef8e1a58c9" | ||||||
|         }, |         }, | ||||||
|         "dist": { |         "dist": { | ||||||
|             "type": "zip", |             "type": "zip", | ||||||
|             "url": "https://api.github.com/repos/fguillot/picoFeed/zipball/2bf5bc40361e788eda6b1bd5d444630986721e69", |             "url": "https://api.github.com/repos/zendframework/ZendXml/zipball/7b64507bc35d841c9c5802d67f6f87ef8e1a58c9", | ||||||
|             "reference": "2bf5bc40361e788eda6b1bd5d444630986721e69", |             "reference": "7b64507bc35d841c9c5802d67f6f87ef8e1a58c9", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "require": { | ||||||
|  |             "php": "^5.3.3 || ^7.0" | ||||||
|  |         }, | ||||||
|  |         "require-dev": { | ||||||
|  |             "phpunit/phpunit": "^3.7 || ^4.0", | ||||||
|  |             "squizlabs/php_codesniffer": "^1.5" | ||||||
|  |         }, | ||||||
|  |         "time": "2016-02-04T21:02:08+00:00", | ||||||
|  |         "type": "library", | ||||||
|  |         "extra": { | ||||||
|  |             "branch-alias": { | ||||||
|  |                 "dev-master": "1.0-dev" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "installation-source": "dist", | ||||||
|  |         "autoload": { | ||||||
|  |             "psr-0": { | ||||||
|  |                 "ZendXml\\": "library/" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "BSD-3-Clause" | ||||||
|  |         ], | ||||||
|  |         "description": "Utility library for XML usage, best practices, and security in PHP", | ||||||
|  |         "homepage": "http://packages.zendframework.com/", | ||||||
|  |         "keywords": [ | ||||||
|  |             "security", | ||||||
|  |             "xml", | ||||||
|  |             "zf2" | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "fguillot/picofeed", | ||||||
|  |         "version": "v0.1.35", | ||||||
|  |         "version_normalized": "0.1.35.0", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/miniflux/picoFeed.git", | ||||||
|  |             "reference": "3a27b47de31eedec075c719f961783c5db7a7b08" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/miniflux/picoFeed/zipball/3a27b47de31eedec075c719f961783c5db7a7b08", | ||||||
|  |             "reference": "3a27b47de31eedec075c719f961783c5db7a7b08", | ||||||
|             "shasum": "" |             "shasum": "" | ||||||
|         }, |         }, | ||||||
|         "require": { |         "require": { | ||||||
| @@ -134,10 +134,15 @@ | |||||||
|             "php": ">=5.3.0", |             "php": ">=5.3.0", | ||||||
|             "zendframework/zendxml": "^1.0" |             "zendframework/zendxml": "^1.0" | ||||||
|         }, |         }, | ||||||
|  |         "require-dev": { | ||||||
|  |             "phpdocumentor/reflection-docblock": "2.0.4", | ||||||
|  |             "phpunit/phpunit": "4.8.26", | ||||||
|  |             "symfony/yaml": "2.8.7" | ||||||
|  |         }, | ||||||
|         "suggest": { |         "suggest": { | ||||||
|             "ext-curl": "PicoFeed will use cURL if present" |             "ext-curl": "PicoFeed will use cURL if present" | ||||||
|         }, |         }, | ||||||
|         "time": "2016-08-30 01:33:18", |         "time": "2017-06-20T22:54:47+00:00", | ||||||
|         "bin": [ |         "bin": [ | ||||||
|             "picofeed" |             "picofeed" | ||||||
|         ], |         ], | ||||||
| @@ -158,6 +163,59 @@ | |||||||
|             } |             } | ||||||
|         ], |         ], | ||||||
|         "description": "Modern library to handle RSS/Atom feeds", |         "description": "Modern library to handle RSS/Atom feeds", | ||||||
|         "homepage": "https://github.com/fguillot/picoFeed" |         "homepage": "https://github.com/miniflux/picoFeed" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |         "name": "robthree/twofactorauth", | ||||||
|  |         "version": "1.6", | ||||||
|  |         "version_normalized": "1.6.0.0", | ||||||
|  |         "source": { | ||||||
|  |             "type": "git", | ||||||
|  |             "url": "https://github.com/RobThree/TwoFactorAuth.git", | ||||||
|  |             "reference": "5093ab230cd8f1296d792afb6a49545f37e7fd5a" | ||||||
|  |         }, | ||||||
|  |         "dist": { | ||||||
|  |             "type": "zip", | ||||||
|  |             "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/5093ab230cd8f1296d792afb6a49545f37e7fd5a", | ||||||
|  |             "reference": "5093ab230cd8f1296d792afb6a49545f37e7fd5a", | ||||||
|  |             "shasum": "" | ||||||
|  |         }, | ||||||
|  |         "require": { | ||||||
|  |             "php": ">=5.3.0" | ||||||
|  |         }, | ||||||
|  |         "require-dev": { | ||||||
|  |             "phpunit/phpunit": "@stable" | ||||||
|  |         }, | ||||||
|  |         "time": "2017-02-17T15:24:54+00:00", | ||||||
|  |         "type": "library", | ||||||
|  |         "installation-source": "dist", | ||||||
|  |         "autoload": { | ||||||
|  |             "psr-4": { | ||||||
|  |                 "RobThree\\Auth\\": "lib" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "notification-url": "https://packagist.org/downloads/", | ||||||
|  |         "license": [ | ||||||
|  |             "MIT" | ||||||
|  |         ], | ||||||
|  |         "authors": [ | ||||||
|  |             { | ||||||
|  |                 "name": "Rob Janssen", | ||||||
|  |                 "homepage": "http://robiii.me", | ||||||
|  |                 "role": "Developer" | ||||||
|  |             } | ||||||
|  |         ], | ||||||
|  |         "description": "Two Factor Authentication", | ||||||
|  |         "homepage": "https://github.com/RobThree/TwoFactorAuth", | ||||||
|  |         "keywords": [ | ||||||
|  |             "Authentication", | ||||||
|  |             "MFA", | ||||||
|  |             "Multi Factor Authentication", | ||||||
|  |             "Two Factor Authentication", | ||||||
|  |             "authenticator", | ||||||
|  |             "authy", | ||||||
|  |             "php", | ||||||
|  |             "tfa" | ||||||
|  |         ] | ||||||
|     } |     } | ||||||
| ] | ] | ||||||
|   | |||||||
| @@ -31,4 +31,8 @@ abstract class Base | |||||||
|         $this->config = $config ?: new Config(); |         $this->config = $config ?: new Config(); | ||||||
|         Logger::setTimezone($this->config->getTimezone()); |         Logger::setTimezone($this->config->getTimezone()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function setConfig(Config $config) { | ||||||
|  |         $this->config = $config; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ | |||||||
|  |  | ||||||
| namespace PicoFeed\Client; | namespace PicoFeed\Client; | ||||||
|  |  | ||||||
|  | use DateTime; | ||||||
|  | use Exception; | ||||||
| use LogicException; | use LogicException; | ||||||
| use PicoFeed\Logging\Logger; | use PicoFeed\Logging\Logger; | ||||||
| use PicoFeed\Config\Config; | use PicoFeed\Config\Config; | ||||||
| @@ -55,6 +57,13 @@ abstract class Client | |||||||
|      */ |      */ | ||||||
|     protected $last_modified = ''; |     protected $last_modified = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Expiration DateTime | ||||||
|  |      * | ||||||
|  |      * @var DateTime | ||||||
|  |      */ | ||||||
|  |     protected $expiration = null; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Proxy hostname. |      * Proxy hostname. | ||||||
|      * |      * | ||||||
| @@ -97,6 +106,13 @@ abstract class Client | |||||||
|      */ |      */ | ||||||
|     protected $password = ''; |     protected $password = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * CURL options. | ||||||
|  |      * | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     protected $additional_curl_options = array(); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Client connection timeout. |      * Client connection timeout. | ||||||
|      * |      * | ||||||
| @@ -109,7 +125,7 @@ abstract class Client | |||||||
|      * |      * | ||||||
|      * @var string |      * @var string | ||||||
|      */ |      */ | ||||||
|     protected $user_agent = 'PicoFeed (https://github.com/fguillot/picoFeed)'; |     protected $user_agent = 'PicoFeed (https://github.com/miniflux/picoFeed)'; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Real URL used (can be changed after a HTTP redirect). |      * Real URL used (can be changed after a HTTP redirect). | ||||||
| @@ -214,6 +230,9 @@ abstract class Client | |||||||
|         $this->handleErrorResponse($response); |         $this->handleErrorResponse($response); | ||||||
|         $this->handleNormalResponse($response); |         $this->handleNormalResponse($response); | ||||||
|  |  | ||||||
|  |         $this->expiration = $this->parseExpiration($response['headers']); | ||||||
|  |         Logger::setMessage(get_called_class().' Expiration: '.$this->expiration->format(DATE_ISO8601)); | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -241,6 +260,9 @@ abstract class Client | |||||||
|      * Handle Http Error codes |      * Handle Http Error codes | ||||||
|      * |      * | ||||||
|      * @param array $response Client response |      * @param array $response Client response | ||||||
|  |      * @throws ForbiddenException | ||||||
|  |      * @throws InvalidUrlException | ||||||
|  |      * @throws UnauthorizedException | ||||||
|      */ |      */ | ||||||
|     protected function handleErrorResponse(array $response) |     protected function handleErrorResponse(array $response) | ||||||
|     { |     { | ||||||
| @@ -308,7 +330,6 @@ abstract class Client | |||||||
|      * Find content type from response headers. |      * Find content type from response headers. | ||||||
|      * |      * | ||||||
|      * @param array $response Client response |      * @param array $response Client response | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function findContentType(array $response) |     public function findContentType(array $response) | ||||||
| @@ -324,7 +345,6 @@ abstract class Client | |||||||
|     public function findCharset() |     public function findCharset() | ||||||
|     { |     { | ||||||
|         $result = explode('charset=', $this->content_type); |         $result = explode('charset=', $this->content_type); | ||||||
|  |  | ||||||
|         return isset($result[1]) ? $result[1] : ''; |         return isset($result[1]) ? $result[1] : ''; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -333,7 +353,6 @@ abstract class Client | |||||||
|      * |      * | ||||||
|      * @param array  $response Client response |      * @param array  $response Client response | ||||||
|      * @param string $header   Header name |      * @param string $header   Header name | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function getHeader(array $response, $header) |     public function getHeader(array $response, $header) | ||||||
| @@ -345,13 +364,11 @@ abstract class Client | |||||||
|      * Set the Last-Modified HTTP header. |      * Set the Last-Modified HTTP header. | ||||||
|      * |      * | ||||||
|      * @param string $last_modified Header value |      * @param string $last_modified Header value | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setLastModified($last_modified) |     public function setLastModified($last_modified) | ||||||
|     { |     { | ||||||
|         $this->last_modified = $last_modified; |         $this->last_modified = $last_modified; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -369,13 +386,11 @@ abstract class Client | |||||||
|      * Set the value of the Etag HTTP header. |      * Set the value of the Etag HTTP header. | ||||||
|      * |      * | ||||||
|      * @param string $etag Etag HTTP header value |      * @param string $etag Etag HTTP header value | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setEtag($etag) |     public function setEtag($etag) | ||||||
|     { |     { | ||||||
|         $this->etag = $etag; |         $this->etag = $etag; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -402,13 +417,12 @@ abstract class Client | |||||||
|     /** |     /** | ||||||
|      * Set the url. |      * Set the url. | ||||||
|      * |      * | ||||||
|  |      * @param  $url | ||||||
|      * @return string |      * @return string | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setUrl($url) |     public function setUrl($url) | ||||||
|     { |     { | ||||||
|         $this->url = $url; |         $this->url = $url; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -476,13 +490,11 @@ abstract class Client | |||||||
|      * Set connection timeout. |      * Set connection timeout. | ||||||
|      * |      * | ||||||
|      * @param int $timeout Connection timeout |      * @param int $timeout Connection timeout | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setTimeout($timeout) |     public function setTimeout($timeout) | ||||||
|     { |     { | ||||||
|         $this->timeout = $timeout ?: $this->timeout; |         $this->timeout = $timeout ?: $this->timeout; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -490,13 +502,11 @@ abstract class Client | |||||||
|      * Set a custom user agent. |      * Set a custom user agent. | ||||||
|      * |      * | ||||||
|      * @param string $user_agent User Agent |      * @param string $user_agent User Agent | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setUserAgent($user_agent) |     public function setUserAgent($user_agent) | ||||||
|     { |     { | ||||||
|         $this->user_agent = $user_agent ?: $this->user_agent; |         $this->user_agent = $user_agent ?: $this->user_agent; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -504,13 +514,11 @@ abstract class Client | |||||||
|      * Set the maximum number of HTTP redirections. |      * Set the maximum number of HTTP redirections. | ||||||
|      * |      * | ||||||
|      * @param int $max Maximum |      * @param int $max Maximum | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setMaxRedirections($max) |     public function setMaxRedirections($max) | ||||||
|     { |     { | ||||||
|         $this->max_redirects = $max ?: $this->max_redirects; |         $this->max_redirects = $max ?: $this->max_redirects; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -518,13 +526,11 @@ abstract class Client | |||||||
|      * Set the maximum size of the HTTP body. |      * Set the maximum size of the HTTP body. | ||||||
|      * |      * | ||||||
|      * @param int $max Maximum |      * @param int $max Maximum | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setMaxBodySize($max) |     public function setMaxBodySize($max) | ||||||
|     { |     { | ||||||
|         $this->max_body_size = $max ?: $this->max_body_size; |         $this->max_body_size = $max ?: $this->max_body_size; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -532,13 +538,11 @@ abstract class Client | |||||||
|      * Set the proxy hostname. |      * Set the proxy hostname. | ||||||
|      * |      * | ||||||
|      * @param string $hostname Proxy hostname |      * @param string $hostname Proxy hostname | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setProxyHostname($hostname) |     public function setProxyHostname($hostname) | ||||||
|     { |     { | ||||||
|         $this->proxy_hostname = $hostname ?: $this->proxy_hostname; |         $this->proxy_hostname = $hostname ?: $this->proxy_hostname; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -546,13 +550,11 @@ abstract class Client | |||||||
|      * Set the proxy port. |      * Set the proxy port. | ||||||
|      * |      * | ||||||
|      * @param int $port Proxy port |      * @param int $port Proxy port | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setProxyPort($port) |     public function setProxyPort($port) | ||||||
|     { |     { | ||||||
|         $this->proxy_port = $port ?: $this->proxy_port; |         $this->proxy_port = $port ?: $this->proxy_port; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -560,13 +562,11 @@ abstract class Client | |||||||
|      * Set the proxy username. |      * Set the proxy username. | ||||||
|      * |      * | ||||||
|      * @param string $username Proxy username |      * @param string $username Proxy username | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setProxyUsername($username) |     public function setProxyUsername($username) | ||||||
|     { |     { | ||||||
|         $this->proxy_username = $username ?: $this->proxy_username; |         $this->proxy_username = $username ?: $this->proxy_username; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -574,13 +574,11 @@ abstract class Client | |||||||
|      * Set the proxy password. |      * Set the proxy password. | ||||||
|      * |      * | ||||||
|      * @param string $password Password |      * @param string $password Password | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setProxyPassword($password) |     public function setProxyPassword($password) | ||||||
|     { |     { | ||||||
|         $this->proxy_password = $password ?: $this->proxy_password; |         $this->proxy_password = $password ?: $this->proxy_password; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -589,12 +587,11 @@ abstract class Client | |||||||
|      * |      * | ||||||
|      * @param string $username Basic Auth username |      * @param string $username Basic Auth username | ||||||
|      * |      * | ||||||
|      * @return \PicoFeed\Client\Client |      * @return $this | ||||||
|      */ |      */ | ||||||
|     public function setUsername($username) |     public function setUsername($username) | ||||||
|     { |     { | ||||||
|         $this->username = $username ?: $this->username; |         $this->username = $username ?: $this->username; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -603,36 +600,46 @@ abstract class Client | |||||||
|      * |      * | ||||||
|      * @param string $password Basic Auth Password |      * @param string $password Basic Auth Password | ||||||
|      * |      * | ||||||
|      * @return \PicoFeed\Client\Client |      * @return $this | ||||||
|      */ |      */ | ||||||
|     public function setPassword($password) |     public function setPassword($password) | ||||||
|     { |     { | ||||||
|         $this->password = $password ?: $this->password; |         $this->password = $password ?: $this->password; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set the CURL options. | ||||||
|  |      * | ||||||
|  |      * @param array $options | ||||||
|  |      * @return $this | ||||||
|  |      */ | ||||||
|  |     public function setAdditionalCurlOptions(array $options) | ||||||
|  |     { | ||||||
|  |         $this->additional_curl_options = $options ?: $this->additional_curl_options; | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Enable the passthrough mode. |      * Enable the passthrough mode. | ||||||
|      * |      * | ||||||
|      * @return \PicoFeed\Client\Client |      * @return $this | ||||||
|      */ |      */ | ||||||
|     public function enablePassthroughMode() |     public function enablePassthroughMode() | ||||||
|     { |     { | ||||||
|         $this->passthrough = true; |         $this->passthrough = true; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Disable the passthrough mode. |      * Disable the passthrough mode. | ||||||
|      * |      * | ||||||
|      * @return \PicoFeed\Client\Client |      * @return $this | ||||||
|      */ |      */ | ||||||
|     public function disablePassthroughMode() |     public function disablePassthroughMode() | ||||||
|     { |     { | ||||||
|         $this->passthrough = false; |         $this->passthrough = false; | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -640,8 +647,7 @@ abstract class Client | |||||||
|      * Set config object. |      * Set config object. | ||||||
|      * |      * | ||||||
|      * @param \PicoFeed\Config\Config $config Config instance |      * @param \PicoFeed\Config\Config $config Config instance | ||||||
|      * |      * @return $this | ||||||
|      * @return \PicoFeed\Client\Client |  | ||||||
|      */ |      */ | ||||||
|     public function setConfig(Config $config) |     public function setConfig(Config $config) | ||||||
|     { |     { | ||||||
| @@ -654,6 +660,7 @@ abstract class Client | |||||||
|             $this->setProxyPort($config->getProxyPort()); |             $this->setProxyPort($config->getProxyPort()); | ||||||
|             $this->setProxyUsername($config->getProxyUsername()); |             $this->setProxyUsername($config->getProxyUsername()); | ||||||
|             $this->setProxyPassword($config->getProxyPassword()); |             $this->setProxyPassword($config->getProxyPassword()); | ||||||
|  |             $this->setAdditionalCurlOptions($config->getAdditionalCurlOptions() ?: array()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $this; |         return $this; | ||||||
| @@ -670,4 +677,36 @@ abstract class Client | |||||||
|     { |     { | ||||||
|         return $code == 301 || $code == 302 || $code == 303 || $code == 307; |         return $code == 301 || $code == 302 || $code == 303 || $code == 307; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function parseExpiration(HttpHeaders $headers) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |  | ||||||
|  |             if (isset($headers['Cache-Control'])) { | ||||||
|  |                 if (preg_match('/s-maxage=(\d+)/', $headers['Cache-Control'], $matches)) { | ||||||
|  |                     return new DateTime('+' . $matches[1] . ' seconds'); | ||||||
|  |                 } else if (preg_match('/max-age=(\d+)/', $headers['Cache-Control'], $matches)) { | ||||||
|  |                     return new DateTime('+' . $matches[1] . ' seconds'); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (! empty($headers['Expires'])) { | ||||||
|  |                 return new DateTime($headers['Expires']); | ||||||
|  |             } | ||||||
|  |         } catch (Exception $e) { | ||||||
|  |             Logger::setMessage('Unable to parse expiration date: '.$e->getMessage()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return new DateTime(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get expiration date time from "Expires" or "Cache-Control" headers | ||||||
|  |      * | ||||||
|  |      * @return DateTime | ||||||
|  |      */ | ||||||
|  |     public function getExpiration() | ||||||
|  |     { | ||||||
|  |         return $this->expiration ?: new DateTime(); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,6 +11,8 @@ use PicoFeed\Logging\Logger; | |||||||
|  */ |  */ | ||||||
| class Curl extends Client | class Curl extends Client | ||||||
| { | { | ||||||
|  |     protected $nbRedirects = 0; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * HTTP response body. |      * HTTP response body. | ||||||
|      * |      * | ||||||
| @@ -108,8 +110,6 @@ class Curl extends Client | |||||||
|                 return $this->handleRedirection($headers['Location']); |                 return $this->handleRedirection($headers['Location']); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             header(':', true, $status); |  | ||||||
|  |  | ||||||
|             if (isset($headers['Content-Type'])) { |             if (isset($headers['Content-Type'])) { | ||||||
|                 header('Content-Type:' .$headers['Content-Type']); |                 header('Content-Type:' .$headers['Content-Type']); | ||||||
|             } |             } | ||||||
| @@ -136,6 +136,7 @@ class Curl extends Client | |||||||
|  |  | ||||||
|         if ($this->etag) { |         if ($this->etag) { | ||||||
|             $headers[] = 'If-None-Match: '.$this->etag; |             $headers[] = 'If-None-Match: '.$this->etag; | ||||||
|  |             $headers[] = 'A-IM: feed'; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ($this->last_modified) { |         if ($this->last_modified) { | ||||||
| @@ -199,6 +200,9 @@ class Curl extends Client | |||||||
|      */ |      */ | ||||||
|     private function prepareDownloadMode($ch) |     private function prepareDownloadMode($ch) | ||||||
|     { |     { | ||||||
|  |         $this->body = ''; | ||||||
|  |         $this->response_headers = array(); | ||||||
|  |         $this->response_headers_count = 0; | ||||||
|         $write_function = 'readBody'; |         $write_function = 'readBody'; | ||||||
|         $header_function = 'readHeaders'; |         $header_function = 'readHeaders'; | ||||||
|  |  | ||||||
| @@ -212,6 +216,20 @@ class Curl extends Client | |||||||
|         return $ch; |         return $ch; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set additional CURL options. | ||||||
|  |      * | ||||||
|  |      * @param resource $ch | ||||||
|  |      * | ||||||
|  |      * @return resource $ch | ||||||
|  |      */ | ||||||
|  |     private function prepareAdditionalCurlOptions($ch){ | ||||||
|  |         foreach( $this->additional_curl_options as $c_op => $c_val ){ | ||||||
|  |             curl_setopt($ch, $c_op, $c_val); | ||||||
|  |         } | ||||||
|  |         return $ch; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Prepare curl context. |      * Prepare curl context. | ||||||
|      * |      * | ||||||
| @@ -245,6 +263,7 @@ class Curl extends Client | |||||||
|         $ch = $this->prepareDownloadMode($ch); |         $ch = $this->prepareDownloadMode($ch); | ||||||
|         $ch = $this->prepareProxyContext($ch); |         $ch = $this->prepareProxyContext($ch); | ||||||
|         $ch = $this->prepareAuthContext($ch); |         $ch = $this->prepareAuthContext($ch); | ||||||
|  |         $ch = $this->prepareAdditionalCurlOptions($ch); | ||||||
|  |  | ||||||
|         return $ch; |         return $ch; | ||||||
|     } |     } | ||||||
| @@ -290,7 +309,11 @@ class Curl extends Client | |||||||
|         list($status, $headers) = HttpHeaders::parse(explode("\n", $this->response_headers[$this->response_headers_count - 1])); |         list($status, $headers) = HttpHeaders::parse(explode("\n", $this->response_headers[$this->response_headers_count - 1])); | ||||||
|  |  | ||||||
|         if ($this->isRedirection($status)) { |         if ($this->isRedirection($status)) { | ||||||
|             return $this->handleRedirection($headers['Location']); |             if (empty($headers['Location'])) { | ||||||
|  |                 $status = 200; | ||||||
|  |             } else { | ||||||
|  |                 return $this->handleRedirection($headers['Location']); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return array( |         return array( | ||||||
| @@ -304,12 +327,11 @@ class Curl extends Client | |||||||
|      * Handle HTTP redirects |      * Handle HTTP redirects | ||||||
|      * |      * | ||||||
|      * @param string $location Redirected URL |      * @param string $location Redirected URL | ||||||
|      * |  | ||||||
|      * @return array |      * @return array | ||||||
|  |      * @throws MaxRedirectException | ||||||
|      */ |      */ | ||||||
|     private function handleRedirection($location) |     private function handleRedirection($location) | ||||||
|     { |     { | ||||||
|         $nb_redirects = 0; |  | ||||||
|         $result = array(); |         $result = array(); | ||||||
|         $this->url = Url::resolve($location, $this->url); |         $this->url = Url::resolve($location, $this->url); | ||||||
|         $this->body = ''; |         $this->body = ''; | ||||||
| @@ -318,9 +340,9 @@ class Curl extends Client | |||||||
|         $this->response_headers_count = 0; |         $this->response_headers_count = 0; | ||||||
|  |  | ||||||
|         while (true) { |         while (true) { | ||||||
|             ++$nb_redirects; |             $this->nbRedirects++; | ||||||
|  |  | ||||||
|             if ($nb_redirects >= $this->max_redirects) { |             if ($this->nbRedirects >= $this->max_redirects) { | ||||||
|                 throw new MaxRedirectException('Maximum number of redirections reached'); |                 throw new MaxRedirectException('Maximum number of redirections reached'); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -349,6 +371,11 @@ class Curl extends Client | |||||||
|      * @see    http://curl.haxx.se/libcurl/c/libcurl-errors.html |      * @see    http://curl.haxx.se/libcurl/c/libcurl-errors.html | ||||||
|      * |      * | ||||||
|      * @param int $errno cURL error code |      * @param int $errno cURL error code | ||||||
|  |      * @throws InvalidCertificateException | ||||||
|  |      * @throws InvalidUrlException | ||||||
|  |      * @throws MaxRedirectException | ||||||
|  |      * @throws MaxSizeException | ||||||
|  |      * @throws TimeoutException | ||||||
|      */ |      */ | ||||||
|     private function handleError($errno) |     private function handleError($errno) | ||||||
|     { |     { | ||||||
| @@ -372,8 +399,7 @@ class Curl extends Client | |||||||
|             case 66: // CURLE_SSL_ENGINE_INITFAILED |             case 66: // CURLE_SSL_ENGINE_INITFAILED | ||||||
|             case 77: // CURLE_SSL_CACERT_BADFILE |             case 77: // CURLE_SSL_CACERT_BADFILE | ||||||
|             case 83: // CURLE_SSL_ISSUER_ERROR |             case 83: // CURLE_SSL_ISSUER_ERROR | ||||||
|                 $msg = 'Invalid SSL certificate caused by CURL error number ' . |                 $msg = 'Invalid SSL certificate caused by CURL error number ' . $errno; | ||||||
|                         $errno; |  | ||||||
|                 throw new InvalidCertificateException($msg, $errno); |                 throw new InvalidCertificateException($msg, $errno); | ||||||
|             case 47: // CURLE_TOO_MANY_REDIRECTS |             case 47: // CURLE_TOO_MANY_REDIRECTS | ||||||
|                 throw new MaxRedirectException('Maximum number of redirections reached', $errno); |                 throw new MaxRedirectException('Maximum number of redirections reached', $errno); | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ class HttpHeaders implements ArrayAccess | |||||||
|  |  | ||||||
|     public function offsetGet($offset) |     public function offsetGet($offset) | ||||||
|     { |     { | ||||||
|         return $this->headers[strtolower($offset)]; |         return $this->offsetExists($offset) ? $this->headers[strtolower($offset)] : ''; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function offsetSet($offset, $value) |     public function offsetSet($offset, $value) | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ class Stream extends Client | |||||||
|  |  | ||||||
|         if ($this->etag) { |         if ($this->etag) { | ||||||
|             $headers[] = 'If-None-Match: '.$this->etag; |             $headers[] = 'If-None-Match: '.$this->etag; | ||||||
|  |             $headers[] = 'A-IM: feed'; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ($this->last_modified) { |         if ($this->last_modified) { | ||||||
| @@ -104,6 +105,9 @@ class Stream extends Client | |||||||
|      * Do the HTTP request. |      * Do the HTTP request. | ||||||
|      * |      * | ||||||
|      * @return array HTTP response ['body' => ..., 'status' => ..., 'headers' => ...] |      * @return array HTTP response ['body' => ..., 'status' => ..., 'headers' => ...] | ||||||
|  |      * @throws InvalidUrlException | ||||||
|  |      * @throws MaxSizeException | ||||||
|  |      * @throws TimeoutException | ||||||
|      */ |      */ | ||||||
|     public function doRequest() |     public function doRequest() | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -50,10 +50,8 @@ class Url | |||||||
|      * Shortcut method to get an absolute url from relative url. |      * Shortcut method to get an absolute url from relative url. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param mixed $item_url    Unknown url (can be relative or not) |      * @param mixed $item_url    Unknown url (can be relative or not) | ||||||
|      * @param mixed $website_url Website url |      * @param mixed $website_url Website url | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public static function resolve($item_url, $website_url) |     public static function resolve($item_url, $website_url) | ||||||
| @@ -78,9 +76,7 @@ class Url | |||||||
|      * Shortcut method to get a base url. |      * Shortcut method to get a base url. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $url |      * @param string $url | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public static function base($url) |     public static function base($url) | ||||||
| @@ -94,7 +90,6 @@ class Url | |||||||
|      * Get the base URL. |      * Get the base URL. | ||||||
|      * |      * | ||||||
|      * @param string $suffix Add a suffix to the url |      * @param string $suffix Add a suffix to the url | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function getBaseUrl($suffix = '') |     public function getBaseUrl($suffix = '') | ||||||
| @@ -106,7 +101,6 @@ class Url | |||||||
|      * Get the absolute URL. |      * Get the absolute URL. | ||||||
|      * |      * | ||||||
|      * @param string $base_url Use this url as base url |      * @param string $base_url Use this url as base url | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function getAbsoluteUrl($base_url = '') |     public function getAbsoluteUrl($base_url = '') | ||||||
| @@ -150,7 +144,8 @@ class Url | |||||||
|      * Imported from Guzzle library: https://github.com/guzzle/psr7/blob/master/src/Uri.php#L568-L582 |      * Imported from Guzzle library: https://github.com/guzzle/psr7/blob/master/src/Uri.php#L568-L582 | ||||||
|      * |      * | ||||||
|      * @param $path |      * @param $path | ||||||
|      * |      * @param string $charUnreserved | ||||||
|  |      * @param string $charSubDelims | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function filterPath($path, $charUnreserved = 'a-zA-Z0-9_\-\.~', $charSubDelims = '!\$&\'\(\)\*\+,;=') |     public function filterPath($path, $charUnreserved = 'a-zA-Z0-9_\-\.~', $charSubDelims = '!\$&\'\(\)\*\+,;=') | ||||||
| @@ -226,7 +221,6 @@ class Url | |||||||
|      * Get the scheme. |      * Get the scheme. | ||||||
|      * |      * | ||||||
|      * @param string $suffix Suffix to add when there is a scheme |      * @param string $suffix Suffix to add when there is a scheme | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function getScheme($suffix = '') |     public function getScheme($suffix = '') | ||||||
| @@ -238,12 +232,12 @@ class Url | |||||||
|      * Set the scheme. |      * Set the scheme. | ||||||
|      * |      * | ||||||
|      * @param string $scheme Set a scheme |      * @param string $scheme Set a scheme | ||||||
|      * |      * @return $this | ||||||
|      * @return string |  | ||||||
|      */ |      */ | ||||||
|     public function setScheme($scheme) |     public function setScheme($scheme) | ||||||
|     { |     { | ||||||
|         $this->components['scheme'] = $scheme; |         $this->components['scheme'] = $scheme; | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -260,7 +254,6 @@ class Url | |||||||
|      * Get the port. |      * Get the port. | ||||||
|      * |      * | ||||||
|      * @param string $prefix Prefix to add when there is a port |      * @param string $prefix Prefix to add when there is a port | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function getPort($prefix = '') |     public function getPort($prefix = '') | ||||||
|   | |||||||
| @@ -7,9 +7,11 @@ namespace PicoFeed\Config; | |||||||
|  * |  * | ||||||
|  * @author  Frederic Guillot |  * @author  Frederic Guillot | ||||||
|  * |  * | ||||||
|  |  * @method  \PicoFeed\Config\Config setAdditionalCurlOptions(array $options) | ||||||
|  * @method  \PicoFeed\Config\Config setClientTimeout(integer $value) |  * @method  \PicoFeed\Config\Config setClientTimeout(integer $value) | ||||||
|  * @method  \PicoFeed\Config\Config setClientUserAgent(string $value) |  * @method  \PicoFeed\Config\Config setClientUserAgent(string $value) | ||||||
|  * @method  \PicoFeed\Config\Config setMaxRedirections(integer $value) |  * @method  \PicoFeed\Config\Config setMaxRedirections(integer $value) | ||||||
|  |  * @method  \PicoFeed\Config\Config setMaxRecursions(integer $value) | ||||||
|  * @method  \PicoFeed\Config\Config setMaxBodySize(integer $value) |  * @method  \PicoFeed\Config\Config setMaxBodySize(integer $value) | ||||||
|  * @method  \PicoFeed\Config\Config setProxyHostname(string $value) |  * @method  \PicoFeed\Config\Config setProxyHostname(string $value) | ||||||
|  * @method  \PicoFeed\Config\Config setProxyPort(integer $value) |  * @method  \PicoFeed\Config\Config setProxyPort(integer $value) | ||||||
| @@ -36,6 +38,7 @@ namespace PicoFeed\Config; | |||||||
|  * @method  integer    getClientTimeout() |  * @method  integer    getClientTimeout() | ||||||
|  * @method  string     getClientUserAgent() |  * @method  string     getClientUserAgent() | ||||||
|  * @method  integer    getMaxRedirections() |  * @method  integer    getMaxRedirections() | ||||||
|  |  * @method  integer    getMaxRecursions() | ||||||
|  * @method  integer    getMaxBodySize() |  * @method  integer    getMaxBodySize() | ||||||
|  * @method  string     getProxyHostname() |  * @method  string     getProxyHostname() | ||||||
|  * @method  integer    getProxyPort() |  * @method  integer    getProxyPort() | ||||||
| @@ -59,6 +62,7 @@ namespace PicoFeed\Config; | |||||||
|  * @method  string     getFilterImageProxyUrl() |  * @method  string     getFilterImageProxyUrl() | ||||||
|  * @method  \Closure   getFilterImageProxyCallback() |  * @method  \Closure   getFilterImageProxyCallback() | ||||||
|  * @method  string     getFilterImageProxyProtocol() |  * @method  string     getFilterImageProxyProtocol() | ||||||
|  |  * @method  array      getAdditionalCurlOptions() | ||||||
|  */ |  */ | ||||||
| class Config | class Config | ||||||
| { | { | ||||||
| @@ -92,5 +96,7 @@ class Config | |||||||
|  |  | ||||||
|             return isset($this->container[$parameter]) ? $this->container[$parameter] : $default_value; |             return isset($this->container[$parameter]) ? $this->container[$parameter] : $default_value; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -51,6 +51,7 @@ class Attribute | |||||||
|         'td' => array(), |         'td' => array(), | ||||||
|         'tbody' => array(), |         'tbody' => array(), | ||||||
|         'thead' => array(), |         'thead' => array(), | ||||||
|  |         'h1' => array(), | ||||||
|         'h2' => array(), |         'h2' => array(), | ||||||
|         'h3' => array(), |         'h3' => array(), | ||||||
|         'h4' => array(), |         'h4' => array(), | ||||||
|   | |||||||
| @@ -13,10 +13,8 @@ class Filter | |||||||
|      * Get the Html filter instance. |      * Get the Html filter instance. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $html    HTML content |      * @param string $html    HTML content | ||||||
|      * @param string $website Site URL (used to build absolute URL) |      * @param string $website Site URL (used to build absolute URL) | ||||||
|      * |  | ||||||
|      * @return Html |      * @return Html | ||||||
|      */ |      */ | ||||||
|     public static function html($html, $website) |     public static function html($html, $website) | ||||||
| @@ -30,7 +28,7 @@ class Filter | |||||||
|      * Escape HTML content. |      * Escape HTML content. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |      * @param  string $content | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public static function escape($content) |     public static function escape($content) | ||||||
| @@ -42,7 +40,6 @@ class Filter | |||||||
|      * Remove HTML tags. |      * Remove HTML tags. | ||||||
|      * |      * | ||||||
|      * @param string $data Input data |      * @param string $data Input data | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function removeHTMLTags($data) |     public function removeHTMLTags($data) | ||||||
| @@ -54,9 +51,7 @@ class Filter | |||||||
|      * Remove the XML tag from a document. |      * Remove the XML tag from a document. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $data Input data |      * @param string $data Input data | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public static function stripXmlTag($data) |     public static function stripXmlTag($data) | ||||||
| @@ -80,9 +75,7 @@ class Filter | |||||||
|      * Strip head tag from the HTML content. |      * Strip head tag from the HTML content. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $data Input data |      * @param string $data Input data | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public static function stripHeadTags($data) |     public static function stripHeadTags($data) | ||||||
| @@ -94,9 +87,7 @@ class Filter | |||||||
|      * Trim whitespace from the begining, the end and inside a string and don't break utf-8 string. |      * Trim whitespace from the begining, the end and inside a string and don't break utf-8 string. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $value Raw data |      * @param string $value Raw data | ||||||
|      * |  | ||||||
|      * @return string Normalized data |      * @return string Normalized data | ||||||
|      */ |      */ | ||||||
|     public static function stripWhiteSpace($value) |     public static function stripWhiteSpace($value) | ||||||
| @@ -112,9 +103,7 @@ class Filter | |||||||
|      * Fixes before XML parsing. |      * Fixes before XML parsing. | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $data Raw data |      * @param string $data Raw data | ||||||
|      * |  | ||||||
|      * @return string Normalized data |      * @return string Normalized data | ||||||
|      */ |      */ | ||||||
|     public static function normalizeData($data) |     public static function normalizeData($data) | ||||||
|   | |||||||
| @@ -90,7 +90,6 @@ class Html | |||||||
|      * Set config object. |      * Set config object. | ||||||
|      * |      * | ||||||
|      * @param \PicoFeed\Config\Config $config Config instance |      * @param \PicoFeed\Config\Config $config Config instance | ||||||
|      * |  | ||||||
|      * @return \PicoFeed\Filter\Html |      * @return \PicoFeed\Filter\Html | ||||||
|      */ |      */ | ||||||
|     public function setConfig($config) |     public function setConfig($config) | ||||||
| @@ -160,7 +159,8 @@ class Html | |||||||
|     /** |     /** | ||||||
|      * Called after XML parsing. |      * Called after XML parsing. | ||||||
|      * |      * | ||||||
|      * @param string $content the content that should be filtered |      * @param  string $content | ||||||
|  |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function filterRules($content) |     public function filterRules($content) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ class Tag extends Base | |||||||
|         'td', |         'td', | ||||||
|         'tbody', |         'tbody', | ||||||
|         'thead', |         'thead', | ||||||
|  |         'h1', | ||||||
|         'h2', |         'h2', | ||||||
|         'h3', |         'h3', | ||||||
|         'h4', |         'h4', | ||||||
| @@ -67,6 +68,8 @@ class Tag extends Base | |||||||
|         'abbr', |         'abbr', | ||||||
|         'iframe', |         'iframe', | ||||||
|         'q', |         'q', | ||||||
|  |         'sup', | ||||||
|  |         'sub', | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -74,7 +77,6 @@ class Tag extends Base | |||||||
|      * |      * | ||||||
|      * @param string $tag        Tag name |      * @param string $tag        Tag name | ||||||
|      * @param array  $attributes Attributes dictionary |      * @param array  $attributes Attributes dictionary | ||||||
|      * |  | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
|     public function isAllowed($tag, array $attributes) |     public function isAllowed($tag, array $attributes) | ||||||
| @@ -87,7 +89,6 @@ class Tag extends Base | |||||||
|      * |      * | ||||||
|      * @param string $tag        Tag name |      * @param string $tag        Tag name | ||||||
|      * @param string $attributes Attributes converted in html |      * @param string $attributes Attributes converted in html | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function openHtmlTag($tag, $attributes = '') |     public function openHtmlTag($tag, $attributes = '') | ||||||
| @@ -99,7 +100,6 @@ class Tag extends Base | |||||||
|      * Return the HTML closing tag. |      * Return the HTML closing tag. | ||||||
|      * |      * | ||||||
|      * @param string $tag Tag name |      * @param string $tag Tag name | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function closeHtmlTag($tag) |     public function closeHtmlTag($tag) | ||||||
| @@ -111,7 +111,6 @@ class Tag extends Base | |||||||
|      * Return true is the tag is self-closing. |      * Return true is the tag is self-closing. | ||||||
|      * |      * | ||||||
|      * @param string $tag Tag name |      * @param string $tag Tag name | ||||||
|      * |  | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
|     public function isSelfClosingTag($tag) |     public function isSelfClosingTag($tag) | ||||||
| @@ -123,7 +122,6 @@ class Tag extends Base | |||||||
|      * Check if a tag is on the whitelist. |      * Check if a tag is on the whitelist. | ||||||
|      * |      * | ||||||
|      * @param string $tag Tag name |      * @param string $tag Tag name | ||||||
|      * |  | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
|     public function isAllowedTag($tag) |     public function isAllowedTag($tag) | ||||||
| @@ -139,7 +137,6 @@ class Tag extends Base | |||||||
|      * |      * | ||||||
|      * @param string $tag        Tag name |      * @param string $tag        Tag name | ||||||
|      * @param array  $attributes Tag attributes |      * @param array  $attributes Tag attributes | ||||||
|      * |  | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
|     public function isPixelTracker($tag, array $attributes) |     public function isPixelTracker($tag, array $attributes) | ||||||
| @@ -153,7 +150,6 @@ class Tag extends Base | |||||||
|      * Remove script tags. |      * Remove script tags. | ||||||
|      * |      * | ||||||
|      * @param string $data Input data |      * @param string $data Input data | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function removeBlacklistedTags($data) |     public function removeBlacklistedTags($data) | ||||||
| @@ -179,7 +175,6 @@ class Tag extends Base | |||||||
|      * Remove empty tags. |      * Remove empty tags. | ||||||
|      * |      * | ||||||
|      * @param string $data Input data |      * @param string $data Input data | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function removeEmptyTags($data) |     public function removeEmptyTags($data) | ||||||
| @@ -191,7 +186,6 @@ class Tag extends Base | |||||||
|      * Replace <br/><br/> by only one. |      * Replace <br/><br/> by only one. | ||||||
|      * |      * | ||||||
|      * @param string $data Input data |      * @param string $data Input data | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function removeMultipleBreakTags($data) |     public function removeMultipleBreakTags($data) | ||||||
| @@ -203,7 +197,6 @@ class Tag extends Base | |||||||
|      * Set whitelisted tags adn attributes for each tag. |      * Set whitelisted tags adn attributes for each tag. | ||||||
|      * |      * | ||||||
|      * @param array $values List of tags: ['video' => ['src', 'cover'], 'img' => ['src']] |      * @param array $values List of tags: ['video' => ['src', 'cover'], 'img' => ['src']] | ||||||
|      * |  | ||||||
|      * @return Tag |      * @return Tag | ||||||
|      */ |      */ | ||||||
|     public function setWhitelistedTags(array $values) |     public function setWhitelistedTags(array $values) | ||||||
|   | |||||||
| @@ -25,8 +25,7 @@ class Atom extends Parser | |||||||
|      * Get the path to the items XML tree. |      * Get the path to the items XML tree. | ||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $xml Feed xml |      * @param SimpleXMLElement $xml Feed xml | ||||||
|      * |      * @return SimpleXMLElement[] | ||||||
|      * @return SimpleXMLElement |  | ||||||
|      */ |      */ | ||||||
|     public function getItemsTree(SimpleXMLElement $xml) |     public function getItemsTree(SimpleXMLElement $xml) | ||||||
|     { |     { | ||||||
| @@ -288,12 +287,25 @@ class Atom extends Parser | |||||||
|         $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); |         $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Find the item categories. | ||||||
|  |      * | ||||||
|  |      * @param SimpleXMLElement      $entry Feed item | ||||||
|  |      * @param Item $item  Item object | ||||||
|  |      * @param Feed $feed  Feed object | ||||||
|  |      */ | ||||||
|  |     public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) | ||||||
|  |     { | ||||||
|  |         $categories = XmlParser::getXPathResult($entry, 'atom:category/@term', $this->namespaces) | ||||||
|  |                  ?: XmlParser::getXPathResult($entry, 'category/@term'); | ||||||
|  |         $item->setCategoriesFromXml($categories); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Get the URL from a link tag. |      * Get the URL from a link tag. | ||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $xml XML tag |      * @param SimpleXMLElement $xml XML tag | ||||||
|      * @param string           $rel Link relationship: alternate, enclosure, related, self, via |      * @param string           $rel Link relationship: alternate, enclosure, related, self, via | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     private function getUrl(SimpleXMLElement $xml, $rel, $fallback = false) |     private function getUrl(SimpleXMLElement $xml, $rel, $fallback = false) | ||||||
| @@ -317,7 +329,6 @@ class Atom extends Parser | |||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $xml XML tag |      * @param SimpleXMLElement $xml XML tag | ||||||
|      * @param string           $rel Link relationship: alternate, enclosure, related, self, via |      * @param string           $rel Link relationship: alternate, enclosure, related, self, via | ||||||
|      * |  | ||||||
|      * @return SimpleXMLElement|null |      * @return SimpleXMLElement|null | ||||||
|      */ |      */ | ||||||
|     private function findLink(SimpleXMLElement $xml, $rel) |     private function findLink(SimpleXMLElement $xml, $rel) | ||||||
| @@ -338,7 +349,6 @@ class Atom extends Parser | |||||||
|      * Get the entry content. |      * Get the entry content. | ||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $entry XML Entry |      * @param SimpleXMLElement $entry XML Entry | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     private function getContent(SimpleXMLElement $entry) |     private function getContent(SimpleXMLElement $entry) | ||||||
|   | |||||||
| @@ -38,6 +38,7 @@ class DateParser extends Base | |||||||
|         DATE_RFC1123 => null, |         DATE_RFC1123 => null, | ||||||
|         DATE_RFC2822 => null, |         DATE_RFC2822 => null, | ||||||
|         DATE_RFC3339 => null, |         DATE_RFC3339 => null, | ||||||
|  |         'l, d M Y H:i:s' => null, | ||||||
|         'D, d M Y H:i:s' => 25, |         'D, d M Y H:i:s' => 25, | ||||||
|         'D, d M Y h:i:s' => 25, |         'D, d M Y h:i:s' => 25, | ||||||
|         'D M d Y H:i:s' => 24, |         'D M d Y H:i:s' => 24, | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ class Feed | |||||||
|     /** |     /** | ||||||
|      * Feed items. |      * Feed items. | ||||||
|      * |      * | ||||||
|      * @var array |      * @var Item[] | ||||||
|      */ |      */ | ||||||
|     public $items = array(); |     public $items = array(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -103,6 +103,13 @@ class Item | |||||||
|      */ |      */ | ||||||
|     public $language = ''; |     public $language = ''; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Item categories. | ||||||
|  |      * | ||||||
|  |      * @var array | ||||||
|  |      */ | ||||||
|  |     public $categories = array(); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Raw XML. |      * Raw XML. | ||||||
|      * |      * | ||||||
| @@ -169,10 +176,13 @@ class Item | |||||||
|         $publishedDate = $this->publishedDate != null ? $this->publishedDate->format(DATE_RFC822) : null; |         $publishedDate = $this->publishedDate != null ? $this->publishedDate->format(DATE_RFC822) : null; | ||||||
|         $updatedDate = $this->updatedDate != null ? $this->updatedDate->format(DATE_RFC822) : null; |         $updatedDate = $this->updatedDate != null ? $this->updatedDate->format(DATE_RFC822) : null; | ||||||
|  |  | ||||||
|  |         $categoryString = $this->categories != null ? implode(',', $this->categories) : null; | ||||||
|  |  | ||||||
|         $output .= 'Item::date = '.$this->date->format(DATE_RFC822).PHP_EOL; |         $output .= 'Item::date = '.$this->date->format(DATE_RFC822).PHP_EOL; | ||||||
|         $output .= 'Item::publishedDate = '.$publishedDate.PHP_EOL; |         $output .= 'Item::publishedDate = '.$publishedDate.PHP_EOL; | ||||||
|         $output .= 'Item::updatedDate = '.$updatedDate.PHP_EOL; |         $output .= 'Item::updatedDate = '.$updatedDate.PHP_EOL; | ||||||
|         $output .= 'Item::isRTL() = '.($this->isRTL() ? 'true' : 'false').PHP_EOL; |         $output .= 'Item::isRTL() = '.($this->isRTL() ? 'true' : 'false').PHP_EOL; | ||||||
|  |         $output .= 'Item::categories = ['.$categoryString.']'.PHP_EOL; | ||||||
|         $output .= 'Item::content = '.strlen($this->content).' bytes'.PHP_EOL; |         $output .= 'Item::content = '.strlen($this->content).' bytes'.PHP_EOL; | ||||||
|  |  | ||||||
|         return $output; |         return $output; | ||||||
| @@ -305,6 +315,16 @@ class Item | |||||||
|         return $this->language; |         return $this->language; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Get categories. | ||||||
|  |      * | ||||||
|  |      * @return array | ||||||
|  |      */ | ||||||
|  |     public function getCategories() | ||||||
|  |     { | ||||||
|  |         return $this->categories; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Get author. |      * Get author. | ||||||
|      * |      * | ||||||
| @@ -433,6 +453,40 @@ class Item | |||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set item categories. | ||||||
|  |      * | ||||||
|  |      * @param array $categories | ||||||
|  |      * @return Item | ||||||
|  |      */ | ||||||
|  |     public function setCategories($categories) | ||||||
|  |     { | ||||||
|  |         $this->categories = $categories; | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Set item categories from xml. | ||||||
|  |      * | ||||||
|  |      * @param |SimpleXMLElement[] $categories | ||||||
|  |      * @return Item | ||||||
|  |      */ | ||||||
|  |     public function setCategoriesFromXml($categories) | ||||||
|  |     { | ||||||
|  |         if ($categories !== false) { | ||||||
|  |             $this->setCategories( | ||||||
|  |                 array_map( | ||||||
|  |                     function ($element) { | ||||||
|  |                         return trim((string) $element); | ||||||
|  |                     }, | ||||||
|  |                     $categories | ||||||
|  |                 ) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return $this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Set raw XML. |      * Set raw XML. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -103,8 +103,8 @@ abstract class Parser implements ParserInterface | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Parse the document. |      * Parse the document. | ||||||
|      * |      * @return Feed | ||||||
|      * @return \PicoFeed\Parser\Feed |      * @throws MalformedXmlException | ||||||
|      */ |      */ | ||||||
|     public function execute() |     public function execute() | ||||||
|     { |     { | ||||||
| @@ -163,6 +163,7 @@ abstract class Parser implements ParserInterface | |||||||
|             $this->findItemDate($entry, $item, $feed); |             $this->findItemDate($entry, $item, $feed); | ||||||
|             $this->findItemEnclosure($entry, $item, $feed); |             $this->findItemEnclosure($entry, $item, $feed); | ||||||
|             $this->findItemLanguage($entry, $item, $feed); |             $this->findItemLanguage($entry, $item, $feed); | ||||||
|  |             $this->findItemCategories($entry, $item, $feed); | ||||||
|  |  | ||||||
|             $this->itemPostProcessor->execute($feed, $item); |             $this->itemPostProcessor->execute($feed, $item); | ||||||
|             $feed->items[] = $item; |             $feed->items[] = $item; | ||||||
| @@ -222,18 +223,20 @@ abstract class Parser implements ParserInterface | |||||||
|     public function findItemDate(SimpleXMLElement $entry, Item $item, Feed $feed) |     public function findItemDate(SimpleXMLElement $entry, Item $item, Feed $feed) | ||||||
|     { |     { | ||||||
|         $this->findItemPublishedDate($entry, $item, $feed); |         $this->findItemPublishedDate($entry, $item, $feed); | ||||||
|         $published = $item->getPublishedDate(); |  | ||||||
|  |  | ||||||
|         $this->findItemUpdatedDate($entry, $item, $feed); |         $this->findItemUpdatedDate($entry, $item, $feed); | ||||||
|         $updated = $item->getUpdatedDate(); |  | ||||||
|  |  | ||||||
|         if ($published === null && $updated === null) { |         if ($item->getPublishedDate() === null) { | ||||||
|             $item->setDate($feed->getDate()); // We use the feed date if there is no date for the item |             // Use the updated date if available, otherwise use the feed date | ||||||
|         } elseif ($published !== null && $updated !== null) { |             $item->setPublishedDate($item->getUpdatedDate() ?: $feed->getDate()); | ||||||
|             $item->setDate(max($published, $updated)); // We use the most recent date between published and updated |  | ||||||
|         } else { |  | ||||||
|             $item->setDate($updated ?: $published); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if ($item->getUpdatedDate() === null) { | ||||||
|  |             // Use the published date as fallback | ||||||
|  |             $item->setUpdatedDate($item->getPublishedDate()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Use the most recent of published and updated dates | ||||||
|  |         $item->setDate(max($item->getPublishedDate(), $item->getUpdatedDate())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -256,7 +259,7 @@ abstract class Parser implements ParserInterface | |||||||
|     public function getDateParser() |     public function getDateParser() | ||||||
|     { |     { | ||||||
|         if ($this->dateParser === null) { |         if ($this->dateParser === null) { | ||||||
|             return new DateParser($this->config); |             $this->dateParser = new DateParser($this->config); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return $this->dateParser; |         return $this->dateParser; | ||||||
| @@ -276,9 +279,7 @@ abstract class Parser implements ParserInterface | |||||||
|      * Return true if the given language is "Right to Left". |      * Return true if the given language is "Right to Left". | ||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * |  | ||||||
|      * @param string $language Language: fr-FR, en-US |      * @param string $language Language: fr-FR, en-US | ||||||
|      * |  | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
|     public static function isLanguageRTL($language) |     public static function isLanguageRTL($language) | ||||||
| @@ -321,12 +322,12 @@ abstract class Parser implements ParserInterface | |||||||
|      * Set config object. |      * Set config object. | ||||||
|      * |      * | ||||||
|      * @param \PicoFeed\Config\Config $config Config instance |      * @param \PicoFeed\Config\Config $config Config instance | ||||||
|      * |  | ||||||
|      * @return \PicoFeed\Parser\Parser |      * @return \PicoFeed\Parser\Parser | ||||||
|      */ |      */ | ||||||
|     public function setConfig($config) |     public function setConfig($config) | ||||||
|     { |     { | ||||||
|         $this->config = $config; |         $this->config = $config; | ||||||
|  |         $this->itemPostProcessor->setConfig($config); | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -348,7 +349,6 @@ abstract class Parser implements ParserInterface | |||||||
|      *                                       scraped |      *                                       scraped | ||||||
|      * @param null|\Closure $scraperCallback Callback function that gets called for each |      * @param null|\Closure $scraperCallback Callback function that gets called for each | ||||||
|      *                                       scraper execution |      *                                       scraper execution | ||||||
|      * |  | ||||||
|      * @return \PicoFeed\Parser\Parser |      * @return \PicoFeed\Parser\Parser | ||||||
|      */ |      */ | ||||||
|     public function enableContentGrabber($needsRuleFile = false, $scraperCallback = null) |     public function enableContentGrabber($needsRuleFile = false, $scraperCallback = null) | ||||||
| @@ -371,7 +371,6 @@ abstract class Parser implements ParserInterface | |||||||
|      * Set ignored URLs for the content grabber. |      * Set ignored URLs for the content grabber. | ||||||
|      * |      * | ||||||
|      * @param array $urls URLs |      * @param array $urls URLs | ||||||
|      * |  | ||||||
|      * @return \PicoFeed\Parser\Parser |      * @return \PicoFeed\Parser\Parser | ||||||
|      */ |      */ | ||||||
|     public function setGrabberIgnoreUrls(array $urls) |     public function setGrabberIgnoreUrls(array $urls) | ||||||
| @@ -384,7 +383,6 @@ abstract class Parser implements ParserInterface | |||||||
|      * Register all supported namespaces to be used within an xpath query. |      * Register all supported namespaces to be used within an xpath query. | ||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $xml Feed xml |      * @param SimpleXMLElement $xml Feed xml | ||||||
|      * |  | ||||||
|      * @return SimpleXMLElement |      * @return SimpleXMLElement | ||||||
|      */ |      */ | ||||||
|     public function registerSupportedNamespaces(SimpleXMLElement $xml) |     public function registerSupportedNamespaces(SimpleXMLElement $xml) | ||||||
| @@ -395,6 +393,4 @@ abstract class Parser implements ParserInterface | |||||||
|  |  | ||||||
|         return $xml; |         return $xml; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -170,4 +170,13 @@ interface ParserInterface | |||||||
|      * @param Feed $feed  Feed object |      * @param Feed $feed  Feed object | ||||||
|      */ |      */ | ||||||
|     public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed); |     public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Find the item categories. | ||||||
|  |      * | ||||||
|  |      * @param SimpleXMLElement      $entry Feed item | ||||||
|  |      * @param Item $item  Item object | ||||||
|  |      * @param Feed $feed  Feed object | ||||||
|  |      */ | ||||||
|  |     public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -27,8 +27,7 @@ class Rss10 extends Parser | |||||||
|      * Get the path to the items XML tree. |      * Get the path to the items XML tree. | ||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $xml Feed xml |      * @param SimpleXMLElement $xml Feed xml | ||||||
|      * |      * @return SimpleXMLElement[] | ||||||
|      * @return SimpleXMLElement |  | ||||||
|      */ |      */ | ||||||
|     public function getItemsTree(SimpleXMLElement $xml) |     public function getItemsTree(SimpleXMLElement $xml) | ||||||
|     { |     { | ||||||
| @@ -290,4 +289,17 @@ class Rss10 extends Parser | |||||||
|  |  | ||||||
|         $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); |         $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Find the item categories. | ||||||
|  |      * | ||||||
|  |      * @param SimpleXMLElement      $entry Feed item | ||||||
|  |      * @param Item $item  Item object | ||||||
|  |      * @param Feed $feed  Feed object | ||||||
|  |      */ | ||||||
|  |     public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) | ||||||
|  |     { | ||||||
|  |         $categories = XmlParser::getXPathResult($entry, 'dc:subject', $this->namespaces); | ||||||
|  |         $item->setCategoriesFromXml($categories); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,8 +28,7 @@ class Rss20 extends Parser | |||||||
|      * Get the path to the items XML tree. |      * Get the path to the items XML tree. | ||||||
|      * |      * | ||||||
|      * @param SimpleXMLElement $xml Feed xml |      * @param SimpleXMLElement $xml Feed xml | ||||||
|      * |      * @return SimpleXMLElement[] | ||||||
|      * @return SimpleXMLElement |  | ||||||
|      */ |      */ | ||||||
|     public function getItemsTree(SimpleXMLElement $xml) |     public function getItemsTree(SimpleXMLElement $xml) | ||||||
|     { |     { | ||||||
| @@ -302,4 +301,17 @@ class Rss20 extends Parser | |||||||
|         $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); |         $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); | ||||||
|         $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); |         $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Find the item categories. | ||||||
|  |      * | ||||||
|  |      * @param SimpleXMLElement      $entry Feed item | ||||||
|  |      * @param Item $item  Item object | ||||||
|  |      * @param Feed $feed  Feed object | ||||||
|  |      */ | ||||||
|  |     public function findItemCategories(SimpleXMLElement $entry, Item $item, Feed $feed) | ||||||
|  |     { | ||||||
|  |         $categories = XmlParser::getXPathResult($entry, 'category'); | ||||||
|  |         $item->setCategoriesFromXml($categories); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ class XmlParser | |||||||
|      * |      * | ||||||
|      * @static |      * @static | ||||||
|      * @param string $input XML content |      * @param string $input XML content | ||||||
|      * @return DOMDocument |      * @return DOMDocument|bool | ||||||
|      */ |      */ | ||||||
|     public static function getDomDocument($input) |     public static function getDomDocument($input) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -33,5 +33,7 @@ class ContentFilterProcessor extends Base implements ItemProcessorInterface | |||||||
|         } else { |         } else { | ||||||
|             Logger::setMessage(get_called_class().': Content filtering disabled'); |             Logger::setMessage(get_called_class().': Content filtering disabled'); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ namespace PicoFeed\Processor; | |||||||
| use PicoFeed\Base; | use PicoFeed\Base; | ||||||
| use PicoFeed\Parser\Feed; | use PicoFeed\Parser\Feed; | ||||||
| use PicoFeed\Parser\Item; | use PicoFeed\Parser\Item; | ||||||
|  | use PicoFeed\Config\Config; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Item Post Processor |  * Item Post Processor | ||||||
| @@ -71,7 +72,7 @@ class ItemPostProcessor extends Base | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Checks wheather a specific processor is registered or not |      * Checks whether a specific processor is registered or not | ||||||
|      * |      * | ||||||
|      * @access public |      * @access public | ||||||
|      * @param  string $class |      * @param  string $class | ||||||
| @@ -93,4 +94,13 @@ class ItemPostProcessor extends Base | |||||||
|     { |     { | ||||||
|         return isset($this->processors[$class]) ? $this->processors[$class] : null; |         return isset($this->processors[$class]) ? $this->processors[$class] : null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function setConfig(Config $config) | ||||||
|  |     { | ||||||
|  |         foreach ($this->processors as $processor) { | ||||||
|  |             $processor->setConfig($config); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ class Favicon extends Base | |||||||
|         'image/x-icon', |         'image/x-icon', | ||||||
|         'image/jpeg', |         'image/jpeg', | ||||||
|         'image/jpg', |         'image/jpg', | ||||||
|         'image/svg+xml' |         'image/svg+xml', | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -95,8 +95,7 @@ class Favicon extends Base | |||||||
|      * Download and check if a resource exists. |      * Download and check if a resource exists. | ||||||
|      * |      * | ||||||
|      * @param string $url URL |      * @param string $url URL | ||||||
|      * |      * @return \PicoFeed\Client\Client Client instance | ||||||
|      * @return \PicoFeed\Client Client instance |  | ||||||
|      */ |      */ | ||||||
|     public function download($url) |     public function download($url) | ||||||
|     { |     { | ||||||
| @@ -118,7 +117,6 @@ class Favicon extends Base | |||||||
|      * Check if a remote file exists. |      * Check if a remote file exists. | ||||||
|      * |      * | ||||||
|      * @param string $url URL |      * @param string $url URL | ||||||
|      * |  | ||||||
|      * @return bool |      * @return bool | ||||||
|      */ |      */ | ||||||
|     public function exists($url) |     public function exists($url) | ||||||
| @@ -131,7 +129,6 @@ class Favicon extends Base | |||||||
|      * |      * | ||||||
|      * @param string $website_link URL |      * @param string $website_link URL | ||||||
|      * @param string $favicon_link optional URL |      * @param string $favicon_link optional URL | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function find($website_link, $favicon_link = '') |     public function find($website_link, $favicon_link = '') | ||||||
| @@ -165,7 +162,6 @@ class Favicon extends Base | |||||||
|      * Extract the icon links from the HTML. |      * Extract the icon links from the HTML. | ||||||
|      * |      * | ||||||
|      * @param string $html HTML |      * @param string $html HTML | ||||||
|      * |  | ||||||
|      * @return array |      * @return array | ||||||
|      */ |      */ | ||||||
|     public function extract($html) |     public function extract($html) | ||||||
| @@ -179,7 +175,7 @@ class Favicon extends Base | |||||||
|         $dom = XmlParser::getHtmlDocument($html); |         $dom = XmlParser::getHtmlDocument($html); | ||||||
|  |  | ||||||
|         $xpath = new DOMXpath($dom); |         $xpath = new DOMXpath($dom); | ||||||
|         $elements = $xpath->query('//link[@rel="icon" or @rel="shortcut icon" or @rel="icon shortcut"]'); |         $elements = $xpath->query('//link[@rel="icon" or @rel="shortcut icon" or @rel="Shortcut Icon" or @rel="icon shortcut"]'); | ||||||
|  |  | ||||||
|         for ($i = 0; $i < $elements->length; ++$i) { |         for ($i = 0; $i < $elements->length; ++$i) { | ||||||
|             $icons[] = $elements->item($i)->getAttribute('href'); |             $icons[] = $elements->item($i)->getAttribute('href'); | ||||||
|   | |||||||
| @@ -56,13 +56,13 @@ class Reader extends Base | |||||||
|     /** |     /** | ||||||
|      * Discover and download a feed. |      * Discover and download a feed. | ||||||
|      * |      * | ||||||
|      * @param string $url           Feed or website url |      * @param string $url Feed or website url | ||||||
|      * @param string $last_modified Last modified HTTP header |      * @param string $last_modified Last modified HTTP header | ||||||
|      * @param string $etag          Etag HTTP header |      * @param string $etag Etag HTTP header | ||||||
|      * @param string $username      HTTP basic auth username |      * @param string $username HTTP basic auth username | ||||||
|      * @param string $password      HTTP basic auth password |      * @param string $password HTTP basic auth password | ||||||
|      * |      * @return Client | ||||||
|      * @return \PicoFeed\Client\Client |      * @throws SubscriptionNotFoundException | ||||||
|      */ |      */ | ||||||
|     public function discover($url, $last_modified = '', $etag = '', $username = '', $password = '') |     public function discover($url, $last_modified = '', $etag = '', $username = '', $password = '') | ||||||
|     { |     { | ||||||
| @@ -127,11 +127,11 @@ class Reader extends Base | |||||||
|     /** |     /** | ||||||
|      * Get a parser instance. |      * Get a parser instance. | ||||||
|      * |      * | ||||||
|      * @param string $url      Site url |      * @param string $url Site url | ||||||
|      * @param string $content  Feed content |      * @param string $content Feed content | ||||||
|      * @param string $encoding HTTP encoding |      * @param string $encoding HTTP encoding | ||||||
|      * |  | ||||||
|      * @return \PicoFeed\Parser\Parser |      * @return \PicoFeed\Parser\Parser | ||||||
|  |      * @throws UnsupportedFeedFormatException | ||||||
|      */ |      */ | ||||||
|     public function getParser($url, $content, $encoding) |     public function getParser($url, $content, $encoding) | ||||||
|     { |     { | ||||||
| @@ -154,7 +154,6 @@ class Reader extends Base | |||||||
|      * Detect the feed format. |      * Detect the feed format. | ||||||
|      * |      * | ||||||
|      * @param string $content Feed content |      * @param string $content Feed content | ||||||
|      * |  | ||||||
|      * @return string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function detectFormat($content) |     public function detectFormat($content) | ||||||
| @@ -177,7 +176,7 @@ class Reader extends Base | |||||||
|      * Add the prefix "http://" if the end-user just enter a domain name. |      * Add the prefix "http://" if the end-user just enter a domain name. | ||||||
|      * |      * | ||||||
|      * @param string $url Url |      * @param string $url Url | ||||||
|      * @retunr string |      * @return string | ||||||
|      */ |      */ | ||||||
|     public function prependScheme($url) |     public function prependScheme($url) | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ return array( | |||||||
|             'body' => array( |             'body' => array( | ||||||
|                 '//div[@class="content"]', |                 '//div[@class="content"]', | ||||||
|             ), |             ), | ||||||
|             'strip' => array() |             'strip' => array(), | ||||||
|         ) |         ), | ||||||
|     ) |     ), | ||||||
| ); | ); | ||||||
|   | |||||||
| @@ -4,28 +4,41 @@ return array( | |||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|             'test_url' => 'http://www.wired.com/gamelife/2013/09/ouya-free-the-games/', |             'test_url' => 'http://www.wired.com/gamelife/2013/09/ouya-free-the-games/', | ||||||
|             'body' => array( |             'body' => array( | ||||||
|                  '//div[@data-js="gallerySlides"]', |                 '//div[@data-js="gallerySlides"]', | ||||||
|                  '//article', |                  '//div[starts-with(@class,"post")]', | ||||||
|             ), |             ), | ||||||
|             'strip' => array( |             'strip' => array( | ||||||
|                 '//*[@id="linker_widget"]', |                 '//h1', | ||||||
|                 '//*[@class="credit"]', |                 '//nav', | ||||||
|                 '//div[@data-js="slideCount"]', |                 '//button', | ||||||
|                 '//*[contains(@class="visually-hidden")]', |                 '//figure[starts-with(@class,"rad-slide")]', | ||||||
|                 '//*[@data-slide-number="_endslate"]', |                 '//figure[starts-with(@class,"end-slate")]', | ||||||
|                 '//*[@id="related"]', |                 '//div[contains(@class,"mobile-")]', | ||||||
|                 '//*[contains(@class, "bio")]', |                 '//div[starts-with(@class,"mob-gallery-launcher")]', | ||||||
|                 '//*[contains(@class, "entry-footer")]', |                 '//div[contains(@id,"mobile-")]', | ||||||
|                 '//*[contains(@class, "mobify_backtotop_link")]', |                 '//span[contains(@class,"slide-count")]', | ||||||
|                 '//*[contains(@class, "gallery-navigation")]', |                 '//div[contains(@class,"show-ipad")]', | ||||||
|                 '//*[contains(@class, "gallery-thumbnail")]', |                 '//img[contains(@id,"-hero-bg")]', | ||||||
|                 '//img[contains(@src, "1x1")]', |                 '//div[@data-js="overlayWrap"]', | ||||||
|                 '//a[contains(@href, "creativecommons")]', |                 '//ul[contains(@class,"metadata")]', | ||||||
|                 '//a[@href="#start-of-content"]', |                 '//div[@class="opening center"]', | ||||||
|  |                 '//p[contains(@class="byline-mob"]', | ||||||
|  |                 '//div[@id="o-gallery"]', | ||||||
|  |                 '//div[starts-with(@class,"sm-col")]', | ||||||
|  |                 '//div[contains(@class,"pad-b-huge")]', | ||||||
|  |                 '//a[contains(@class,"visually-hidden")]', | ||||||
|  |                 '//*[@class="social"]', | ||||||
|  |                 '//i', | ||||||
|  |                 '//div[@data-js="mobGalleryAd"]', | ||||||
|  |                 '//div[contains(@class,"footer")]', | ||||||
|  |                 '//div[contains(@data-js,"fader")]', | ||||||
|  |                 '//div[@id="sharing"]', | ||||||
|  |                 '//div[contains(@id,"related")]', | ||||||
|  |                 '//div[@id="most-pop"]', | ||||||
|                 '//ul[@id="article-tags"]', |                 '//ul[@id="article-tags"]', | ||||||
|  |                 '//style', | ||||||
|  |                 '//section[contains(@class,"footer")]' | ||||||
|             ), |             ), | ||||||
|         ) |         ) | ||||||
|     ) |     ) | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'filter' => array( |     'filter' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%^/news.*%' => array( |         '%^/news.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,21 +1,24 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|             'test_url' => 'http://www.aljazeera.com/news/2015/09/xi-jinping-seattle-china-150922230118373.html', |             'test_url' => 'http://www.aljazeera.com/news/2015/09/xi-jinping-seattle-china-150922230118373.html', | ||||||
|             'body' => array( |             'body' => array( | ||||||
|                 '//figure[@class="article-content"]', |                 '//article[@id="main-story"]', | ||||||
|                 '//div[@class="article-body"]', |  | ||||||
|             ), |             ), | ||||||
|             'strip' => array( |             'strip' => array( | ||||||
|                 '//h1', |                 '//script', | ||||||
|                 '//h3', |                 '//header', | ||||||
|                 '//ul', |                 '//ul', | ||||||
|                 '//table[contains(@class, "in-article-item")]', |                 '//section[contains(@class,"profile")]', | ||||||
|                 '//a[@target="_self"]', |                 '//a[@target="_self"]', | ||||||
|  |                 '//div[contains(@id,"_2")]', | ||||||
|  |                 '//div[contains(@id,"_3")]', | ||||||
|  |                 '//img[@class="viewMode"]', | ||||||
|  |                 '//table[contains(@class,"in-article-item")]', | ||||||
|                 '//div[@data-embed-type="Brightcove"]', |                 '//div[@data-embed-type="Brightcove"]', | ||||||
|                 '//div[@class="QuoteContainer"]', |                 '//div[@class="QuoteContainer"]', | ||||||
|  |                 '//div[@class="BottomByLine"]', | ||||||
|             ), |             ), | ||||||
|         ), |         ), | ||||||
|     ), |     ), | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
| @@ -10,6 +9,7 @@ return array( | |||||||
|             'strip' => array( |             'strip' => array( | ||||||
|             '//p[@class="kindofstory"]', |             '//p[@class="kindofstory"]', | ||||||
|             '//cite[@class="byline"]', |             '//cite[@class="byline"]', | ||||||
|  |             '//div[@class="useful-top"]', | ||||||
|             '//div[contains(@class,"related-topics")]', |             '//div[contains(@class,"related-topics")]', | ||||||
|             '//links', |             '//links', | ||||||
|             '//sharebar', |             '//sharebar', | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'filter' => array( |     'filter' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,23 +1,25 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|             'test_url' => 'http://arstechnica.com/tech-policy/2015/09/judge-warners-2m-happy-birthday-copyright-is-bogus/', |             'test_url' => 'http://arstechnica.com/tech-policy/2015/09/judge-warners-2m-happy-birthday-copyright-is-bogus/', | ||||||
|             'body' => array( |             'body' => array( | ||||||
|                 '//header/h2', |                 '//article', | ||||||
|                 '//section[@id="article-guts"]', |  | ||||||
|                 '//div[@class="superscroll-content show"]', |  | ||||||
|                 '//div[@class="gallery"]', |  | ||||||
|             ), |             ), | ||||||
|             'next_page' => '//span[@class="numbers"]/a', |  | ||||||
|             'strip' => array( |             'strip' => array( | ||||||
|  |                 '//h4[@class="post-upperdek"]', | ||||||
|  |                 '//h1', | ||||||
|  |                 '//ul[@class="lSPager lSGallery"]', | ||||||
|  |                 '//div[@class="lSAction"]', | ||||||
|  |                 '//section[@class="post-meta"]', | ||||||
|                 '//figcaption', |                 '//figcaption', | ||||||
|                 '//div[@class="post-meta"]', |  | ||||||
|                 '//div[@class="gallery-image-credit"]', |  | ||||||
|                 '//aside', |                 '//aside', | ||||||
|                 '//div[@class="article-expander"]', |                 '//div[@class="gallery-image-credit"]', | ||||||
|  |                 '//section[@class="article-author"]', | ||||||
|  |                 '//*[contains(@id,"social-")]', | ||||||
|  |                 '//div[contains(@id,"footer")]', | ||||||
|             ), |             ), | ||||||
|         ), |         ), | ||||||
|     ), |     ), | ||||||
| ); | ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%/index.php.*comic=.*%' => array( |         '%/index.php.*comic=.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/backchannel.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/backchannel.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'https://medium.com/lessons-learned/917b8b63ae3e', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//div[contains(@class,"section-inner")]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//div[contains(@class,"metabar")]', | ||||||
|  |                 '//img[contains(@class,"thumbnail")]', | ||||||
|  |                 '//h1', | ||||||
|  |                 '//blockquote', | ||||||
|  |                 '//p[contains(@class,"graf-after--h4")]' | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
| @@ -1,11 +1,10 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|             'test_url' => 'http://www.bangkokpost.com/news/politics/704204/new-us-ambassador-arrives-in-bangkok', |             'test_url' => 'http://www.bangkokpost.com/news/politics/704204/new-us-ambassador-arrives-in-bangkok', | ||||||
|             'body' => array( |             'body' => array( | ||||||
|             '//div[@class="articleContents"]', |             '//article/div[@class="articleContents"]', | ||||||
|             ), |             ), | ||||||
|             'strip' => array( |             'strip' => array( | ||||||
|             '//h2', |             '//h2', | ||||||
| @@ -13,7 +12,6 @@ return array( | |||||||
|             '//div[@class="text-size"]', |             '//div[@class="text-size"]', | ||||||
|             '//div[@class="relate-story"]', |             '//div[@class="relate-story"]', | ||||||
|             '//div[@class="text-ads"]', |             '//div[@class="text-ads"]', | ||||||
|             '//script', |  | ||||||
|             '//ul', |             '//ul', | ||||||
|             ), |             ), | ||||||
|         ), |         ), | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'filter' => array( |     'filter' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/bigpicture.ru.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'http://bigpicture.ru/?p=556658', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//div[@class="article container"]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//script', | ||||||
|  |                 '//form', | ||||||
|  |                 '//style', | ||||||
|  |                 '//h1', | ||||||
|  |                 '//*[@class="wp-smiley"]', | ||||||
|  |                 '//div[@class="ipmd"]', | ||||||
|  |                 '//div[@class="tags"]', | ||||||
|  |                 '//div[@class="social-button"]', | ||||||
|  |                 '//div[@class="bottom-share"]', | ||||||
|  |                 '//div[@class="raccoonbox"]', | ||||||
|  |                 '//div[@class="yndadvert"]', | ||||||
|  |                 '//div[@class="we-recommend"]', | ||||||
|  |                 '//div[@class="relap-bigpicture_ru-wrapper"]', | ||||||
|  |                 '//div[@id="mmail"]', | ||||||
|  |                 '//div[@id="mobile-ads-cut"]', | ||||||
|  |                 '//div[@id="liquidstorm-alt-html"]', | ||||||
|  |                 '//div[contains(@class, "post-tags")]', | ||||||
|  |                 '//*[contains(text(),"Смотрите также")]', | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/biztimes.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/biztimes.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'https://www.biztimes.com/2017/02/10/settlement-would-revive-fowler-lake-condo-project-in-oconomowoc/', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//h2/span[@class="subhead"]', | ||||||
|  |                 '//div[contains(@class,"article-content")]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//script', | ||||||
|  |                 '//div[contains(@class,"mobile-article-content")]', | ||||||
|  |                 '//div[contains(@class,"sharedaddy")]', | ||||||
|  |                 '//div[contains(@class,"author-details")]', | ||||||
|  |                 '//div[@class="row ad"]', | ||||||
|  |                 '//div[contains(@class,"relatedposts")]', | ||||||
|  |                 '//div[@class="col-lg-12"]', | ||||||
|  |                 '//div[contains(@class,"widget")]', | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
							
								
								
									
										15
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/bleepingcomputer.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'https://www.bleepingcomputer.com/news/google/chromes-sandbox-feature-infringes-on-three-patents-so-google-must-now-pay-20m/', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//div[@class="article_section"]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//*[@itemprop="headline"]', | ||||||
|  |                 '//div[@class="cz-news-story-title-section"]' | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/brewers.mlb.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'http://m.brewers.mlb.com/news/article/161364798', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//article[contains(@class,"article")]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//div[contains(@class,"ad-slot")]', | ||||||
|  |                 '//h1', | ||||||
|  |                 '//span[@class="timestamp"]', | ||||||
|  |                 '//div[contains(@class,"contributor-bottom")]', | ||||||
|  |                 '//div[contains(@class,"video")]', | ||||||
|  |                 '//ul[contains(@class,"social")]', | ||||||
|  |                 '//p[@class="tagline"]', | ||||||
|  |                 '//div[contains(@class,"social")]', | ||||||
|  |                 '//div[@class="button-wrap"]', | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%/cad/.+%' => array( |         '%/cad/.+%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/chinafile.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/chinafile.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'http://www.chinafile.com/books/shanghai-faithful?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+chinafile%2FAll+%28ChinaFile%29', | ||||||
|  |             'body' => array( | ||||||
|  |             '//div[contains(@class,"pane-featured-photo-panel-pane-1")]', | ||||||
|  |             '//div[contains(@class,"video-above-fold")]', | ||||||
|  |             '//div[@class="sc-media"]', | ||||||
|  |             '//div[contains(@class,"field-name-body")]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//div[contains(@class,"cboxes")]', | ||||||
|  |                 '//div[contains(@class,"l-middle")]', | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%/comic.*%' => array( |         '%/comic.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
| 		 '%^/products.*%' => array( | 		 '%^/products.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'filter' => array( |     'filter' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/crash.net.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/crash.net.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'http://www.crash.net/motogp/interview/247550/1/exclusive-andrea-dovizioso-interview.html', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//div[@id="content"]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//script', | ||||||
|  |                 '//style', | ||||||
|  |                 '//*[@title="Social Networking"]', | ||||||
|  |                 '//*[@class="crash-ad2"]', | ||||||
|  |                 '//*[@class="clearfix"]', | ||||||
|  |                 '//*[@class="crash-ad2"]', | ||||||
|  |                 '//*[contains(@id, "divCB"]', | ||||||
|  |                 '//*[@class="pnlComment"]', | ||||||
|  |                 '//*[@class="comments-tabs"]', | ||||||
|  |                 '//*[contains(@class, "ad-twocol"]', | ||||||
|  |                 '//*[@class="stories-list"]', | ||||||
|  |                 '//*[contains(@class, "btn")]', | ||||||
|  |                 '//*[@class="content"]', | ||||||
|  |                 '//h3', | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
|  |  | ||||||
| @@ -1,18 +1,18 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|             'test_url' => 'http://www.csmonitor.com/USA/Politics/2015/0925/John-Boehner-steps-down-Self-sacrificing-but-will-it-lead-to-better-government', |             'test_url' => 'http://www.csmonitor.com/USA/Politics/2015/0925/John-Boehner-steps-down-Self-sacrificing-but-will-it-lead-to-better-government', | ||||||
|             'body' => array( |             'body' => array( | ||||||
|             '//figure[@id="image-top-1"]', |                 '//h2[@id="summary"]', | ||||||
|             '//div[@id="story-body"]', |                 '//div[@class="flex-video youtube"]', | ||||||
|  |                 '//div[contains(@class,"eza-body")]', | ||||||
|             ), |             ), | ||||||
|             'strip' => array( |             'strip' => array( | ||||||
|             '//script', |                 '//span[@id="breadcrumb"]', | ||||||
|             '//img[@title="hide caption"]', |                 '//div[@id="byline-wrapper"]', | ||||||
|             '//*[contains(@class,"promo_link")]', |                 '//div[@class="injection"]', | ||||||
|             '//div[@id="story-embed-column"]', |                 '//*[contains(@class,"promo_link")]', | ||||||
|             ), |             ), | ||||||
|         ), |         ), | ||||||
|     ), |     ), | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,17 +1,25 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|             'test_url' => 'http://blogs.discovermagazine.com/the-extremo-files/2015/09/11/have-scientists-found-the-worlds-deepest-fish/', |             'test_url' => 'http://blogs.discovermagazine.com/neuroskeptic/2017/01/25/publishers-jeffrey-beall/', | ||||||
|             'body' => array( |             'body' => array( | ||||||
|             '//div[@class="entry"]', |             '//div[@class="contentWell"]', | ||||||
|             ), |             ), | ||||||
|             'strip' => array( |             'strip' => array( | ||||||
|             '//h1', |             '//h1', | ||||||
|  |             '//div[@class="breadcrumbs"]', | ||||||
|  |             '//div[@class="mobile"]', | ||||||
|  |             '//div[@class="fromIssue"]', | ||||||
|  |             '//div[contains(@class,"belowDeck")]', | ||||||
|             '//div[@class="meta"]', |             '//div[@class="meta"]', | ||||||
|             '//div[@class="shareIcons"]', |             '//div[@class="shareIcons"]', | ||||||
|  |             '//div[@class="categories"]', | ||||||
|             '//div[@class="navigation"]', |             '//div[@class="navigation"]', | ||||||
|  |             '//div[@class="heading"]', | ||||||
|  |             '//div[contains(@id,"-ad")]', | ||||||
|  |             '//div[@class="relatedArticles"]', | ||||||
|  |             '//div[@id="disqus_thread"]' | ||||||
|             ), |             ), | ||||||
|          ), |          ), | ||||||
|     ), |     ), | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'grabber' => array( |     'grabber' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/e-w-e.ru.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'http://e-w-e.ru/16-prekrasnyx-izobretenij-zhenshhin/', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//div[contains(@class, "post_text")]', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//script', | ||||||
|  |                 '//form', | ||||||
|  |                 '//style', | ||||||
|  |                 '//*[@class="views_post"]', | ||||||
|  |                 '//*[@class="adman_mobile"]', | ||||||
|  |                 '//*[@class="adman_desctop"]', | ||||||
|  |                 '//*[contains(@rel, "nofollow")]', | ||||||
|  |                 '//*[contains(@class, "wp-smiley")]', | ||||||
|  |                 '//*[contains(text(),"Источник:")]', | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
							
								
								
									
										25
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/economist.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/fguillot/picofeed/lib/PicoFeed/Rules/economist.com.php
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  | return array( | ||||||
|  |     'grabber' => array( | ||||||
|  |         '%.*%' => array( | ||||||
|  |             'test_url' => 'http://www.economist.com/blogs/buttonwood/2017/02/mixed-signals?fsrc=rss', | ||||||
|  |             'body' => array( | ||||||
|  |                 '//article', | ||||||
|  |             ), | ||||||
|  |             'strip' => array( | ||||||
|  |                 '//span[@class="blog-post__siblings-list-header "]', | ||||||
|  |                 '//h1', | ||||||
|  |                 '//aside', | ||||||
|  |                 '//div[@class="blog-post__asideable-wrapper"]', | ||||||
|  |                 '//div[@class="share_inline_header"]', | ||||||
|  |                 '//div[@id="column-right"]', | ||||||
|  |                 '//div[contains(@class,"blog-post__siblings-list-aside")]', | ||||||
|  |                 '//div[@class="video-player__wrapper"]', | ||||||
|  |                 '//div[@class="blog-post__bottom-panel"]', | ||||||
|  |                 '//div[contains(@class,"latest-updates-panel__container")]', | ||||||
|  |                 '//div[contains(@class,"blog-post__asideable-content")]', | ||||||
|  |                 '//div[@aria-label="Advertisement"]' | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|  | ); | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| return array( | return array( | ||||||
|     'filter' => array( |     'filter' => array( | ||||||
|         '%.*%' => array( |         '%.*%' => array( | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user