1
0
mirror of https://github.com/e107inc/e107.git synced 2025-01-17 12:48:24 +01:00

Updated third-party PHP libraries

* phpmailer/phpmailer has been updated to fix an attachment filename
  escaping issue.
* hybridauth/hybridauth has been updated to add Patreon as a social
  login provider.
* ifsnop/mysqldump-php has been updated just 'cause.
This commit is contained in:
Nick Liu 2020-05-27 12:45:33 -05:00
parent 903be35f8c
commit 3b0a679524
No known key found for this signature in database
GPG Key ID: 1167C5F9C9897637
21 changed files with 536 additions and 219 deletions

45
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "33e332186d73935e44e71e72a52ae532", "content-hash": "1c075824f15ab5d3b2b7f32dcf933e8a",
"packages": [ "packages": [
{ {
"name": "hybridauth/hybridauth", "name": "hybridauth/hybridauth",
"version": "3.2.0", "version": "3.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hybridauth/hybridauth.git", "url": "https://github.com/hybridauth/hybridauth.git",
"reference": "2edf92f07b94fcc9e17ea14e2a1644b83981af7d" "reference": "51cb2ad2f04d175d298b51e919868dec1d4d8b04"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hybridauth/hybridauth/zipball/2edf92f07b94fcc9e17ea14e2a1644b83981af7d", "url": "https://api.github.com/repos/hybridauth/hybridauth/zipball/51cb2ad2f04d175d298b51e919868dec1d4d8b04",
"reference": "2edf92f07b94fcc9e17ea14e2a1644b83981af7d", "reference": "51cb2ad2f04d175d298b51e919868dec1d4d8b04",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -56,20 +56,20 @@
"social", "social",
"twitter" "twitter"
], ],
"time": "2020-03-04T14:32:04+00:00" "time": "2020-04-16T08:04:26+00:00"
}, },
{ {
"name": "ifsnop/mysqldump-php", "name": "ifsnop/mysqldump-php",
"version": "v2.8", "version": "v2.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ifsnop/mysqldump-php.git", "url": "https://github.com/ifsnop/mysqldump-php.git",
"reference": "b6919eff87c36b18fe0d4b3a53635df03c8a3b38" "reference": "fc9c119fe5d70af9a685cad6a8ac612fd7589e25"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ifsnop/mysqldump-php/zipball/b6919eff87c36b18fe0d4b3a53635df03c8a3b38", "url": "https://api.github.com/repos/ifsnop/mysqldump-php/zipball/fc9c119fe5d70af9a685cad6a8ac612fd7589e25",
"reference": "b6919eff87c36b18fe0d4b3a53635df03c8a3b38", "reference": "fc9c119fe5d70af9a685cad6a8ac612fd7589e25",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -111,20 +111,20 @@
"php5", "php5",
"sql" "sql"
], ],
"time": "2019-10-29T23:13:43+00:00" "time": "2020-04-03T14:40:40+00:00"
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.1.4", "version": "v6.1.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "c5e61d0729507049cec9673aa1a679f9adefd683" "reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/c5e61d0729507049cec9673aa1a679f9adefd683", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"reference": "c5e61d0729507049cec9673aa1a679f9adefd683", "reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -173,7 +173,13 @@
} }
], ],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP", "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"time": "2019-12-10T11:17:38+00:00" "funding": [
{
"url": "https://github.com/synchro",
"type": "github"
}
],
"time": "2020-05-27T12:24:03+00:00"
}, },
{ {
"name": "tedivm/jshrink", "name": "tedivm/jshrink",
@ -229,10 +235,13 @@
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": ">=5.6" "php": ">=5.6",
"ext-json": "*",
"ext-pdo": "*"
}, },
"platform-dev": [], "platform-dev": [],
"platform-overrides": { "platform-overrides": {
"php": "5.6" "php": "5.6"
} },
"plugin-api-version": "1.1.0"
} }

View File

@ -13,6 +13,9 @@ class ComposerAutoloaderInit1da798ad8058bf7b615c0a3d8f41e314
} }
} }
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader() public static function getLoader()
{ {
if (null !== self::$loader) { if (null !== self::$loader) {

View File

@ -1,17 +1,17 @@
[ [
{ {
"name": "hybridauth/hybridauth", "name": "hybridauth/hybridauth",
"version": "3.2.0", "version": "3.3.0",
"version_normalized": "3.2.0.0", "version_normalized": "3.3.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/hybridauth/hybridauth.git", "url": "https://github.com/hybridauth/hybridauth.git",
"reference": "2edf92f07b94fcc9e17ea14e2a1644b83981af7d" "reference": "51cb2ad2f04d175d298b51e919868dec1d4d8b04"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/hybridauth/hybridauth/zipball/2edf92f07b94fcc9e17ea14e2a1644b83981af7d", "url": "https://api.github.com/repos/hybridauth/hybridauth/zipball/51cb2ad2f04d175d298b51e919868dec1d4d8b04",
"reference": "2edf92f07b94fcc9e17ea14e2a1644b83981af7d", "reference": "51cb2ad2f04d175d298b51e919868dec1d4d8b04",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -21,7 +21,7 @@
"ext-curl": "*", "ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^6.5 || ^8" "phpunit/phpunit": "^4.8.35 || ^6.5 || ^8"
}, },
"time": "2020-03-04T14:32:04+00:00", "time": "2020-04-16T08:04:26+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -55,17 +55,17 @@
}, },
{ {
"name": "ifsnop/mysqldump-php", "name": "ifsnop/mysqldump-php",
"version": "v2.8", "version": "v2.9",
"version_normalized": "2.8.0.0", "version_normalized": "2.9.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ifsnop/mysqldump-php.git", "url": "https://github.com/ifsnop/mysqldump-php.git",
"reference": "b6919eff87c36b18fe0d4b3a53635df03c8a3b38" "reference": "fc9c119fe5d70af9a685cad6a8ac612fd7589e25"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ifsnop/mysqldump-php/zipball/b6919eff87c36b18fe0d4b3a53635df03c8a3b38", "url": "https://api.github.com/repos/ifsnop/mysqldump-php/zipball/fc9c119fe5d70af9a685cad6a8ac612fd7589e25",
"reference": "b6919eff87c36b18fe0d4b3a53635df03c8a3b38", "reference": "fc9c119fe5d70af9a685cad6a8ac612fd7589e25",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -75,7 +75,7 @@
"phpunit/phpunit": "4.8.36", "phpunit/phpunit": "4.8.36",
"squizlabs/php_codesniffer": "1.*" "squizlabs/php_codesniffer": "1.*"
}, },
"time": "2019-10-29T23:13:43+00:00", "time": "2020-04-03T14:40:40+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -112,17 +112,17 @@
}, },
{ {
"name": "phpmailer/phpmailer", "name": "phpmailer/phpmailer",
"version": "v6.1.4", "version": "v6.1.6",
"version_normalized": "6.1.4.0", "version_normalized": "6.1.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git", "url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "c5e61d0729507049cec9673aa1a679f9adefd683" "reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/c5e61d0729507049cec9673aa1a679f9adefd683", "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"reference": "c5e61d0729507049cec9673aa1a679f9adefd683", "reference": "c2796cb1cb99d7717290b48c4e6f32cb6c60b7b3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -143,7 +143,7 @@
"stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
}, },
"time": "2019-12-10T11:17:38+00:00", "time": "2020-05-27T12:24:03+00:00",
"type": "library", "type": "library",
"installation-source": "dist", "installation-source": "dist",
"autoload": { "autoload": {
@ -172,7 +172,13 @@
"name": "Brent R. Matzelle" "name": "Brent R. Matzelle"
} }
], ],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP" "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"funding": [
{
"url": "https://github.com/synchro",
"type": "github"
}
]
}, },
{ {
"name": "tedivm/jshrink", "name": "tedivm/jshrink",

View File

@ -1,4 +1,4 @@
## [Hybridauth](https://hybridauth.github.io/) 3.1 ## [Hybridauth](https://hybridauth.github.io/) 3.3
[![Build Status](https://travis-ci.org/hybridauth/hybridauth.svg?branch=master)](https://travis-ci.org/hybridauth/hybridauth) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/hybridauth/hybridauth/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/hybridauth/hybridauth/?branch=master) [![Latest Stable Version](https://poser.pugx.org/hybridauth/hybridauth/v/stable.png)](https://packagist.org/packages/hybridauth/hybridauth) [![Join the chat at https://gitter.im/hybridauth/hybridauth](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hybridauth/hybridauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/hybridauth/hybridauth.svg?branch=master)](https://travis-ci.org/hybridauth/hybridauth) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/hybridauth/hybridauth/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/hybridauth/hybridauth/?branch=master) [![Latest Stable Version](https://poser.pugx.org/hybridauth/hybridauth/v/stable.png)](https://packagist.org/packages/hybridauth/hybridauth) [![Join the chat at https://gitter.im/hybridauth/hybridauth](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hybridauth/hybridauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

View File

@ -47,7 +47,7 @@ class Facebook extends OAuth2
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected $apiBaseUrl = 'https://graph.facebook.com/v2.12/'; protected $apiBaseUrl = 'https://graph.facebook.com/v6.0/';
/** /**
* {@inheritdoc} * {@inheritdoc}

View File

@ -2,35 +2,35 @@
/*! /*!
* Hybridauth * Hybridauth
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth * https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
* (c) 2017 Hybridauth authors | https://hybridauth.github.io/license.html * (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
*/ */
namespace Hybridauth\Provider; namespace Hybridauth\Provider;
use Hybridauth\Adapter\OAuth2; use Hybridauth\Adapter\OAuth2;
use Hybridauth\Data\Collection;
use Hybridauth\Exception\UnexpectedApiResponseException; use Hybridauth\Exception\UnexpectedApiResponseException;
use Hybridauth\Data;
use Hybridauth\User; use Hybridauth\User;
/** /**
* Instagram OAuth2 provider adapter. * Instagram OAuth2 provider adapter via Instagram Basic Display API.
*/ */
class Instagram extends OAuth2 class Instagram extends OAuth2
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected $scope = 'basic'; protected $scope = 'user_profile,user_media';
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected $apiBaseUrl = 'https://api.instagram.com/v1/'; protected $apiBaseUrl = 'https://graph.instagram.com';
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected $authorizeUrl = 'https://api.instagram.com/oauth/authorize/'; protected $authorizeUrl = 'https://api.instagram.com/oauth/authorize';
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -40,7 +40,7 @@ class Instagram extends OAuth2
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
protected $apiDocumentation = 'https://www.instagram.com/developer/authentication/'; protected $apiDocumentation = 'https://developers.facebook.com/docs/instagram-basic-display-api';
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -50,7 +50,7 @@ class Instagram extends OAuth2
parent::initialize(); parent::initialize();
// The Instagram API requires an access_token from authenticated users // The Instagram API requires an access_token from authenticated users
// for each endpoint, see https://www.instagram.com/developer/endpoints. // for each endpoint.
$accessToken = $this->getStoredData($this->accessTokenName); $accessToken = $this->getStoredData($this->accessTokenName);
$this->apiRequestParameters[$this->accessTokenName] = $accessToken; $this->apiRequestParameters[$this->accessTokenName] = $accessToken;
} }
@ -60,28 +60,111 @@ class Instagram extends OAuth2
*/ */
public function getUserProfile() public function getUserProfile()
{ {
$response = $this->apiRequest('users/self/'); $response = $this->apiRequest('me', 'GET', [
'fields' => 'id,username,account_type,media_count',
]);
$data = new Data\Collection($response); $data = new Collection($response);
if (!$data->exists('id')) {
if (! $data->exists('data')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.'); throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
} }
$userProfile = new User\Profile(); $userProfile = new User\Profile();
$data = $data->filter('data');
$userProfile->identifier = $data->get('id'); $userProfile->identifier = $data->get('id');
$userProfile->description = $data->get('bio'); $userProfile->displayName = $data->get('username');
$userProfile->photoURL = $data->get('profile_picture'); $userProfile->profileURL = "https://instagram.com/{$userProfile->displayName}";
$userProfile->webSiteURL = $data->get('website'); $userProfile->data = [
$userProfile->displayName = $data->get('full_name'); 'account_type' => $data->get('account_type'),
$userProfile->displayName = $userProfile->displayName ?: $data->get('username'); 'media_count' => $data->get('media_count'),
$userProfile->profileURL = "https://instagram.com/{$data->get('username')}"; ];
$userProfile->data = (array) $data->get('counts');
return $userProfile; return $userProfile;
} }
/**
* Fetch user medias.
*
* @param int $limit Number of elements per page.
* @param string $pageId Current pager ID.
* @param array|null $fields Fields to fetch per media.
*
* @return \Hybridauth\Data\Collection
*
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
* @throws \Hybridauth\Exception\InvalidAccessTokenException
* @throws \Hybridauth\Exception\UnexpectedApiResponseException
*/
public function getUserMedia($limit = 12, $pageId = null, array $fields = null)
{
if (empty($fields)) {
$fields = [
'id',
'caption',
'media_type',
'media_url',
'thumbnail_url',
'permalink',
'timestamp',
'username',
];
}
$params = [
'fields' => implode(',', $fields),
'limit' => $limit,
];
if ($pageId !== null) {
$params['after'] = $pageId;
}
$response = $this->apiRequest('me/media', 'GET', $params);
$data = new Collection($response);
if (!$data->exists('data')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
return $data;
}
/**
* Fetches a single user's media.
*
* @param string $mediaId Media ID.
* @param array|null $fields Fields to fetch per media.
*
* @return \Hybridauth\Data\Collection
*
* @throws \Hybridauth\Exception\HttpClientFailureException
* @throws \Hybridauth\Exception\HttpRequestFailedException
* @throws \Hybridauth\Exception\InvalidAccessTokenException
* @throws \Hybridauth\Exception\UnexpectedApiResponseException
*/
public function getMedia($mediaId, array $fields = null)
{
if (empty($fields)) {
$fields = [
'id',
'caption',
'media_type',
'media_url',
'thumbnail_url',
'permalink',
'timestamp',
'username',
];
}
$response = $this->apiRequest($mediaId, 'GET', [
'fields' => implode(',', $fields),
]);
$data = new Collection($response);
if (!$data->exists('id')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
return $data;
}
} }

View File

@ -110,6 +110,14 @@ class Odnoklassniki extends OAuth2
$userProfile->photoURL = $data->get('pic1024x768'); $userProfile->photoURL = $data->get('pic1024x768');
$userProfile->profileURL = 'http://ok.ru/profile/' . $data->get('uid'); $userProfile->profileURL = 'http://ok.ru/profile/' . $data->get('uid');
// Handle birthday.
if ($data->get('birthday')) {
$bday = explode('-', $data->get('birthday'));
$userProfile->birthDay = (int)$bday[0];
$userProfile->birthMonth = (int)$bday[1];
$userProfile->birthYear = (int)$bday[2];
}
return $userProfile; return $userProfile;
} }
} }

View File

@ -0,0 +1,85 @@
<?php
/*!
* Hybridauth
* https://hybridauth.github.io | https://github.com/hybridauth/hybridauth
* (c) 2020 Hybridauth authors | https://hybridauth.github.io/license.html
*/
namespace Hybridauth\Provider;
use Hybridauth\Adapter\OAuth2;
use Hybridauth\Exception\UnexpectedApiResponseException;
use Hybridauth\User\Profile;
use Hybridauth\Data\Collection;
/**
* Patreon OAuth2 provider adapter.
*/
class Patreon extends OAuth2
{
/**
* {@inheritdoc}
*/
public $scope = 'identity identity[email]';
/**
* {@inheritdoc}
*/
protected $apiBaseUrl = 'https://www.patreon.com/api';
/**
* {@inheritdoc}
*/
protected $authorizeUrl = 'https://www.patreon.com/oauth2/authorize';
/**
* {@inheritdoc}
*/
protected $accessTokenUrl = 'https://www.patreon.com/api/oauth2/token';
/**
* {@inheritdoc}
*/
protected function initialize()
{
parent::initialize();
$this->tokenRefreshParameters += [
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
];
}
/**
* {@inheritdoc}
*/
public function getUserProfile()
{
$response = $this->apiRequest('oauth2/v2/identity', 'GET', [
'fields[user]' => 'created,first_name,last_name,email,full_name,is_email_verified,thumb_url,url',
]);
$collection = new Collection($response);
if (!$collection->exists('data')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
}
$userProfile = new Profile();
$data = $collection->filter('data');
$attributes = $data->filter('attributes');
$userProfile->identifier = $data->get('id');
$userProfile->email = $attributes->get('email');
$userProfile->firstName = $attributes->get('first_name');
$userProfile->lastName = $attributes->get('last_name');
$userProfile->displayName = $attributes->get('full_name') ?: $data->get('id');
$userProfile->photoURL = $attributes->get('thumb_url');
$userProfile->profileURL = $attributes->get('url');
$userProfile->emailVerified = $attributes->get('is_email_verified') ? $userProfile->email : '';
return $userProfile;
}
}

View File

@ -64,6 +64,31 @@ class Vkontakte extends OAuth2
*/ */
protected $scope = 'email,offline'; protected $scope = 'email,offline';
/**
* {@inheritdoc}
*/
protected function initialize()
{
parent::initialize();
// The VK API requires version and access_token from authenticated users
// for each endpoint.
$accessToken = $this->getStoredData($this->accessTokenName);
$this->apiRequestParameters[$this->accessTokenName] = $accessToken;
$this->apiRequestParameters['v'] = static::API_VERSION;
}
/**
* {@inheritdoc}
*/
protected function validateAccessTokenExchange($response)
{
$data = parent::validateAccessTokenExchange($response);
// Need to store email for later use.
$this->storeData('email', $data->get('email'));
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -77,33 +102,16 @@ class Vkontakte extends OAuth2
return $expired; return $expired;
} }
/**
* {@inheritdoc}
*/
protected function validateAccessTokenExchange($response)
{
$data = parent::validateAccessTokenExchange($response);
// Need to store user_id as token for later use.
$this->storeData('user_id', $data->get('user_id'));
$this->storeData('email', $data->get('email'));
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getUserProfile() public function getUserProfile()
{ {
$photoField = 'photo_' . ($this->config->get('photo_size') ?: 'max_orig'); $photoField = 'photo_' . ($this->config->get('photo_size') ?: 'max_orig');
$parameters = [
'user_ids' => $this->getStoredData('user_id'),
// Required fields: id,first_name,last_name
'fields' => 'screen_name,sex,has_photo,' . $photoField,
'v' => static::API_VERSION,
$this->accessTokenName => $this->getStoredData($this->accessTokenName),
];
$response = $this->apiRequest('users.get', 'GET', $parameters); $response = $this->apiRequest('users.get', 'GET', [
'fields' => 'screen_name,sex,education,bdate,has_photo,' . $photoField,
]);
if (property_exists($response, 'error')) { if (property_exists($response, 'error')) {
throw new UnexpectedApiResponseException($response->error->error_msg); throw new UnexpectedApiResponseException($response->error->error_msg);
@ -124,6 +132,18 @@ class Vkontakte extends OAuth2
$userProfile->displayName = $data->get('screen_name'); $userProfile->displayName = $data->get('screen_name');
$userProfile->photoURL = $data->get('has_photo') === 1 ? $data->get($photoField) : ''; $userProfile->photoURL = $data->get('has_photo') === 1 ? $data->get($photoField) : '';
// Handle b-date.
if ($data->get('bdate')) {
$bday = explode('.', $data->get('bdate'));
$userProfile->birthDay = (int) $bday[0];
$userProfile->birthMonth = (int) $bday[1];
$userProfile->birthYear = (int) $bday[2];
}
$userProfile->data = [
'education' => $data->get('education'),
];
$screen_name = static::URL . ($data->get('screen_name') ?: 'id' . $data->get('id')); $screen_name = static::URL . ($data->get('screen_name') ?: 'id' . $data->get('id'));
$userProfile->profileURL = $screen_name; $userProfile->profileURL = $screen_name;
@ -145,21 +165,16 @@ class Vkontakte extends OAuth2
*/ */
public function getUserContacts() public function getUserContacts()
{ {
$contacts = []; $response = $this->apiRequest('friends.get', 'GET', [
$parameters = [
'user_id' => $this->getStoredData('user_id'),
'fields' => 'uid,name,photo_200_orig', 'fields' => 'uid,name,photo_200_orig',
'v' => static::API_VERSION, ]);
$this->accessTokenName => $this->getStoredData($this->accessTokenName),
];
$response = $this->apiRequest('friends.get', 'GET', $parameters);
$data = new Data\Collection($response); $data = new Data\Collection($response);
if (!$data->exists('response')) { if (!$data->exists('response')) {
throw new UnexpectedApiResponseException('Provider API returned an unexpected response.'); throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
} }
$contacts = [];
if (!$data->filter('response')->filter('items')->isEmpty()) { if (!$data->filter('response')->filter('items')->isEmpty()) {
foreach ($data->filter('response')->filter('items')->toArray() as $item) { foreach ($data->filter('response')->filter('items')->toArray() as $item) {
$contacts[] = $this->fetchUserContact($item); $contacts[] = $this->fetchUserContact($item);

View File

@ -25,7 +25,7 @@ Out of the box, MySQLDump-PHP supports backing up table structures, the data its
MySQLDump-PHP is the only library that supports: MySQLDump-PHP is the only library that supports:
* output binary blobs as hex. * output binary blobs as hex.
* resolves view dependencies (using Stand-In tables). * resolves view dependencies (using Stand-In tables).
* output compared against original mysqldump. Linked to travis-ci testing system (testing from php 5.3 to 7.1 & hhvm) * output compared against original mysqldump. Linked to travis-ci testing system (testing from php 5.3 to 7.3 & hhvm)
* dumps stored routines (functions and procedures). * dumps stored routines (functions and procedures).
* dumps events. * dumps events.
* does extended-insert and/or complete-insert. * does extended-insert and/or complete-insert.
@ -89,23 +89,36 @@ Plain old PHP:
Refer to the [wiki](https://github.com/ifsnop/mysqldump-php/wiki/Full-usage-example) for some examples and a comparision between mysqldump and mysqldump-php dumps. Refer to the [wiki](https://github.com/ifsnop/mysqldump-php/wiki/Full-usage-example) for some examples and a comparision between mysqldump and mysqldump-php dumps.
## Changing values when exporting ## Changing values when exporting
You can register a callable that will be used to transform values during the export. An example use-case for this is removing sensitive data from database dumps: You can register a callable that will be used to transform values during the export. An example use-case for this is removing sensitive data from database dumps:
```php ```php
$dumper = new IMysqldump\Mysqldump('mysql:host=localhost;dbname=testdb', 'username', 'password'); $dumper = new IMysqldump\Mysqldump('mysql:host=localhost;dbname=testdb', 'username', 'password');
$dumper->setTransformColumnValueHook(function ($tableName, $colName, $colValue) { $dumper->setTransformTableRowHook(function ($tableName, array $row) {
if ($colName === 'social_security_number') { if ($tableName === 'customers') {
return (string) rand(1000000, 9999999); $row['social_security_number'] = (string) rand(1000000, 9999999);
} }
return $colValue; return $row;
}); });
$dumper->start('storage/work/dump.sql'); $dumper->start('storage/work/dump.sql');
``` ```
## Getting information about the dump
You can register a callable that will be used to report on the progress of the dump
```php
$dumper->setInfoHook(function($object, $info) {
if ($object === 'table') {
echo $info['name'], $info['rowCount'];
});
```
## Table specific export conditions ## Table specific export conditions
You can register table specific 'where' clauses to limit data on a per table basis. These override the default `where` dump setting: You can register table specific 'where' clauses to limit data on a per table basis. These override the default `where` dump setting:
```php ```php
@ -119,6 +132,7 @@ $dumper->setTableWheres(array(
``` ```
## Table specific export limits ## Table specific export limits
You can register table specific 'limits' to limit the returned rows on a per table basis: You can register table specific 'limits' to limit the returned rows on a per table basis:
```php ```php
@ -132,6 +146,7 @@ $dumper->setTableLimits(array(
``` ```
## Constructor and default parameters ## Constructor and default parameters
```php ```php
/** /**
* Constructor of Mysqldump. Note that in the case of an SQLite database * Constructor of Mysqldump. Note that in the case of an SQLite database
@ -200,9 +215,11 @@ $this->_dumpSettings = self::array_replace_recursive($dumpSettingsDefault, $dump
## Dump Settings ## Dump Settings
- **include-tables** - **include-tables**
- Only include these tables (array of table names), include all if empty - Only include these tables (array of table names), include all if empty.
- **exclude-tables** - **exclude-tables**
- Exclude these tables (array of table names), include all if empty, supports regexps - Exclude these tables (array of table names), include all if empty, supports regexps.
- **include-views**
- Only include these views (array of view names), include all if empty. By default, all views named as the include-tables array are included.
- **compress** - **compress**
- Gzip, Bzip2, None. - Gzip, Bzip2, None.
- Could be specified using the declared consts: IMysqldump\Mysqldump::GZIP, IMysqldump\Mysqldump::BZIP2 or IMysqldump\Mysqldump::NONE - Could be specified using the declared consts: IMysqldump\Mysqldump::GZIP, IMysqldump\Mysqldump::BZIP2 or IMysqldump\Mysqldump::NONE

View File

@ -83,7 +83,9 @@ class Mysqldump
private $pdoSettings = array(); private $pdoSettings = array();
private $version; private $version;
private $tableColumnTypes = array(); private $tableColumnTypes = array();
private $transformTableRowCallable;
private $transformColumnValueCallable; private $transformColumnValueCallable;
private $infoCallable;
/** /**
* Database name, parsed from dsn. * Database name, parsed from dsn.
@ -112,6 +114,7 @@ class Mysqldump
private $tableWheres = array(); private $tableWheres = array();
private $tableLimits = array(); private $tableLimits = array();
/** /**
* Constructor of Mysqldump. Note that in the case of an SQLite database * Constructor of Mysqldump. Note that in the case of an SQLite database
* connection, the filename must be in the $db parameter. * connection, the filename must be in the $db parameter.
@ -132,6 +135,7 @@ class Mysqldump
$dumpSettingsDefault = array( $dumpSettingsDefault = array(
'include-tables' => array(), 'include-tables' => array(),
'exclude-tables' => array(), 'exclude-tables' => array(),
'include-views' => array(),
'compress' => Mysqldump::NONE, 'compress' => Mysqldump::NONE,
'init_commands' => array(), 'init_commands' => array(),
'no-data' => array(), 'no-data' => array(),
@ -196,8 +200,10 @@ class Mysqldump
throw new Exception("Include-tables and exclude-tables should be arrays"); throw new Exception("Include-tables and exclude-tables should be arrays");
} }
// Dump the same views as tables, mimic mysqldump behaviour // If no include-views is passed in, dump the same views as tables, mimic mysqldump behaviour.
if (!isset($dumpSettings['include-views'])) {
$this->dumpSettings['include-views'] = $this->dumpSettings['include-tables']; $this->dumpSettings['include-views'] = $this->dumpSettings['include-tables'];
}
// Create a new compressManager to manage compressed output // Create a new compressManager to manage compressed output
$this->compressManager = CompressManagerFactory::create($this->dumpSettings['compress']); $this->compressManager = CompressManagerFactory::create($this->dumpSettings['compress']);
@ -723,6 +729,7 @@ class Mysqldump
foreach ($this->triggers as $trigger) { foreach ($this->triggers as $trigger) {
$this->getTriggerStructure($trigger); $this->getTriggerStructure($trigger);
} }
} }
/** /**
@ -1011,12 +1018,20 @@ class Mysqldump
* *
* @return array * @return array
*/ */
private function prepareColumnValues($tableName, $row) private function prepareColumnValues($tableName, array $row)
{ {
$ret = array(); $ret = array();
$columnTypes = $this->tableColumnTypes[$tableName]; $columnTypes = $this->tableColumnTypes[$tableName];
if ($this->transformTableRowCallable) {
$row = call_user_func($this->transformTableRowCallable, $tableName, $row);
}
foreach ($row as $colName => $colValue) { foreach ($row as $colName => $colValue) {
$colValue = $this->hookTransformColumnValue($tableName, $colName, $colValue, $row); if ($this->transformColumnValueCallable) {
$colValue = call_user_func($this->transformColumnValueCallable, $tableName, $colName, $colValue, $row);
}
$ret[] = $this->escape($colValue, $columnTypes[$colName]); $ret[] = $this->escape($colValue, $columnTypes[$colName]);
} }
@ -1049,38 +1064,41 @@ class Mysqldump
} }
/** /**
* Set a callable that will will be used to transform column values. * Set a callable that will be used to transform table rows
* *
* @param callable $callable * @param callable $callable
* *
* @return void * @return void
*/ */
public function setTransformTableRowHook($callable)
{
$this->transformTableRowCallable = $callable;
}
/**
* Set a callable that will be used to transform column values
*
* @param callable $callable
*
* @return void
*
* @deprecated Use setTransformTableRowHook instead for better performance
*/
public function setTransformColumnValueHook($callable) public function setTransformColumnValueHook($callable)
{ {
$this->transformColumnValueCallable = $callable; $this->transformColumnValueCallable = $callable;
} }
/** /**
* Give extending classes an opportunity to transform column values * Set a callable that will be used to report dump information
* *
* @param string $tableName Name of table which contains rows * @param callable $callable
* @param string $colName Name of the column in question
* @param string $colValue Value of the column in question
* *
* @return string * @return void
*/ */
protected function hookTransformColumnValue($tableName, $colName, $colValue, $row) public function setInfoHook($callable)
{ {
if (!$this->transformColumnValueCallable) { $this->infoCallable = $callable;
return $colValue;
}
return call_user_func_array($this->transformColumnValueCallable, array(
$tableName,
$colName,
$colValue,
$row
));
} }
/** /**
@ -1157,6 +1175,10 @@ class Mysqldump
} }
$this->endListValues($tableName, $count); $this->endListValues($tableName, $count);
if ($this->infoCallable) {
call_user_func($this->infoCallable, 'table', array('name' => $tableName, 'rowCount' => $count));
}
} }
/** /**
@ -1942,7 +1964,7 @@ class TypeAdapterMysql extends TypeAdapterFactory
"Please check 'https://bugs.mysql.com/bug.php?id=14564'"); "Please check 'https://bugs.mysql.com/bug.php?id=14564'");
} }
$procedureStmt = $row['Create Procedure']; $procedureStmt = $row['Create Procedure'];
if ( $this->dumpSettings['skip-definer'] ) { if ($this->dumpSettings['skip-definer']) {
if ($procedureStmtReplaced = preg_replace( if ($procedureStmtReplaced = preg_replace(
'/^(CREATE)\s+('.self::DEFINER_RE.')?\s+(PROCEDURE\s.*)$/s', '/^(CREATE)\s+('.self::DEFINER_RE.')?\s+(PROCEDURE\s.*)$/s',
'\1 \3', '\1 \3',
@ -2132,7 +2154,7 @@ class TypeAdapterMysql extends TypeAdapterFactory
public function start_transaction() public function start_transaction()
{ {
return "START TRANSACTION " . return "START TRANSACTION ".
"/*!40100 WITH CONSISTENT SNAPSHOT */"; "/*!40100 WITH CONSISTENT SNAPSHOT */";
} }

View File

@ -102,8 +102,8 @@ try {
$mail->SMTPAuth = true; // Enable SMTP authentication $mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'user@example.com'; // SMTP username $mail->Username = 'user@example.com'; // SMTP username
$mail->Password = 'secret'; // SMTP password $mail->Password = 'secret'; // SMTP password
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` also accepted $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
$mail->Port = 587; // TCP port to connect to $mail->Port = 587; // TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
//Recipients //Recipients
$mail->setFrom('from@example.com', 'Mailer'); $mail->setFrom('from@example.com', 'Mailer');
@ -155,7 +155,7 @@ Note that in order to reduce PHPMailer's deployed code footprint, the examples a
Complete generated API documentation is [available online](http://phpmailer.github.io/PHPMailer/). Complete generated API documentation is [available online](http://phpmailer.github.io/PHPMailer/).
You can generate complete API-level documentation by running `phpdoc` in the top-level folder, and documentation will appear in the `docs` folder, though you'll need to have [PHPDocumentor](http://www.phpdoc.org) installed. You may find [the unit tests](https://github.com/PHPMailer/PHPMailer/tree/master/test/phpmailerTest.php) a good source of how to do various operations such as encryption. You can generate complete API-level documentation by running `phpdoc` in the top-level folder, and documentation will appear in the `docs` folder, though you'll need to have [PHPDocumentor](http://www.phpdoc.org) installed. You may find [the unit tests](https://github.com/PHPMailer/PHPMailer/blob/master/test/PHPMailerTest.php) a good source of how to do various operations such as encryption.
If the documentation doesn't cover what you need, search the [many questions on Stack Overflow](http://stackoverflow.com/questions/tagged/phpmailer), and before you ask a question about "SMTP Error: Could not connect to SMTP host.", [read the troubleshooting guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting). If the documentation doesn't cover what you need, search the [many questions on Stack Overflow](http://stackoverflow.com/questions/tagged/phpmailer), and before you ask a question about "SMTP Error: Could not connect to SMTP host.", [read the troubleshooting guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting).

View File

@ -2,6 +2,8 @@
Please disclose any vulnerabilities found responsibly - report any security problems found to the maintainers privately. Please disclose any vulnerabilities found responsibly - report any security problems found to the maintainers privately.
PHPMailer versions 6.1.5 and earlier contain an output escaping bug that occurs in `Content-Type` and `Content-Disposition` when filenames passed into `addAttachment` and other methods that accept attachment names contain double quote characters, in contravention of RFC822 3.4.1. No specific vulnerability has been found relating to this, but it could allow file attachments to bypass attachment filters that are based on matching filename extensions. Recorded as [CVE-2020-13625](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2020-13625). Reported by Elar Lang of Clarified Security.
PHPMailer versions prior to 6.0.6 and 5.2.27 are vulnerable to an object injection attack by passing `phar://` paths into `addAttachment()` and other functions that may receive unfiltered local paths, possibly leading to RCE. Recorded as [CVE-2018-19296](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-19296). See [this article](https://knasmueller.net/5-answers-about-php-phar-exploitation) for more info on this type of vulnerability. Mitigated by blocking the use of paths containing URL-protocol style prefixes such as `phar://`. Reported by Sehun Oh of cyberone.kr. PHPMailer versions prior to 6.0.6 and 5.2.27 are vulnerable to an object injection attack by passing `phar://` paths into `addAttachment()` and other functions that may receive unfiltered local paths, possibly leading to RCE. Recorded as [CVE-2018-19296](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-19296). See [this article](https://knasmueller.net/5-answers-about-php-phar-exploitation) for more info on this type of vulnerability. Mitigated by blocking the use of paths containing URL-protocol style prefixes such as `phar://`. Reported by Sehun Oh of cyberone.kr.
PHPMailer versions prior to 5.2.24 (released July 26th 2017) have an XSS vulnerability in one of the code examples, [CVE-2017-11503](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-11503). The `code_generator.phps` example did not filter user input prior to output. This file is distributed with a `.phps` extension, so it it not normally executable unless it is explicitly renamed, and the file is not included when PHPMailer is loaded through composer, so it is safe by default. There was also an undisclosed potential XSS vulnerability in the default exception handler (unused by default). Patches for both issues kindly provided by Patrick Monnerat of the Fedora Project. PHPMailer versions prior to 5.2.24 (released July 26th 2017) have an XSS vulnerability in one of the code examples, [CVE-2017-11503](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-11503). The `code_generator.phps` example did not filter user input prior to output. This file is distributed with a `.phps` extension, so it it not normally executable unless it is explicitly renamed, and the file is not included when PHPMailer is loaded through composer, so it is safe by default. There was also an undisclosed potential XSS vulnerability in the default exception handler (unused by default). Patches for both issues kindly provided by Patrick Monnerat of the Fedora Project.

View File

@ -1 +1 @@
6.1.4 6.1.6

View File

@ -19,6 +19,12 @@
"name": "Brent R. Matzelle" "name": "Brent R. Matzelle"
} }
], ],
"funding": [
{
"url": "https://github.com/synchro",
"type": "github"
}
],
"require": { "require": {
"php": ">=5.5.0", "php": ">=5.5.0",
"ext-ctype": "*", "ext-ctype": "*",

View File

@ -2,25 +2,27 @@
/** /**
* Danish PHPMailer language file: refer to English translation for definitive list * Danish PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer * @package PHPMailer
* @author Mikael Stokkebro <info@stokkebro.dk> * @author John Sebastian <jms@iwb.dk>
* Rewrite and extension of the work by Mikael Stokkebro <info@stokkebro.dk>
*
*/ */
$PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Kunne ikke logge på.'; $PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Login mislykkedes.';
$PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.'; $PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Forbindelse til SMTP serveren kunne ikke oprettes.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data kunne ikke accepteres.'; $PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data blev ikke accepteret.';
//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; $PHPMAILER_LANG['empty_message'] = 'Meddelelsen er uden indhold';
$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; $PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: ';
$PHPMAILER_LANG['execute'] = 'Kunne ikke køre: '; $PHPMAILER_LANG['execute'] = 'Kunne ikke afvikle: ';
$PHPMAILER_LANG['file_access'] = 'Ingen adgang til fil: '; $PHPMAILER_LANG['file_access'] = 'Kunne ikke tilgå filen: ';
$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; $PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: ';
$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; $PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: ';
$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere email funktionen.'; $PHPMAILER_LANG['instantiate'] = 'Email funktionen kunne ikke initialiseres.';
//$PHPMAILER_LANG['invalid_address'] = 'Invalid address: '; $PHPMAILER_LANG['invalid_address'] = 'Udgyldig adresse: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; $PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.';
$PHPMAILER_LANG['provide_address'] = 'Du skal indtaste mindst en modtagers emailadresse.'; $PHPMAILER_LANG['provide_address'] = 'Indtast mindst en modtagers email adresse.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: '; $PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: ';
//$PHPMAILER_LANG['signing'] = 'Signing Error: '; $PHPMAILER_LANG['signing'] = 'Signeringsfejl: ';
//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() fejlede.';
//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; $PHPMAILER_LANG['smtp_error'] = 'SMTP server fejl: ';
//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; $PHPMAILER_LANG['variable_set'] = 'Kunne ikke definere eller nulstille variablen: ';
//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: '; $PHPMAILER_LANG['extension_missing'] = 'Udvidelse mangler: ';

View File

@ -64,7 +64,7 @@ class PHPMailer
* Options: null (default), 1 = High, 3 = Normal, 5 = low. * Options: null (default), 1 = High, 3 = Normal, 5 = low.
* When null, the header is not set at all. * When null, the header is not set at all.
* *
* @var int * @var int|null
*/ */
public $Priority; public $Priority;
@ -745,7 +745,7 @@ class PHPMailer
* *
* @var string * @var string
*/ */
const VERSION = '6.1.4'; const VERSION = '6.1.6';
/** /**
* Error severity: message only, continue processing. * Error severity: message only, continue processing.
@ -769,11 +769,22 @@ class PHPMailer
const STOP_CRITICAL = 2; const STOP_CRITICAL = 2;
/** /**
* SMTP RFC standard line ending. * The SMTP standard CRLF line break.
* If you want to change line break format, change static::$LE, not this.
*/
const CRLF = "\r\n";
/**
* "Folding White Space" a white space string used for line folding.
*/
const FWS = ' ';
/**
* SMTP RFC standard line ending; Carriage Return, Line Feed.
* *
* @var string * @var string
*/ */
protected static $LE = "\r\n"; protected static $LE = self::CRLF;
/** /**
* The maximum line length supported by mail(). * The maximum line length supported by mail().
@ -1446,7 +1457,7 @@ class PHPMailer
) { ) {
//SMTP mandates RFC-compliant line endings //SMTP mandates RFC-compliant line endings
//and it's also used with mail() on Windows //and it's also used with mail() on Windows
static::setLE("\r\n"); static::setLE(self::CRLF);
} else { } else {
//Maintain backward compatibility with legacy Linux command line mailers //Maintain backward compatibility with legacy Linux command line mailers
static::setLE(PHP_EOL); static::setLE(PHP_EOL);
@ -1553,7 +1564,7 @@ class PHPMailer
$this->encodeHeader($this->secureHeader($this->Subject)), $this->encodeHeader($this->secureHeader($this->Subject)),
$this->MIMEBody $this->MIMEBody
); );
$this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . static::$LE . $this->MIMEHeader = static::stripTrailingWSP($this->MIMEHeader) . static::$LE .
static::normalizeBreaks($header_dkim) . static::$LE; static::normalizeBreaks($header_dkim) . static::$LE;
} }
@ -1620,7 +1631,7 @@ class PHPMailer
*/ */
protected function sendmailSend($header, $body) protected function sendmailSend($header, $body)
{ {
$header = rtrim($header, "\r\n ") . static::$LE . static::$LE; $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
// CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
if (!empty($this->Sender) && self::isShellSafe($this->Sender)) { if (!empty($this->Sender) && self::isShellSafe($this->Sender)) {
@ -1750,7 +1761,7 @@ class PHPMailer
*/ */
protected function mailSend($header, $body) protected function mailSend($header, $body)
{ {
$header = rtrim($header, "\r\n ") . static::$LE . static::$LE; $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
$toArr = []; $toArr = [];
foreach ($this->to as $toaddr) { foreach ($this->to as $toaddr) {
@ -1839,7 +1850,7 @@ class PHPMailer
*/ */
protected function smtpSend($header, $body) protected function smtpSend($header, $body)
{ {
$header = rtrim($header, "\r\n ") . static::$LE . static::$LE; $header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
$bad_rcpt = []; $bad_rcpt = [];
if (!$this->smtpConnect($this->SMTPOptions)) { if (!$this->smtpConnect($this->SMTPOptions)) {
throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
@ -2075,6 +2086,7 @@ class PHPMailer
'se' => 'sv', 'se' => 'sv',
'rs' => 'sr', 'rs' => 'sr',
'tg' => 'tl', 'tg' => 'tl',
'am' => 'hy',
]; ];
if (isset($renamed_langcodes[$langcode])) { if (isset($renamed_langcodes[$langcode])) {
@ -2511,7 +2523,8 @@ class PHPMailer
*/ */
public function getSentMIMEMessage() public function getSentMIMEMessage()
{ {
return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . static::$LE . static::$LE . $this->MIMEBody; return static::stripTrailingWSP($this->MIMEHeader . $this->mailHeader) .
static::$LE . static::$LE . $this->MIMEBody;
} }
/** /**
@ -2594,7 +2607,7 @@ class PHPMailer
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE; $altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
} }
//Use this as a preamble in all multipart message types //Use this as a preamble in all multipart message types
$mimepre = 'This is a multi-part message in MIME format.' . static::$LE; $mimepre = 'This is a multi-part message in MIME format.' . static::$LE . static::$LE;
switch ($this->message_type) { switch ($this->message_type) {
case 'inline': case 'inline':
$body .= $mimepre; $body .= $mimepre;
@ -2949,7 +2962,7 @@ class PHPMailer
$disposition = 'attachment' $disposition = 'attachment'
) { ) {
try { try {
if (!static::isPermittedPath($path) || !@is_file($path)) { if (!static::isPermittedPath($path) || !@is_file($path) || !is_readable($path)) {
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE); throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
} }
@ -3051,9 +3064,9 @@ class PHPMailer
//Only include a filename property if we have one //Only include a filename property if we have one
if (!empty($name)) { if (!empty($name)) {
$mime[] = sprintf( $mime[] = sprintf(
'Content-Type: %s; name="%s"%s', 'Content-Type: %s; name=%s%s',
$type, $type,
$this->encodeHeader($this->secureHeader($name)), static::quotedString($this->encodeHeader($this->secureHeader($name))),
static::$LE static::$LE
); );
} else { } else {
@ -3073,24 +3086,14 @@ class PHPMailer
$mime[] = 'Content-ID: <' . $this->encodeHeader($this->secureHeader($cid)) . '>' . static::$LE; $mime[] = 'Content-ID: <' . $this->encodeHeader($this->secureHeader($cid)) . '>' . static::$LE;
} }
// If a filename contains any of these chars, it should be quoted, // Allow for bypassing the Content-Disposition header
// but not otherwise: RFC2183 & RFC2045 5.1
// Fixes a warning in IETF's msglint MIME checker
// Allow for bypassing the Content-Disposition header totally
if (!empty($disposition)) { if (!empty($disposition)) {
$encoded_name = $this->encodeHeader($this->secureHeader($name)); $encoded_name = $this->encodeHeader($this->secureHeader($name));
if (preg_match('/[ ()<>@,;:"\/\[\]?=]/', $encoded_name)) { if (!empty($encoded_name)) {
$mime[] = sprintf(
'Content-Disposition: %s; filename="%s"%s',
$disposition,
$encoded_name,
static::$LE . static::$LE
);
} elseif (!empty($encoded_name)) {
$mime[] = sprintf( $mime[] = sprintf(
'Content-Disposition: %s; filename=%s%s', 'Content-Disposition: %s; filename=%s%s',
$disposition, $disposition,
$encoded_name, static::quotedString($encoded_name),
static::$LE . static::$LE static::$LE . static::$LE
); );
} else { } else {
@ -3134,7 +3137,7 @@ class PHPMailer
protected function encodeFile($path, $encoding = self::ENCODING_BASE64) protected function encodeFile($path, $encoding = self::ENCODING_BASE64)
{ {
try { try {
if (!static::isPermittedPath($path) || !file_exists($path)) { if (!static::isPermittedPath($path) || !file_exists($path) || !is_readable($path)) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
} }
$file_buffer = file_get_contents($path); $file_buffer = file_get_contents($path);
@ -3146,6 +3149,10 @@ class PHPMailer
return $file_buffer; return $file_buffer;
} catch (Exception $exc) { } catch (Exception $exc) {
$this->setError($exc->getMessage()); $this->setError($exc->getMessage());
$this->edebug($exc->getMessage());
if ($this->exceptions) {
throw $exc;
}
return ''; return '';
} }
@ -3516,7 +3523,7 @@ class PHPMailer
$disposition = 'inline' $disposition = 'inline'
) { ) {
try { try {
if (!static::isPermittedPath($path) || !@is_file($path)) { if (!static::isPermittedPath($path) || !@is_file($path) || !is_readable($path)) {
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE); throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
} }
@ -3935,15 +3942,28 @@ class PHPMailer
* *
* @param string $name Custom header name * @param string $name Custom header name
* @param string|null $value Header value * @param string|null $value Header value
*
* @throws Exception
*/ */
public function addCustomHeader($name, $value = null) public function addCustomHeader($name, $value = null)
{ {
if (null === $value) { if (null === $value && strpos($name, ':') !== false) {
// Value passed in as name:value // Value passed in as name:value
$this->CustomHeader[] = explode(':', $name, 2); list($name, $value) = explode(':', $name, 2);
} else {
$this->CustomHeader[] = [$name, $value];
} }
$name = trim($name);
$value = trim($value);
//Ensure name is not empty, and that neither name nor value contain line breaks
if (empty($name) || strpbrk($name . $value, "\r\n") !== false) {
if ($this->exceptions) {
throw new Exception('Invalid header name or value');
}
return false;
}
$this->CustomHeader[] = [$name, $value];
return true;
} }
/** /**
@ -3987,6 +4007,7 @@ class PHPMailer
foreach ($images[2] as $imgindex => $url) { foreach ($images[2] as $imgindex => $url) {
// Convert data URIs into embedded images // Convert data URIs into embedded images
//e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" //e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
$match = [];
if (preg_match('#^data:(image/(?:jpe?g|gif|png));?(base64)?,(.+)#', $url, $match)) { if (preg_match('#^data:(image/(?:jpe?g|gif|png));?(base64)?,(.+)#', $url, $match)) {
if (count($match) === 4 && static::ENCODING_BASE64 === $match[2]) { if (count($match) === 4 && static::ENCODING_BASE64 === $match[2]) {
$data = base64_decode($match[3]); $data = base64_decode($match[3]);
@ -4355,7 +4376,7 @@ class PHPMailer
$breaktype = static::$LE; $breaktype = static::$LE;
} }
// Normalise to \n // Normalise to \n
$text = str_replace(["\r\n", "\r"], "\n", $text); $text = str_replace([self::CRLF, "\r"], "\n", $text);
// Now convert LE as needed // Now convert LE as needed
if ("\n" !== $breaktype) { if ("\n" !== $breaktype) {
$text = str_replace("\n", $breaktype, $text); $text = str_replace("\n", $breaktype, $text);
@ -4364,6 +4385,18 @@ class PHPMailer
return $text; return $text;
} }
/**
* Remove trailing breaks from a string.
*
* @param string $text
*
* @return string The text to remove breaks from
*/
public static function stripTrailingWSP($text)
{
return rtrim($text, " \r\n\t");
}
/** /**
* Return the current line break format string. * Return the current line break format string.
* *
@ -4472,13 +4505,15 @@ class PHPMailer
*/ */
public function DKIM_HeaderC($signHeader) public function DKIM_HeaderC($signHeader)
{ {
//Normalize breaks to CRLF (regardless of the mailer)
$signHeader = static::normalizeBreaks($signHeader, self::CRLF);
//Unfold header lines
//Note PCRE \s is too broad a definition of whitespace; RFC5322 defines it as `[ \t]` //Note PCRE \s is too broad a definition of whitespace; RFC5322 defines it as `[ \t]`
//@see https://tools.ietf.org/html/rfc5322#section-2.2 //@see https://tools.ietf.org/html/rfc5322#section-2.2
//That means this may break if you do something daft like put vertical tabs in your headers. //That means this may break if you do something daft like put vertical tabs in your headers.
//Unfold header lines
$signHeader = preg_replace('/\r\n[ \t]+/', ' ', $signHeader); $signHeader = preg_replace('/\r\n[ \t]+/', ' ', $signHeader);
//Break headers out into an array //Break headers out into an array
$lines = explode("\r\n", $signHeader); $lines = explode(self::CRLF, $signHeader);
foreach ($lines as $key => $line) { foreach ($lines as $key => $line) {
//If the header is missing a :, skip it as it's invalid //If the header is missing a :, skip it as it's invalid
//This is likely to happen because the explode() above will also split //This is likely to happen because the explode() above will also split
@ -4498,7 +4533,7 @@ class PHPMailer
$lines[$key] = trim($heading, " \t") . ':' . trim($value, " \t"); $lines[$key] = trim($heading, " \t") . ':' . trim($value, " \t");
} }
return implode("\r\n", $lines); return implode(self::CRLF, $lines);
} }
/** /**
@ -4515,13 +4550,13 @@ class PHPMailer
public function DKIM_BodyC($body) public function DKIM_BodyC($body)
{ {
if (empty($body)) { if (empty($body)) {
return "\r\n"; return self::CRLF;
} }
// Normalize line endings to CRLF // Normalize line endings to CRLF
$body = static::normalizeBreaks($body, "\r\n"); $body = static::normalizeBreaks($body, self::CRLF);
//Reduce multiple trailing line breaks to a single one //Reduce multiple trailing line breaks to a single one
return rtrim($body, "\r\n") . "\r\n"; return static::stripTrailingWSP($body) . self::CRLF;
} }
/** /**
@ -4542,17 +4577,18 @@ class PHPMailer
$DKIMquery = 'dns/txt'; // Query method $DKIMquery = 'dns/txt'; // Query method
$DKIMtime = time(); $DKIMtime = time();
//Always sign these headers without being asked //Always sign these headers without being asked
//Recommended list from https://tools.ietf.org/html/rfc6376#section-5.4.1
$autoSignHeaders = [ $autoSignHeaders = [
'From', 'from',
'To', 'to',
'CC', 'cc',
'Date', 'date',
'Subject', 'subject',
'Reply-To', 'reply-to',
'Message-ID', 'message-id',
'Content-Type', 'content-type',
'Mime-Version', 'mime-version',
'X-Mailer', 'x-mailer',
]; ];
if (stripos($headers_line, 'Subject') === false) { if (stripos($headers_line, 'Subject') === false) {
$headers_line .= 'Subject: ' . $subject . static::$LE; $headers_line .= 'Subject: ' . $subject . static::$LE;
@ -4587,7 +4623,7 @@ class PHPMailer
$headersToSign = []; $headersToSign = [];
foreach ($parsedHeaders as $header) { foreach ($parsedHeaders as $header) {
//Is this header one that must be included in the DKIM signature? //Is this header one that must be included in the DKIM signature?
if (in_array($header['label'], $autoSignHeaders, true)) { if (in_array(strtolower($header['label']), $autoSignHeaders, true)) {
$headersToSignKeys[] = $header['label']; $headersToSignKeys[] = $header['label'];
$headersToSign[] = $header['label'] . ': ' . $header['value']; $headersToSign[] = $header['label'] . ': ' . $header['value'];
if ($this->DKIM_copyHeaderFields) { if ($this->DKIM_copyHeaderFields) {
@ -4625,9 +4661,9 @@ class PHPMailer
//Fold long values //Fold long values
if (strlen($copiedHeader) > self::STD_LINE_LENGTH - 3) { if (strlen($copiedHeader) > self::STD_LINE_LENGTH - 3) {
$copiedHeaderFields .= substr( $copiedHeaderFields .= substr(
chunk_split($copiedHeader, self::STD_LINE_LENGTH - 3, static::$LE . ' '), chunk_split($copiedHeader, self::STD_LINE_LENGTH - 3, static::$LE . self::FWS),
0, 0,
-strlen(static::$LE . ' ') -strlen(static::$LE . self::FWS)
); );
} else { } else {
$copiedHeaderFields .= $copiedHeader; $copiedHeaderFields .= $copiedHeader;
@ -4639,7 +4675,6 @@ class PHPMailer
$headerKeys = ' h=' . implode(':', $headersToSignKeys) . ';' . static::$LE; $headerKeys = ' h=' . implode(':', $headersToSignKeys) . ';' . static::$LE;
$headerValues = implode(static::$LE, $headersToSign); $headerValues = implode(static::$LE, $headersToSign);
$body = $this->DKIM_BodyC($body); $body = $this->DKIM_BodyC($body);
$DKIMlen = strlen($body); // Length of body
$DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
$ident = ''; $ident = '';
if ('' !== $this->DKIM_identity) { if ('' !== $this->DKIM_identity) {
@ -4653,7 +4688,6 @@ class PHPMailer
' s=' . $this->DKIM_selector . ';' . static::$LE . ' s=' . $this->DKIM_selector . ';' . static::$LE .
' a=' . $DKIMsignatureType . ';' . ' a=' . $DKIMsignatureType . ';' .
' q=' . $DKIMquery . ';' . ' q=' . $DKIMquery . ';' .
' l=' . $DKIMlen . ';' .
' t=' . $DKIMtime . ';' . ' t=' . $DKIMtime . ';' .
' c=' . $DKIMcanonicalization . ';' . static::$LE . ' c=' . $DKIMcanonicalization . ';' . static::$LE .
$headerKeys . $headerKeys .
@ -4666,9 +4700,9 @@ class PHPMailer
$headerValues . static::$LE . $dkimSignatureHeader $headerValues . static::$LE . $dkimSignatureHeader
); );
$signature = $this->DKIM_Sign($canonicalizedHeaders); $signature = $this->DKIM_Sign($canonicalizedHeaders);
$signature = trim(chunk_split($signature, self::STD_LINE_LENGTH - 3, static::$LE . ' ')); $signature = trim(chunk_split($signature, self::STD_LINE_LENGTH - 3, static::$LE . self::FWS));
return static::normalizeBreaks($dkimSignatureHeader . $signature) . static::$LE; return static::normalizeBreaks($dkimSignatureHeader . $signature);
} }
/** /**
@ -4684,6 +4718,28 @@ class PHPMailer
return (bool) preg_match('/^(.{' . (self::MAX_LINE_LENGTH + strlen(static::$LE)) . ',})/m', $str); return (bool) preg_match('/^(.{' . (self::MAX_LINE_LENGTH + strlen(static::$LE)) . ',})/m', $str);
} }
/**
* If a string contains any "special" characters, double-quote the name,
* and escape any double quotes with a backslash.
*
* @param string $str
*
* @return string
*
* @see RFC822 3.4.1
*/
public static function quotedString($str)
{
if (preg_match('/[ ()<>@,;:"\/\[\]?=]/', $str)) {
//If the string contains any of these chars, it must be double-quoted
//and any double quotes must be escaped with a backslash
return '"' . str_replace('"', '\\"', $str) . '"';
}
//Return the string untouched, it doesn't need quoting
return $str;
}
/** /**
* Allows for public read access to 'to' property. * Allows for public read access to 'to' property.
* Before the send() call, queued addresses (i.e. with IDN) are not yet included. * Before the send() call, queued addresses (i.e. with IDN) are not yet included.

View File

@ -45,7 +45,7 @@ class POP3
* *
* @var string * @var string
*/ */
const VERSION = '6.1.4'; const VERSION = '6.1.6';
/** /**
* Default POP3 port number. * Default POP3 port number.
@ -230,6 +230,8 @@ class POP3
} }
// connect to the POP3 server // connect to the POP3 server
$errno = 0;
$errstr = '';
$this->pop_conn = fsockopen( $this->pop_conn = fsockopen(
$host, // POP3 Host $host, // POP3 Host
$port, // Port # $port, // Port #

View File

@ -34,7 +34,7 @@ class SMTP
* *
* @var string * @var string
*/ */
const VERSION = '6.1.4'; const VERSION = '6.1.6';
/** /**
* SMTP line break constant. * SMTP line break constant.
@ -1168,7 +1168,7 @@ class SMTP
//Must pass vars in here as params are by reference //Must pass vars in here as params are by reference
if (!stream_select($selR, $selW, $selW, $this->Timelimit)) { if (!stream_select($selR, $selW, $selW, $this->Timelimit)) {
$this->edebug( $this->edebug(
'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', 'SMTP -> get_lines(): select timed-out in (' . $this->Timelimit . ' sec)',
self::DEBUG_LOWLEVEL self::DEBUG_LOWLEVEL
); );
break; break;
@ -1187,7 +1187,7 @@ class SMTP
$info = stream_get_meta_data($this->smtp_conn); $info = stream_get_meta_data($this->smtp_conn);
if ($info['timed_out']) { if ($info['timed_out']) {
$this->edebug( $this->edebug(
'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', 'SMTP -> get_lines(): stream timed-out (' . $this->Timeout . ' sec)',
self::DEBUG_LOWLEVEL self::DEBUG_LOWLEVEL
); );
break; break;
@ -1344,6 +1344,7 @@ class SMTP
} else { } else {
$this->last_smtp_transaction_id = false; $this->last_smtp_transaction_id = false;
foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) { foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
$matches = [];
if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) { if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
$this->last_smtp_transaction_id = trim($matches[1]); $this->last_smtp_transaction_id = trim($matches[1]);
break; break;

View File

@ -34,7 +34,7 @@ class e_user_providerTest extends \Codeception\Test\Unit
$this->assertIsArray($result); $this->assertIsArray($result);
$this->assertContains("Facebook", $result); $this->assertContains("Facebook", $result);
$this->assertContains("Twitter", $result); $this->assertContains("Twitter", $result);
$this->assertCount(45, $result, $this->assertCount(46, $result,
"The number of Hybridauth providers has changed! If this is intentional, note the change " . "The number of Hybridauth providers has changed! If this is intentional, note the change " .
"in Hybridauth providers in the release changelog and update the count in this test." "in Hybridauth providers in the release changelog and update the count in this test."
); );