diff --git a/.travis.yml b/.travis.yml index 6f81f0d74..b1400e89e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,10 @@ sudo: required dist: trusty php: - - 5.6 - - 7.2 + - 8.1 + - 8.2 + - 8.3 + - 8.4 before_script: - sudo cp -f tests/travis-ci-apache-vhost /etc/apache2/sites-available/default diff --git a/Adapter/Adapter_ProductPriceCalculator.php b/Adapter/Adapter_ProductPriceCalculator.php index 91e9b370f..ed3e04a30 100644 --- a/Adapter/Adapter_ProductPriceCalculator.php +++ b/Adapter/Adapter_ProductPriceCalculator.php @@ -42,7 +42,7 @@ class Adapter_ProductPriceCalculator &$specific_price_output = null, $with_ecotax = true, $use_group_reduction = true, - Context $context = null, + ?Context $context = null, $use_customer_price = true, $id_roomtype = false ) { diff --git a/Core/Foundation/Exception/Core_Foundation_Exception_Exception.php b/Core/Foundation/Exception/Core_Foundation_Exception_Exception.php index 16b46fee2..b7953c2ab 100644 --- a/Core/Foundation/Exception/Core_Foundation_Exception_Exception.php +++ b/Core/Foundation/Exception/Core_Foundation_Exception_Exception.php @@ -26,7 +26,7 @@ class Core_Foundation_Exception_Exception extends Exception { - public function __construct($message = null, $code = 0, Exception $previous = null) + public function __construct($message = null, $code = 0, ?Exception $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/Core/Foundation/IoC/Core_Foundation_IoC_Container.php b/Core/Foundation/IoC/Core_Foundation_IoC_Container.php index 093ea79a6..6cc2faf66 100644 --- a/Core/Foundation/IoC/Core_Foundation_IoC_Container.php +++ b/Core/Foundation/IoC/Core_Foundation_IoC_Container.php @@ -105,9 +105,9 @@ class Core_Foundation_IoC_Container if ($classConstructor) { foreach ($classConstructor->getParameters() as $param) { - $paramClass = $param->getClass(); + $paramClass = ($param->getType() && !$param->getType()->isBuiltin()) ? new ReflectionClass($param->getType()>getName()) : null; if ($paramClass) { - $args[] = $this->doMake($param->getClass()->getName(), $alreadySeen); + $args[] = $this->doMake($paramClass->getName(), $alreadySeen); } elseif ($param->isDefaultValueAvailable()) { $args[] = $param->getDefaultValue(); } else { diff --git a/README.md b/README.md index 51ca925c0..7f126b4d4 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,8 @@ The system compatibility will also be checked by the system with installation an #### Hosted Server Configurations * **Web server**: Apache 1.3, Apache 2.x, Nginx or Microsoft IIS -* **PHP version**: PHP 5.6+ to PHP 7.4 -* **MySQL version**: 5.1+ to 5.7 installed with a database created +* **PHP version**: PHP 8.1+ to PHP 8.4 +* **MySQL version**: 5.7+ to 8.4 installed with a database created * SSH or FTP access (ask your hosting service for your credentials) * In the PHP configuration ask your provider to set memory_limit to "128M", upload_max_filesize to "16M" , max_execution_time to "500" and allow_url_fopen "on" * SSL certificate if you plan to process payments internally (not using PayPal for instance) @@ -59,8 +59,8 @@ The system compatibility will also be checked by the system with installation an * **Supported operating system**: Windows, Mac, and Linux * **A prepared package**: WampServer (for Windows), Xampp (for Windows and Mac) or EasyPHP (for Windows) * **Web server**: Apache 1.3, Apache 2.x, Nginx or Microsoft IIS -* **PHP**: PHP 5.6+ to PHP 7.4 -* **MySQL** 5.1+ to 5.7 installed with a database created +* **PHP**: PHP 8.1+ to PHP 8.4 +* **MySQL** 5.7+ to 8.4 installed with a database created * In the PHP configuration, set memory_limit to "128M", upload_max_filesize to "16M" and max_execution_time to "500" * **Required PHP extensions**: PDO_MySQL, cURL, OpenSSL, SOAP, GD, SimpleXML, DOM, Zip, Phar @@ -88,7 +88,7 @@ Please don't disclose security vulnerabilities publicly. If you find any securit ### Documentation & Demo -#### QloApps Documentation +#### QloApps Documentation [https://qloapps.com/qlo-reservation-system](https://qloapps.com/qlo-reservation-system) #### QloApps Demo **Link** : https://demo.qloapps.com diff --git a/admin/filemanager/include/php_image_magician.php b/admin/filemanager/include/php_image_magician.php index 1f384d2e9..0922a7236 100644 --- a/admin/filemanager/include/php_image_magician.php +++ b/admin/filemanager/include/php_image_magician.php @@ -455,7 +455,7 @@ class imageLib // *** Crop this bad boy $crop = imagecreatetruecolor($newWidth, $newHeight); $this->keepTransparancy($optimalWidth, $optimalHeight, $crop); - imagecopyresampled($crop, $this->imageResized, 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight, $newWidth, $newHeight); + imagecopyresampled($crop, $this->imageResized, 0, 0, (int) $cropStartX, (int) $cropStartY, (int) $newWidth, (int) $newHeight, (int) $newWidth, (int) $newHeight); $this->imageResized = $crop; diff --git a/admin/functions.php b/admin/functions.php index 3882086b2..d6d2d148c 100644 --- a/admin/functions.php +++ b/admin/functions.php @@ -287,7 +287,7 @@ function checkTabRights($id_tab) } if (isset($tab_accesses[(int)$id_tab]['view'])) { - return ($tab_accesses[(int)$id_tab]['view'] === '1'); + return ($tab_accesses[(int)$id_tab]['view'] === 1); } return false; } diff --git a/admin/themes/default/template/controllers/groups/helpers/tree/tree_node_folder_radio.tpl b/admin/themes/default/template/controllers/groups/helpers/tree/tree_node_folder_radio.tpl index 4e635fb1d..2076fd73a 100644 --- a/admin/themes/default/template/controllers/groups/helpers/tree/tree_node_folder_radio.tpl +++ b/admin/themes/default/template/controllers/groups/helpers/tree/tree_node_folder_radio.tpl @@ -29,6 +29,6 @@
'.((Tools::getValue('back')) ? $this->l('Back') : $this->l('Back to list')).'
'.((Tools::getValue('back')) ? $this->l('Back') : $this->l('Back to list')).'
';
}
- protected function _displayViewLink($token = null, $id)
+ protected function _displayViewLink($token, $id)
{
$_cacheLang['View'] = $this->l('View');
$href = Tools::safeOutput(self::$currentIndex.'&'.$this->identifier.'='.(int)$id.'&view'.$this->table.'&token='.($token != null ? $token : $this->token));
@@ -1820,7 +1820,7 @@ abstract class AdminTabCore
';
}
- protected function _displayEditLink($token = null, $id)
+ protected function _displayEditLink($token, $id)
{
$_cacheLang['Edit'] = $this->l('Edit');
$href = Tools::safeOutput(self::$currentIndex.'&'.$this->identifier.'='.(int)$id.'&update'.$this->table.'&token='.($token != null ? $token : $this->token));
@@ -1829,7 +1829,7 @@ abstract class AdminTabCore
';
}
- protected function _displayDeleteLink($token = null, $id)
+ protected function _displayDeleteLink($token, $id)
{
$_cacheLang['Delete'] = $this->l('Delete');
$_cacheLang['DeleteItem'] = $this->l('Delete item #', __CLASS__, true, false);
@@ -2344,7 +2344,7 @@ abstract class AdminTabCore
$this->tabAccess = Profile::getProfileAccess($this->context->employee->id_profile, $this->id);
- if ($this->tabAccess['view'] === '1') {
+ if ($this->tabAccess['view'] === 1) {
return true;
}
return false;
diff --git a/classes/AttributeGroup.php b/classes/AttributeGroup.php
index 385a9eb0d..b2804b726 100644
--- a/classes/AttributeGroup.php
+++ b/classes/AttributeGroup.php
@@ -161,7 +161,7 @@ class AttributeGroupCore extends ObjectModel
return false;
}
}
- $this->cleanPositions();
+ AttributeGroup::cleanPositions();
}
$return = parent::delete();
if ($return) {
diff --git a/classes/CMS.php b/classes/CMS.php
index 3476d9a25..5fdf9a9a8 100644
--- a/classes/CMS.php
+++ b/classes/CMS.php
@@ -74,7 +74,7 @@ class CMSCore extends ObjectModel
public function update($null_values = false)
{
if (parent::update($null_values)) {
- return $this->cleanPositions($this->id_cms_category);
+ return CMS::cleanPositions($this->id_cms_category);
}
return false;
}
@@ -82,12 +82,12 @@ class CMSCore extends ObjectModel
public function delete()
{
if (parent::delete()) {
- return $this->cleanPositions($this->id_cms_category);
+ return CMS::cleanPositions($this->id_cms_category);
}
return false;
}
- public static function getLinks($id_lang, $selection = null, $active = true, Link $link = null)
+ public static function getLinks($id_lang, $selection = null, $active = true, ?Link $link = null)
{
if (!$link) {
$link = Context::getContext()->link;
diff --git a/classes/CMSCategory.php b/classes/CMSCategory.php
index f45cc74a2..4d660ef02 100644
--- a/classes/CMSCategory.php
+++ b/classes/CMSCategory.php
@@ -105,7 +105,7 @@ class CMSCategoryCore extends ObjectModel
}
}
$ret = parent::add($autodate, $null_values);
- $this->cleanPositions($this->id_parent);
+ CMSCategory::cleanPositions($this->id_parent);
return $ret;
}
@@ -130,7 +130,7 @@ class CMSCategoryCore extends ObjectModel
*
* @return array Subcategories lite tree
*/
- public function recurseLiteCategTree($max_depth = 3, $currentDepth = 0, $id_lang = null, $excluded_ids_array = null, Link $link = null)
+ public function recurseLiteCategTree($max_depth = 3, $currentDepth = 0, $id_lang = null, $excluded_ids_array = null, ?Link $link = null)
{
if (!$link) {
$link = Context::getContext()->link;
@@ -164,7 +164,7 @@ class CMSCategoryCore extends ObjectModel
);
}
- public static function getRecurseCategory($id_lang = null, $current = 1, $active = 1, $links = 0, Link $link = null)
+ public static function getRecurseCategory($id_lang = null, $current = 1, $active = 1, $links = 0, ?Link $link = null)
{
if (!$link) {
$link = Context::getContext()->link;
@@ -487,7 +487,7 @@ class CMSCategoryCore extends ObjectModel
return $result['link_rewrite'];
}
- public function getLink(Link $link = null)
+ public function getLink(?Link $link = null)
{
if (!$link) {
$link = Context::getContext()->link;
diff --git a/classes/Carrier.php b/classes/Carrier.php
index 7e4fdc8fb..143d52d22 100644
--- a/classes/Carrier.php
+++ b/classes/Carrier.php
@@ -1057,12 +1057,12 @@ class CarrierCore extends ObjectModel
return $suffix;
}
- public function getIdTaxRulesGroup(Context $context = null)
+ public function getIdTaxRulesGroup(?Context $context = null)
{
return Carrier::getIdTaxRulesGroupByIdCarrier((int)$this->id, $context);
}
- public static function getIdTaxRulesGroupByIdCarrier($id_carrier, Context $context = null)
+ public static function getIdTaxRulesGroupByIdCarrier($id_carrier, ?Context $context = null)
{
if (!$context) {
$context = Context::getContext();
@@ -1079,7 +1079,7 @@ class CarrierCore extends ObjectModel
return Cache::retrieve($key);
}
- public function deleteTaxRulesGroup(array $shops = null)
+ public function deleteTaxRulesGroup(?array $shops = null)
{
if (!$shops) {
$shops = Shop::getContextListShopID();
diff --git a/classes/Cart.php b/classes/Cart.php
index bc233be1e..dd7692a16 100644
--- a/classes/Cart.php
+++ b/classes/Cart.php
@@ -1028,7 +1028,7 @@ class CartCore extends ObjectModel
* @param string $operator Indicate if quantity must be increased or decreased
*/
public function updateQty($quantity, $id_product, $id_product_attribute = null, $id_customization = false,
- $operator = 'up', $id_address_delivery = 0, Shop $shop = null, $auto_add_cart_rule = true)
+ $operator = 'up', $id_address_delivery = 0, ?Shop $shop = null, $auto_add_cart_rule = true)
{
if (!$shop) {
$shop = Context::getContext()->shop;
@@ -1056,7 +1056,7 @@ class CartCore extends ObjectModel
/* If we have a product combination, the minimal quantity is set with the one of this combination */
if (!empty($id_product_attribute)) {
- $minimal_quantity = (int)Attribute::getAttributeMinimalQty($id_product_attribute);
+ $minimal_quantity = (int)ProductAttribute::getAttributeMinimalQty($id_product_attribute);
} else {
$minimal_quantity = (int)$product->minimal_quantity;
}
@@ -1620,7 +1620,7 @@ class CartCore extends ObjectModel
$param_product = true;
if (is_null($products)) {
$param_product = false;
- $products = $this->getProducts(false, false, null, false);
+ $products = $this->getProducts(false, false, null);
}
if ($type == Cart::ONLY_PHYSICAL_PRODUCTS_WITHOUT_SHIPPING) {
@@ -2150,7 +2150,7 @@ class CartCore extends ObjectModel
return $cache[$cache_key];
}
- $product_list = $this->getProducts($flush, false, null, true);
+ $product_list = $this->getProducts($flush, false, null);
// Step 1 : Get product informations (warehouse_list and carrier_list), count warehouse
// Determine the best warehouse to determine the packages
// For that we count the number of time we can use a warehouse for a specific delivery address
@@ -2643,7 +2643,7 @@ class CartCore extends ObjectModel
* );
* If there are no carriers available for an address, return an empty array
*/
- public function getDeliveryOptionList(Country $default_country = null, $flush = false)
+ public function getDeliveryOptionList(?Country $default_country = null, $flush = false)
{
static $cache = array();
if (isset($cache[$this->id]) && !$flush) {
@@ -2979,7 +2979,7 @@ class CartCore extends ObjectModel
* @param bool $flush Force flushing cache
*
*/
- public function simulateCarriersOutput(Country $default_country = null, $flush = false)
+ public function simulateCarriersOutput(?Country $default_country = null, $flush = false)
{
$delivery_option_list = $this->getDeliveryOptionList($default_country, $flush);
@@ -3293,7 +3293,7 @@ class CartCore extends ObjectModel
* @param Country|null $default_country
* @return float Shipping total
*/
- public function getTotalShippingCost($delivery_option = null, $use_tax = true, Country $default_country = null)
+ public function getTotalShippingCost($delivery_option = null, $use_tax = true, ?Country $default_country = null)
{
if (isset(Context::getContext()->cookie->id_country)) {
$default_country = new Country(Context::getContext()->cookie->id_country);
@@ -3328,7 +3328,7 @@ class CartCore extends ObjectModel
* @param array|null $delivery_option
* @return float Shipping total
*/
- public function getCarrierCost($id_carrier, $useTax = true, Country $default_country = null, $delivery_option = null)
+ public function getCarrierCost($id_carrier, $useTax = true, ?Country $default_country = null, $delivery_option = null)
{
if (is_null($delivery_option)) {
$delivery_option = $this->getDeliveryOption($default_country);
@@ -3357,7 +3357,7 @@ class CartCore extends ObjectModel
/**
* @deprecated 1.5.0, use Cart->getPackageShippingCost()
*/
- public function getOrderShippingCost($id_carrier = null, $use_tax = true, Country $default_country = null, $product_list = null)
+ public function getOrderShippingCost($id_carrier = null, $use_tax = true, ?Country $default_country = null, $product_list = null)
{
Tools::displayAsDeprecated();
return $this->getPackageShippingCost((int)$id_carrier, $use_tax, $default_country, $product_list);
@@ -3375,7 +3375,7 @@ class CartCore extends ObjectModel
*
* @return float Shipping total
*/
- public function getPackageShippingCost($id_carrier = null, $use_tax = true, Country $default_country = null, $product_list = null, $id_zone = null)
+ public function getPackageShippingCost($id_carrier = null, $use_tax = true, ?Country $default_country = null, $product_list = null, $id_zone = null)
{
if ($this->isVirtualCart()) {
return 0;
@@ -4827,7 +4827,7 @@ class CartCore extends ObjectModel
// get bookings xaml data
$postData = trim(file_get_contents('php://input'));
libxml_use_internal_errors(true);
- $xml = simplexml_load_string(utf8_decode($postData));
+ $xml = simplexml_load_string(mb_convert_encoding($postData, 'ISO-8859-1'));
$cartData = json_decode(json_encode($xml, true));
$this->id_address_delivery = $cartData->cart->id_address_delivery;
@@ -4847,7 +4847,7 @@ class CartCore extends ObjectModel
return false;
}
- public function updateWs($autodate = true, $null_values = false)
+ public function updateWs($null_values = false)
{
$this->id_shop = Configuration::get('PS_SHOP_DEFAULT');
$objShop = new Shop($this->id_shop);
@@ -4856,14 +4856,14 @@ class CartCore extends ObjectModel
// get bookings xml data
$postData = trim(file_get_contents('php://input'));
libxml_use_internal_errors(true);
- $xml = simplexml_load_string(utf8_decode($postData));
+ $xml = simplexml_load_string(mb_convert_encoding($postData, 'ISO-8859-1'));
$cartData = json_decode(json_encode($xml, true));
$this->id_address_delivery = $cartData->cart->id_address_delivery;
$this->id_address_invoice = $cartData->cart->id_address_invoice;
- if ($this->update($autodate, $null_values)) {
+ if ($this->update($null_values)) {
// set bookings for the cart
$bookingRows = $cartData->cart->associations->cart_bookings->booking;
if (isset($bookingRows->id_hotel)) {
@@ -4937,7 +4937,7 @@ class CartCore extends ObjectModel
}
if (!count($errors)) {
- $numDays = $objBookingDetail->getNumberOfDays($dateFrom, $dateTo);
+ $numDays = HotelHelper::getNumberOfDays($dateFrom, $dateTo);
$prodQty = $prodQty * (int) $numDays;
$reqRooms = 1;
diff --git a/classes/CartRule.php b/classes/CartRule.php
index d8a340c6e..240015b37 100644
--- a/classes/CartRule.php
+++ b/classes/CartRule.php
@@ -263,7 +263,7 @@ class CartRuleCore extends ObjectModel
* @return array
* @throws PrestaShopDatabaseException
*/
- public static function getCustomerCartRules($id_lang, $id_customer, $active = false, $includeGeneric = true, $inStock = false, Cart $cart = null, $free_shipping_only = false, $highlight_only = false)
+ public static function getCustomerCartRules($id_lang, $id_customer, $active = false, $includeGeneric = true, $inStock = false, ?Cart $cart = null, $free_shipping_only = false, $highlight_only = false)
{
if (!CartRule::isFeatureActive()) {
return array();
@@ -926,7 +926,7 @@ class CartRuleCore extends ObjectModel
* @param bool $only_advance_payment_products to calculate discount applied only on products that have advance payment
* @return float|int|string
*/
- public function getContextualValue($use_tax, Context $context = null, $filter = null, $package = null, $use_cache = true, $only_advance_payment_products = false)
+ public function getContextualValue($use_tax, ?Context $context = null, $filter = null, $package = null, $use_cache = true, $only_advance_payment_products = false)
{
if (!CartRule::isFeatureActive()) {
return 0;
@@ -1361,8 +1361,7 @@ class CartRuleCore extends ObjectModel
.(in_array($type, array('carrier', 'shop')) ? ' AND t.deleted = 0' : '').
(in_array($type, array('carrier', 'shop')) ? ' ORDER BY t.name ASC ' : '').
(in_array($type, array('country', 'group', 'cart_rule')) && $i18n ? ' ORDER BY tl.name ASC ' : '').
- $sql_limit,
- false);
+ $sql_limit);
while ($row = Db::getInstance()->nextRow($resource)) {
$array[($row['selected'] || $this->{$type.'_restriction'} == 0) ? 'selected' : 'unselected'][] = $row;
}
@@ -1403,7 +1402,7 @@ class CartRuleCore extends ObjectModel
* @param Context|null $context
* @return mixed
*/
- public static function autoAddToCart(Context $context = null)
+ public static function autoAddToCart(?Context $context = null)
{
if ($context === null) {
$context = Context::getContext();
diff --git a/classes/Category.php b/classes/Category.php
index fcd044edd..7524d1688 100644
--- a/classes/Category.php
+++ b/classes/Category.php
@@ -136,10 +136,8 @@ class CategoryCore extends ObjectModel
{
parent::__construct($id_category, $id_lang, $id_shop);
- $link = new Link();
- $imgLink = $link->getMediaLink(_PS_CAT_IMG_DIR_.(int)$this->id.'.jpg'); // by webkul use media link for images
- $this->id_image = ($this->id && (bool)Tools::file_get_contents($imgLink)) ? (int)$this->id : false;
$this->image_dir = _PS_CAT_IMG_DIR_;
+ $this->id_image = ($this->id && file_exists($this->image_dir . (int) $this->id . '.jpg')) ? (int) $this->id : false;
}
public static function getDescriptionClean($description)
@@ -221,7 +219,7 @@ class CategoryCore extends ObjectModel
$ret = parent::update($null_values);
if ($changed && (!isset($this->doNotRegenerateNTree) || !$this->doNotRegenerateNTree)) {
- $this->cleanPositions((int)$this->id_parent);
+ Category::cleanPositions((int)$this->id_parent);
Category::regenerateEntireNtree();
$this->recalculateLevelDepth($this->id);
}
@@ -703,7 +701,7 @@ class CategoryCore extends ObjectModel
* @return array|int|false Products, number of products or false (no access)
* @throws PrestaShopDatabaseException
*/
- public function getProducts($id_lang, $p, $n, $order_by = null, $order_way = null, $get_total = false, $active = true, $random = false, $random_number_products = 1, $check_access = true, Context $context = null)
+ public function getProducts($id_lang, $p, $n, $order_by = null, $order_way = null, $get_total = false, $active = true, $random = false, $random_number_products = 1, $check_access = true, ?Context $context = null)
{
if (!$context) {
$context = Context::getContext();
@@ -823,7 +821,7 @@ class CategoryCore extends ObjectModel
return self::getChildren(Configuration::get('PS_HOME_CATEGORY'), $id_lang, $active, $id_shop);
}
- public static function getRootCategory($id_lang = null, Shop $shop = null)
+ public static function getRootCategory($id_lang = null, ?Shop $shop = null)
{
$context = Context::getContext();
if (is_null($id_lang)) {
@@ -970,7 +968,7 @@ class CategoryCore extends ObjectModel
* @param int $id_lang
* @return array
*/
- public static function getChildrenWithNbSelectedSubCat($id_parent, $selected_cat, $id_lang, Shop $shop = null, $use_shop_context = true)
+ public static function getChildrenWithNbSelectedSubCat($id_parent, $selected_cat, $id_lang, ?Shop $shop = null, $use_shop_context = true)
{
if (!$shop) {
$shop = Context::getContext()->shop;
@@ -1090,7 +1088,7 @@ class CategoryCore extends ObjectModel
return self::$_links[$id_category.'-'.$id_lang];
}
- public function getLink(Link $link = null, $id_lang = null)
+ public function getLink(?Link $link = null, $id_lang = null)
{
if (!$link) {
$link = Context::getContext()->link;
@@ -1564,7 +1562,7 @@ class CategoryCore extends ObjectModel
* @param Shop $shop
* @return bool
*/
- public function inShop(Shop $shop = null)
+ public function inShop(?Shop $shop = null)
{
if (!$shop) {
$shop = Context::getContext()->shop;
@@ -1576,7 +1574,7 @@ class CategoryCore extends ObjectModel
return ($this->nleft >= $interval['nleft'] && $this->nright <= $interval['nright']);
}
- public static function inShopStatic($id_category, Shop $shop = null)
+ public static function inShopStatic($id_category, ?Shop $shop = null)
{
if (!$shop || !is_object($shop)) {
$shop = Context::getContext()->shop;
diff --git a/classes/ConfigurationTest.php b/classes/ConfigurationTest.php
index 98bdaeb44..25c5599fb 100644
--- a/classes/ConfigurationTest.php
+++ b/classes/ConfigurationTest.php
@@ -145,14 +145,14 @@ class ConfigurationTestCore
public static function test_phpversion()
{
return (
- version_compare(substr(phpversion(), 0, 5), '5.6.0', '>=')
- && version_compare(substr(phpversion(), 0, 5), '8.0', '<')
+ version_compare(substr(phpversion(), 0, 5), '8.1.0', '>=')
+ && version_compare(substr(phpversion(), 0, 5), '8.5', '<')
);
}
public static function test_new_phpversion()
{
- return version_compare(substr(phpversion(), 0, 5), '5.6.0', '>=');
+ return version_compare(substr(phpversion(), 0, 5), '8.1.0', '>=');
}
public static function test_mysql_support()
@@ -188,7 +188,7 @@ class ConfigurationTestCore
public static function test_upload_max_filesize()
{
$upload_max_filesize = preg_replace('/[^0-9\.-]/', '', ini_get('upload_max_filesize'));
- if ($upload_max_filesize >= 16) {
+ if ($upload_max_filesize >= 2) {
return true;
}
return false;
diff --git a/classes/ConnectionsSource.php b/classes/ConnectionsSource.php
index a258b9d48..6c9dc5f9d 100644
--- a/classes/ConnectionsSource.php
+++ b/classes/ConnectionsSource.php
@@ -56,7 +56,7 @@ class ConnectionsSourceCore extends ObjectModel
return $result;
}
- public static function logHttpReferer(Cookie $cookie = null)
+ public static function logHttpReferer(?Cookie $cookie = null)
{
if (!$cookie) {
$cookie = Context::getContext()->cookie;
@@ -86,7 +86,7 @@ class ConnectionsSourceCore extends ObjectModel
return false;
}
- if ((preg_replace('/^www./', '', $parsed['host']) == preg_replace('/^www./', '', Tools::getHttpHost(false, false))) && !strncmp($parsed['path'], $parsed_host['path'], strlen(__PS_BASE_URI__))) {
+ if ((preg_replace('/^www./', '', $parsed['host']) == preg_replace('/^www./', '', Tools::getHttpHost(false, false, true))) && !strncmp($parsed['path'], $parsed_host['path'], strlen(__PS_BASE_URI__))) {
return false;
}
diff --git a/classes/Context.php b/classes/Context.php
index d616ff8d1..5461fce9e 100644
--- a/classes/Context.php
+++ b/classes/Context.php
@@ -29,7 +29,8 @@
*
* @since 1.5.0.1
*/
-class ContextCore
+#[\AllowDynamicProperties]
+ class ContextCore
{
/* @var Context */
protected static $instance;
@@ -124,8 +125,8 @@ class ContextCore
public function getMobileDetect()
{
if ($this->mobile_detect === null) {
- require_once(_PS_TOOL_DIR_.'mobile_Detect/Mobile_Detect.php');
- $this->mobile_detect = new Mobile_Detect();
+ require_once(_PS_TOOL_DIR_.'mobile_detect/autoload.php');
+ $this->mobile_detect = new Detection\MobileDetect();
}
return $this->mobile_detect;
}
diff --git a/classes/Cookie.php b/classes/Cookie.php
index 90dbc9509..de404e6ae 100644
--- a/classes/Cookie.php
+++ b/classes/Cookie.php
@@ -24,6 +24,7 @@
* International Registered Trademark & Property of PrestaShop SA
*/
+#[\AllowDynamicProperties]
class CookieCore
{
const SAMESITE_NONE = 'None';
@@ -351,7 +352,7 @@ class CookieCore
*/
protected function _setcookie($cookie = null)
{
- $length = (ini_get('mbstring.func_overload') & 2) ? mb_strlen($cookie, ini_get('default_charset')) : strlen($cookie);
+ $length = (ini_get('mbstring.func_overload') & 2) ? mb_strlen($cookie, ini_get('default_charset')) : Tools::strlen($cookie);
if ($length >= 1048576) {
return false;
}
diff --git a/classes/Country.php b/classes/Country.php
index 8782814e0..a2990ac09 100644
--- a/classes/Country.php
+++ b/classes/Country.php
@@ -254,7 +254,7 @@ class CountryCore extends ObjectModel
* @param string $country Country Name
* @return int Country ID
*/
- public static function getIdByName($id_lang = null, $country)
+ public static function getIdByName($id_lang, $country)
{
$sql = '
SELECT `id_country`
diff --git a/classes/Customer.php b/classes/Customer.php
index fd5fe9f97..0c2ac0023 100644
--- a/classes/Customer.php
+++ b/classes/Customer.php
@@ -242,7 +242,9 @@ class CustomerCore extends ObjectModel
$this->secure_key = md5(uniqid(rand(), true));
$this->last_passwd_gen = date('Y-m-d H:i:s', strtotime('-'.Configuration::get('PS_PASSWD_TIME_FRONT').'minutes'));
- if ($this->newsletter && !Validate::isDate($this->newsletter_date_add)) {
+ if ($this->newsletter
+ && (!$this->newsletter_date_add || !Validate::isDate($this->newsletter_date_add))
+ ) {
$this->newsletter_date_add = date('Y-m-d H:i:s');
}
@@ -795,7 +797,7 @@ class CustomerCore extends ObjectModel
return self::$_defaultGroupId[(int)$id_customer];
}
- public static function getCurrentCountry($id_customer, Cart $cart = null)
+ public static function getCurrentCountry($id_customer, ?Cart $cart = null)
{
if (!$cart) {
$cart = Context::getContext()->cart;
diff --git a/classes/CustomerGuestDetail.php b/classes/CustomerGuestDetail.php
index f40bf3006..95f17d7f8 100644
--- a/classes/CustomerGuestDetail.php
+++ b/classes/CustomerGuestDetail.php
@@ -85,7 +85,7 @@ class CustomerGuestDetailCore extends ObjectModel
* @param int id_cart
* @return bool True on success, false on failure
*/
- public function deleteCustomerGuestInCart($idCart)
+ public static function deleteCustomerGuestInCart($idCart)
{
return Db::getInstance()->delete(
'cart_customer_guest',
diff --git a/classes/DateRange.php b/classes/DateRange.php
index 075d212b7..21d734a16 100644
--- a/classes/DateRange.php
+++ b/classes/DateRange.php
@@ -55,7 +55,7 @@ class DateRangeCore extends ObjectModel
$rangeSize = 86399;
$dateRange = new DateRange();
$dateRange->time_start = date('Y-m-d');
- $dateRange->time_end = strftime('%Y-%m-%d %H:%M:%S', strtotime($dateRange->time_start) + $rangeSize);
+ $dateRange->time_end = date('Y-m-d H:i:s', strtotime($dateRange->time_start) + $rangeSize);
$dateRange->add();
return $dateRange->id;
}
diff --git a/classes/Discount.php b/classes/Discount.php
index 82f3769fe..66ab5711b 100644
--- a/classes/Discount.php
+++ b/classes/Discount.php
@@ -175,7 +175,7 @@ class DiscountCore extends CartRule
/**
* @deprecated 1.5.0.1
*/
- public static function getCustomerDiscounts($id_lang, $id_customer, $active = false, $includeGenericOnes = true, $hasStock = false, Cart $cart = null)
+ public static function getCustomerDiscounts($id_lang, $id_customer, $active = false, $includeGenericOnes = true, $hasStock = false, ?Cart $cart = null)
{
return parent::getCustomerCartRules($id_lang, $id_customer, $active, $includeGenericOnes, $hasStock, $cart);
}
@@ -191,7 +191,7 @@ class DiscountCore extends CartRule
/**
* @deprecated 1.5.0.1
*/
- public function getValue($nb_discounts = 0, $order_total_products = 0, $shipping_fees = 0, $id_cart = false, $useTax = true, Currency $currency = null, Shop $shop = null)
+ public function getValue($nb_discounts = 0, $order_total_products = 0, $shipping_fees = 0, $id_cart = false, $useTax = true, ?Currency $currency = null, ?Shop $shop = null)
{
$context = Context::getContext();
if ((int)$id_cart) {
diff --git a/classes/Feature.php b/classes/Feature.php
index 8d9816263..9b9035886 100644
--- a/classes/Feature.php
+++ b/classes/Feature.php
@@ -151,7 +151,7 @@ class FeatureCore extends ObjectModel
}
/* Reinitializing position */
- $this->cleanPositions();
+ static::cleanPositions();
return $return;
}
diff --git a/classes/Group.php b/classes/Group.php
index 1ea01a9e1..75fca9585 100644
--- a/classes/Group.php
+++ b/classes/Group.php
@@ -189,7 +189,7 @@ class GroupCore extends ObjectModel
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'category_group` WHERE `id_group` = '.(int)$this->id);
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'group_reduction` WHERE `id_group` = '.(int)$this->id);
Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'product_group_reduction_cache` WHERE `id_group` = '.(int)$this->id);
- $this->truncateModulesRestrictions($this->id);
+ self::truncateModulesRestrictions($this->id);
// Add default group (id 3) to customers without groups
Db::getInstance()->execute('INSERT INTO `'._DB_PREFIX_.'customer_group` (
diff --git a/classes/Hook.php b/classes/Hook.php
index 6604c73dd..c408813a2 100644
--- a/classes/Hook.php
+++ b/classes/Hook.php
@@ -618,7 +618,7 @@ class HookCore extends ObjectModel
{
return '
'
.Tools::safeOutput($moduleInstance->displayName).'
diff --git a/classes/ImageManager.php b/classes/ImageManager.php
index 015c83372..c811fdbcf 100644
--- a/classes/ImageManager.php
+++ b/classes/ImageManager.php
@@ -80,7 +80,7 @@ class ImageManagerCore
$size = $y / ($x / $max_x);
}
- ImageManager::resize($image, _PS_TMP_IMG_DIR_.$cache_image, $ratio_x, $size, $image_type);
+ ImageManager::resize($image, _PS_TMP_IMG_DIR_.$cache_image, (int)$ratio_x, (int)$size, $image_type);
}
}
// Relative link will always work, whatever the base uri set in the admin
diff --git a/classes/Language.php b/classes/Language.php
index 976b4ec79..0963279bb 100644
--- a/classes/Language.php
+++ b/classes/Language.php
@@ -541,15 +541,17 @@ class LanguageCore extends ObjectModel
$modList = scandir(_PS_MODULE_DIR_);
foreach ($modList as $mod) {
Language::recurseDeleteDir(_PS_MODULE_DIR_.$mod.'/mails/'.$this->iso_code);
- $files = @scandir(_PS_MODULE_DIR_.$mod.'/mails/');
- if (count($files) <= 2) {
+ if (($files = @scandir(_PS_MODULE_DIR_.$mod.'/mails/'))
+ && (count($files) <= 2)
+ ) {
Language::recurseDeleteDir(_PS_MODULE_DIR_.$mod.'/mails/');
}
if (file_exists(_PS_MODULE_DIR_.$mod.'/'.$this->iso_code.'.php')) {
unlink(_PS_MODULE_DIR_.$mod.'/'.$this->iso_code.'.php');
- $files = @scandir(_PS_MODULE_DIR_.$mod);
- if (count($files) <= 2) {
+ if (($files = @scandir(_PS_MODULE_DIR_.$mod))
+ && (count($files) <= 2)
+ ) {
Language::recurseDeleteDir(_PS_MODULE_DIR_.$mod);
}
}
diff --git a/classes/Link.php b/classes/Link.php
index 69d3f11de..f5c58e6b9 100644
--- a/classes/Link.php
+++ b/classes/Link.php
@@ -483,7 +483,7 @@ class LinkCore
}
} else {
// @FIXME html_entity_decode has been added due to '&' => '%3B' ...
- $request = html_entity_decode($request);
+ $request = html_entity_decode($request ?? '');
if ($request_url_encode) {
$request = urlencode($request);
}
@@ -511,7 +511,7 @@ class LinkCore
* @param int $id_lang Language ID
* @return string link
*/
- public function getLanguageLink($id_lang, Context $context = null)
+ public function getLanguageLink($id_lang, ?Context $context = null)
{
if (!$context) {
$context = Context::getContext();
@@ -644,7 +644,7 @@ class LinkCore
return $url.(!strstr($url, '?') ? '?' : '&').'orderby='.urlencode($orderby).'&orderway='.urlencode($orderway);
}
- protected function getLangLink($id_lang = null, Context $context = null, $id_shop = null)
+ protected function getLangLink($id_lang = null, ?Context $context = null, $id_shop = null)
{
if (!$context) {
$context = Context::getContext();
@@ -700,8 +700,8 @@ class LinkCore
public function matchQuickLink($url)
{
- $quicklink = $this->getQuickLink($url);
- if (isset($quicklink) && $quicklink === ($this->getQuickLink($_SERVER['REQUEST_URI']))) {
+ $quicklink = Link::getQuickLink($url);
+ if (isset($quicklink) && $quicklink === (Link::getQuickLink($_SERVER['REQUEST_URI']))) {
return true;
} else {
return false;
diff --git a/classes/Mail.php b/classes/Mail.php
index 6483afabd..b11a45225 100644
--- a/classes/Mail.php
+++ b/classes/Mail.php
@@ -24,7 +24,15 @@
* International Registered Trademark & Property of PrestaShop SA
*/
-include_once(_PS_SWIFT_DIR_.'swift_required.php');
+include_once(_PS_TOOL_DIR_.'mailer/autoload.php');
+
+use Symfony\Component\Mailer\Exception\ExceptionInterface;
+use Symfony\Component\Mailer\Mailer;
+use Symfony\Component\Mailer\Transport\SendmailTransport;
+use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
+use Symfony\Component\Mime\Address;
+use Symfony\Component\Mime\Email;
+use Symfony\Component\Mime\Header\IdentificationHeader;
class MailCore extends ObjectModel
{
@@ -84,10 +92,23 @@ class MailCore extends ObjectModel
* @param string $reply_to Email address for setting the Reply-To header
* @return bool|int Whether sending was successful. If not at all, false, otherwise amount of recipients succeeded.
*/
- public static function Send($id_lang, $template, $subject, $template_vars, $to,
- $to_name = null, $from = null, $from_name = null, $file_attachment = null, $mode_smtp = null,
- $template_path = _PS_MAIL_DIR_, $die = false, $id_shop = null, $bcc = null, $reply_to = null)
- {
+ public static function Send($id_lang,
+ $template,
+ $subject,
+ $template_vars,
+ $to,
+ $to_name = null,
+ $from = null,
+ $from_name = null,
+ $file_attachment = null,
+ $mode_smtp = null,
+ $template_path = _PS_MAIL_DIR_,
+ $die = false,
+ $id_shop = null,
+ $bcc = null,
+ $reply_to = null,
+ $reply_to_name = ''
+ ) {
if (!$id_shop) {
$id_shop = Context::getContext()->shop->id;
}
@@ -121,9 +142,14 @@ class MailCore extends ObjectModel
}
}
- if (!isset($configuration['PS_MAIL_SMTP_ENCRYPTION']) || Tools::strtolower($configuration['PS_MAIL_SMTP_ENCRYPTION']) === 'off') {
- $configuration['PS_MAIL_SMTP_ENCRYPTION'] = false;
+ if (!isset($configuration['PS_MAIL_SMTP_ENCRYPTION'])
+ || Tools::strtolower($configuration['PS_MAIL_SMTP_ENCRYPTION']) === 'off'
+ ) {
+ $isTls = false;
+ } else {
+ $isTls = true;
}
+
if (!isset($configuration['PS_MAIL_SMTP_PORT'])) {
$configuration['PS_MAIL_SMTP_PORT'] = 'default';
}
@@ -180,7 +206,7 @@ class MailCore extends ObjectModel
try {
/* Construct multiple recipients list if needed */
- $message = Swift_Message::newInstance();
+ $email = new Email();
if (is_array($to) && isset($to)) {
foreach ($to as $key => $addr) {
$addr = trim($addr);
@@ -196,14 +222,14 @@ class MailCore extends ObjectModel
}
$addrName = (($addrName == null || $addrName == $addr || !Validate::isGenericName($addrName)) ? '' : self::mimeEncode($addrName));
- $message->addTo($addr, $addrName);
+ $email->addTo(new Address($addr, $addrName));
}
$to_plugin = $to[0];
} else {
/* Simple recipient, one address */
$to_plugin = $to;
$to_name = (($to_name == null || $to_name == $to) ? '' : self::mimeEncode($to_name));
- $message->addTo($to, $to_name);
+ $email->addTo(new Address($to, $to_name));
}
if (isset($bcc) && is_array($bcc)) {
@@ -213,10 +239,10 @@ class MailCore extends ObjectModel
Tools::dieOrLog(Tools::displayError('Error: invalid e-mail address'), $die);
return false;
}
- $message->addBcc($addr);
+ $email->addBcc(new Address($addr));
}
} elseif (isset($bcc)) {
- $message->addBcc($bcc);
+ $email->addBcc(new Address($bcc));
}
/* Connect with the appropriate configuration */
@@ -226,18 +252,19 @@ class MailCore extends ObjectModel
return false;
}
- $connection = Swift_SmtpTransport::newInstance($configuration['PS_MAIL_SERVER'], $configuration['PS_MAIL_SMTP_PORT'], $configuration['PS_MAIL_SMTP_ENCRYPTION'])
+ $transport = (new EsmtpTransport(
+ $configuration['PS_MAIL_SERVER'],
+ $configuration['PS_MAIL_SMTP_PORT'],
+ $isTls
+ ))
->setUsername($configuration['PS_MAIL_USER'])
->setPassword($configuration['PS_MAIL_PASSWD']);
} else {
- $connection = Swift_MailTransport::newInstance();
+ $transport = new SendmailTransport();
}
- if (!$connection) {
- return false;
- }
- $swift = Swift_Mailer::newInstance($connection);
+ $mailer = new Mailer($transport);
/* Get templates content */
$iso = Language::getIsoById((int)$id_lang);
if (!$iso) {
@@ -277,7 +304,7 @@ class MailCore extends ObjectModel
'id_lang' => (int)$id_lang
), null, true);
$template_html .= Tools::file_get_contents($template_path.$iso_template.'.html');
- $template_txt .= strip_tags(html_entity_decode(Tools::file_get_contents($template_path.$iso_template.'.txt'), null, 'utf-8'));
+ $template_txt .= strip_tags(html_entity_decode(Tools::file_get_contents($template_path.$iso_template.'.txt'), ENT_COMPAT, 'utf-8'));
Hook::exec('actionEmailAddAfterContent', array(
'template' => $template,
'template_html' => &$template_html,
@@ -300,19 +327,20 @@ class MailCore extends ObjectModel
$subject = '[' . strip_tags($configuration['PS_SHOP_NAME']) . '] ' . $subject;
}
- $message->setSubject($subject);
-
- $message->setCharset('utf-8');
+ $email->subject($subject);
/* Set Message-ID - getmypid() is blocked on some hosting */
- $message->setId(Mail::generateId());
+ $email
+ ->getHeaders()
+ ->add(new IdentificationHeader('Message-ID', Mail::generateId()))
+ ;
if (!($reply_to && Validate::isEmail($reply_to))) {
$reply_to = $from;
}
if (isset($reply_to) && $reply_to) {
- $message->setReplyTo($reply_to);
+ $email->replyTo(new Address($reply_to, (string) $reply_to_name));
}
$template_vars = array_map(array('Tools', 'htmlentitiesDecodeUTF8'), $template_vars);
@@ -328,10 +356,11 @@ class MailCore extends ObjectModel
}
}
ShopUrl::cacheMainDomainForShop((int)$id_shop);
- /* don't attach the logo as */
+ /* don't attach the logo as */
if (isset($logo)) {
- $template_vars['{shop_logo}'] = $message->embed(Swift_Image::fromPath($logo));
+ $template_vars['{shop_logo}'] = 'cid:shop_logo';
+ $email->embedFromPath($logo, 'shop_logo');
}
if ((Context::getContext()->link instanceof Link) === false) {
@@ -344,22 +373,31 @@ class MailCore extends ObjectModel
$template_vars['{guest_tracking_url}'] = Context::getContext()->link->getPageLink('guest-tracking', true, $id_lang, null, false, $id_shop);
$template_vars['{history_url}'] = Context::getContext()->link->getPageLink('history', true, $id_lang, null, false, $id_shop);
$template_vars['{color}'] = Tools::safeOutput(Configuration::get('PS_MAIL_COLOR', null, null, $id_shop));
+
// Get extra template_vars
$extra_template_vars = array();
+
Hook::exec('actionGetExtraMailTemplateVars', array(
'template' => $template,
'template_vars' => $template_vars,
'extra_template_vars' => &$extra_template_vars,
'id_lang' => (int)$id_lang
), null, true);
+
$template_vars = array_merge($template_vars, $extra_template_vars);
- $swift->registerPlugin(new Swift_Plugins_DecoratorPlugin(array($to_plugin => $template_vars)));
- if ($configuration['PS_MAIL_TYPE'] == Mail::TYPE_BOTH || $configuration['PS_MAIL_TYPE'] == Mail::TYPE_TEXT) {
- $message->addPart($template_txt, 'text/plain', 'utf-8');
- }
+
if ($configuration['PS_MAIL_TYPE'] == Mail::TYPE_BOTH || $configuration['PS_MAIL_TYPE'] == Mail::TYPE_HTML) {
- $message->addPart($template_html, 'text/html', 'utf-8');
+ $template_html = strtr($template_html, $template_vars);
+ $email->html($template_html);
+ if ($configuration['PS_MAIL_TYPE'] == Mail::TYPE_BOTH) {
+ $template_txt = strtr($template_txt, $template_vars);
+ $email->text($template_txt);
+ }
+ } else {
+ $template_txt = strtr($template_txt, $template_vars);
+ $email->text($template_txt);
}
+
if ($file_attachment && !empty($file_attachment)) {
// Multiple attachments?
if (!is_array(current($file_attachment))) {
@@ -368,24 +406,33 @@ class MailCore extends ObjectModel
foreach ($file_attachment as $attachment) {
if (isset($attachment['content']) && isset($attachment['name']) && isset($attachment['mime'])) {
- $message->attach(Swift_Attachment::newInstance()->setFilename($attachment['name'])->setContentType($attachment['mime'])->setBody($attachment['content']));
+ $email->attach($attachment['content'], $attachment['name'], $attachment['mime']);
}
}
}
/* Send mail */
- $message->setFrom(array($from => $from_name));
- $send = $swift->send($message);
+ $email->from(new Address($from, (string) $from_name));
+
+ // Hook to alter Symfony Mailer before sending mail
+ Hook::exec('actionMailAlterMessageBeforeSend', [
+ 'message' => &$message,
+ 'message' => &$email,
+ ]);
+
+ $mailer->send($email);
ShopUrl::resetMainDomainCache();
- if ($send && Configuration::get('PS_LOG_EMAILS')) {
+ if (Configuration::get('PS_LOG_EMAILS')) {
$mail = new Mail();
$mail->template = Tools::substr($template, 0, 62);
- $mail->subject = Tools::substr($subject, 0, 254);
+ $mail->subject = Tools::substr($email->getSubject(), 0, 255);
$mail->id_lang = (int)$id_lang;
- $recipients_to = $message->getTo();
- $recipients_cc = $message->getCc();
- $recipients_bcc = $message->getBcc();
+
+ $recipients_to = self::convertAdressesToArray($email->getTo());
+ $recipients_cc = self::convertAdressesToArray($email->getCc());
+ $recipients_bcc = self::convertAdressesToArray($email->getBcc());
+
if (!is_array($recipients_to)) {
$recipients_to = array();
}
@@ -395,23 +442,21 @@ class MailCore extends ObjectModel
if (!is_array($recipients_bcc)) {
$recipients_bcc = array();
}
- foreach (array_merge($recipients_to, $recipients_cc, $recipients_bcc) as $email => $recipient_name) {
- /** @var Swift_Address $recipient */
+
+ foreach (array_merge($recipients_to, $recipients_cc, $recipients_bcc) as $emailAlias => $recipientName) {
$mail->id = null;
- $mail->recipient = Tools::substr($email, 0, 126);
+ $mail->recipient = Tools::substr($emailAlias, 0, 255);
$mail->add();
}
}
- return $send;
- } catch (Swift_SwiftException $e) {
+ return true;
+ } catch (ExceptionInterface $e) {
PrestaShopLogger::addLog(
- 'Swift Error: '.$e->getMessage(),
+ 'Mailer Error: ' . $e->getMessage(),
3,
null,
- 'Swift_Message',
- null,
- true
+ 'MailerMessage'
);
return false;
@@ -451,34 +496,39 @@ class MailCore extends ObjectModel
* @param bool|string $smtp_encryption Encryption type. "off" or false disable encryption.
* @return bool|string True if succeeded, otherwise the error message
*/
- public static function sendMailTest($smtp_checked, $smtp_server, $content, $subject, $type, $to, $from, $smtp_login, $smtp_password, $smtp_port = 25, $smtp_encryption)
+ public static function sendMailTest($smtp_checked, $smtp_server, $content, $subject, $type, $to, $from, $smtp_login, $smtp_password, $smtp_port, $smtp_encryption)
{
$result = false;
try {
if ($smtp_checked) {
if (Tools::strtolower($smtp_encryption) === 'off') {
- $smtp_encryption = false;
+ $isTls = false;
+ } else {
+ $isTls = true;
}
- $smtp = Swift_SmtpTransport::newInstance($smtp_server, $smtp_port, $smtp_encryption)
+ $transport = (new EsmtpTransport(
+ $smtp_server,
+ $smtp_port,
+ $isTls
+ ))
->setUsername($smtp_login)
- ->setPassword($smtp_password);
- $swift = Swift_Mailer::newInstance($smtp);
+ ->setPassword($smtp_password)
+ ;
} else {
- $swift = Swift_Mailer::newInstance(Swift_MailTransport::newInstance());
+ $transport = new SendmailTransport();
}
- $message = Swift_Message::newInstance();
+ $mailer = new Mailer($transport);
+ $email = (new Email())
+ ->from($from)
+ ->to($to)
+ ->subject($subject)
+ ->text($content)
+ ;
- $message
- ->setFrom($from)
- ->setTo($to)
- ->setSubject($subject)
- ->setBody($content);
-
- if ($swift->send($message)) {
- $result = true;
- }
- } catch (Swift_SwiftException $e) {
+ $mailer->send($signedEmail ?? $email);
+ $result = true;
+ } catch (ExceptionInterface $e) {
$result = $e->getMessage();
}
@@ -493,7 +543,7 @@ class MailCore extends ObjectModel
* @param string $string raw sentence (write directly in file)
* @return mixed
*/
- public static function l($string, $id_lang = null, Context $context = null)
+ public static function l($string, $id_lang = null, ?Context $context = null)
{
global $_LANGMAIL;
@@ -523,15 +573,15 @@ class MailCore extends ObjectModel
return str_replace('"', '"', Tools::stripslashes((array_key_exists($key, $_LANGMAIL) && !empty($_LANGMAIL[$key])) ? $_LANGMAIL[$key] : $string));
}
- /* Rewrite of Swift_Message::generateId() without getmypid() */
+ /* Generate a Message-ID */
protected static function generateId($idstring = null)
{
- $midparams = array(
- 'utctime' => gmstrftime('%Y%m%d%H%M%S'),
+ $midparams = [
+ 'utctime' => date('YmdHis'),
'randint' => mt_rand(),
- 'customstr' => (preg_match("/^(? ((isset($_SERVER['SERVER_NAME']) && !empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : php_uname('n')),
- );
+ 'customstr' => ($idstring !== null && preg_match('/^(? !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : php_uname('n'),
+ ];
return vsprintf("%s.%d.%s@%s", $midparams);
}
@@ -624,4 +674,20 @@ class MailCore extends ObjectModel
return '';
}
-}
+
+ /**
+ * @param Address[] $addresses
+ *
+ * @return arrayl('This email address will be your username to access your website\'s back office.') ?>
@@ -151,7 +151,7 @@ var default_iso = 'session->shop_country ?>';+ * This attribute is only available from the Insights web service and the + * GeoIP2 Enterprise database. + *
+ */ + public readonly ?string $userType; + + /** + * @ignore + * + * @param array+ If set to true, blank nodes will be removed. This can be useful for maintaining + backwards compatibility when upgrading from previous versions of PHP. +
+--# vim: et sw=4 sts=4 diff --git a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php b/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/ConfigSchema/schema/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Decorator/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php index b82c6bb20..bfad967fb 100644 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php +++ b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php @@ -287,13 +287,14 @@ class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCac } elseif (filegroup($dir) === posix_getgid()) { $chmod = $chmod | 0070; } else { - // PHP's probably running as nobody, so we'll - // need to give global permissions - $chmod = $chmod | 0777; + // PHP's probably running as nobody, it is + // not obvious how to fix this (777 is probably + // bad if you are multi-user), let the user figure it out + $chmod = null; } trigger_error( - 'Directory ' . $dir . ' not writable, ' . - 'please chmod to ' . decoct($chmod), + 'Directory ' . $dir . ' not writable. ' . + ($chmod === null ? '' : 'Please chmod to ' . decoct($chmod)), E_USER_WARNING ); } else { diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCache/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php b/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php index fd1cc9be4..3a0f4616a 100644 --- a/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php +++ b/tools/htmlpurifier/HTMLPurifier/DefinitionCacheFactory.php @@ -71,7 +71,7 @@ class HTMLPurifier_DefinitionCacheFactory return $this->caches[$method][$type]; } if (isset($this->implementations[$method]) && - class_exists($class = $this->implementations[$method], false)) { + class_exists($class = $this->implementations[$method])) { $cache = new $class($type); } else { if ($method != 'Serializer') { diff --git a/tools/htmlpurifier/HTMLPurifier/ElementDef.php b/tools/htmlpurifier/HTMLPurifier/ElementDef.php index d5311cedc..57cfd2bb0 100644 --- a/tools/htmlpurifier/HTMLPurifier/ElementDef.php +++ b/tools/htmlpurifier/HTMLPurifier/ElementDef.php @@ -176,7 +176,7 @@ class HTMLPurifier_ElementDef if (!empty($def->content_model)) { $this->content_model = - str_replace("#SUPER", $this->content_model, $def->content_model); + str_replace("#SUPER", (string)$this->content_model, $def->content_model); $this->child = false; } if (!empty($def->content_model_type)) { diff --git a/tools/htmlpurifier/HTMLPurifier/Encoder.php b/tools/htmlpurifier/HTMLPurifier/Encoder.php index 40a24266a..d4791cc1b 100644 --- a/tools/htmlpurifier/HTMLPurifier/Encoder.php +++ b/tools/htmlpurifier/HTMLPurifier/Encoder.php @@ -398,8 +398,8 @@ class HTMLPurifier_Encoder // characters to their true byte-wise ASCII/UTF-8 equivalents. $str = strtr($str, self::testEncodingSupportsASCII($encoding)); return $str; - } elseif ($encoding === 'iso-8859-1') { - $str = utf8_encode($str); + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1'); return $str; } $bug = HTMLPurifier_Encoder::testIconvTruncateBug(); @@ -450,8 +450,8 @@ class HTMLPurifier_Encoder // Normal stuff $str = self::iconv('utf-8', $encoding . '//IGNORE', $str); return $str; - } elseif ($encoding === 'iso-8859-1') { - $str = utf8_decode($str); + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8'); return $str; } trigger_error('Encoding not supported', E_USER_ERROR); diff --git a/tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php b/tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/EntityLookup/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/EntityParser.php b/tools/htmlpurifier/HTMLPurifier/EntityParser.php index 3ef2d09ec..0f2b83dc8 100644 --- a/tools/htmlpurifier/HTMLPurifier/EntityParser.php +++ b/tools/htmlpurifier/HTMLPurifier/EntityParser.php @@ -116,8 +116,8 @@ class HTMLPurifier_EntityParser protected function entityCallback($matches) { $entity = $matches[0]; - $hex_part = @$matches[1]; - $dec_part = @$matches[2]; + $hex_part = isset($matches[1]) ? $matches[1] : null; + $dec_part = isset($matches[2]) ? $matches[2] : null; $named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3]; if ($hex_part !== NULL && $hex_part !== "") { return HTMLPurifier_Encoder::unichr(hexdec($hex_part)); diff --git a/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php b/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php index 66f70b0fc..e7e3cac1a 100644 --- a/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php +++ b/tools/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -54,6 +54,11 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter */ private $_enum_attrdef; + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_universal_attrdef; + public function __construct() { $this->_tidy = new csstidy(); @@ -70,6 +75,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter 'focus' ) ); + $this->_universal_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'initial', + 'inherit', + 'unset', + ) + ); } /** @@ -146,175 +158,184 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter foreach ($this->_tidy->css as $k => $decls) { // $decls are all CSS declarations inside an @ selector $new_decls = array(); - foreach ($decls as $selector => $style) { - $selector = trim($selector); - if ($selector === '') { - continue; - } // should not happen - // Parse the selector - // Here is the relevant part of the CSS grammar: - // - // ruleset - // : selector [ ',' S* selector ]* '{' ... - // selector - // : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]? - // combinator - // : '+' S* - // : '>' S* - // simple_selector - // : element_name [ HASH | class | attrib | pseudo ]* - // | [ HASH | class | attrib | pseudo ]+ - // element_name - // : IDENT | '*' - // ; - // class - // : '.' IDENT - // ; - // attrib - // : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* - // [ IDENT | STRING ] S* ]? ']' - // ; - // pseudo - // : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ] - // ; - // - // For reference, here are the relevant tokens: - // - // HASH #{name} - // IDENT {ident} - // INCLUDES == - // DASHMATCH |= - // STRING {string} - // FUNCTION {ident}\( - // - // And the lexical scanner tokens - // - // name {nmchar}+ - // nmchar [_a-z0-9-]|{nonascii}|{escape} - // nonascii [\240-\377] - // escape {unicode}|\\[^\r\n\f0-9a-f] - // unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])? - // ident -?{nmstart}{nmchar*} - // nmstart [_a-z]|{nonascii}|{escape} - // string {string1}|{string2} - // string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" - // string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\' - // - // We'll implement a subset (in order to reduce attack - // surface); in particular: - // - // - No Unicode support - // - No escapes support - // - No string support (by proxy no attrib support) - // - element_name is matched against allowed - // elements (some people might find this - // annoying...) - // - Pseudo-elements one of :first-child, :link, - // :visited, :active, :hover, :focus + if (is_array($decls)) { + foreach ($decls as $selector => $style) { + $selector = trim($selector); + if ($selector === '') { + continue; + } // should not happen + // Parse the selector + // Here is the relevant part of the CSS grammar: + // + // ruleset + // : selector [ ',' S* selector ]* '{' ... + // selector + // : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]? + // combinator + // : '+' S* + // : '>' S* + // simple_selector + // : element_name [ HASH | class | attrib | pseudo ]* + // | [ HASH | class | attrib | pseudo ]+ + // element_name + // : IDENT | '*' + // ; + // class + // : '.' IDENT + // ; + // attrib + // : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S* + // [ IDENT | STRING ] S* ]? ']' + // ; + // pseudo + // : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ] + // ; + // + // For reference, here are the relevant tokens: + // + // HASH #{name} + // IDENT {ident} + // INCLUDES == + // DASHMATCH |= + // STRING {string} + // FUNCTION {ident}\( + // + // And the lexical scanner tokens + // + // name {nmchar}+ + // nmchar [_a-z0-9-]|{nonascii}|{escape} + // nonascii [\240-\377] + // escape {unicode}|\\[^\r\n\f0-9a-f] + // unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])? + // ident -?{nmstart}{nmchar*} + // nmstart [_a-z]|{nonascii}|{escape} + // string {string1}|{string2} + // string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" + // string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\' + // + // We'll implement a subset (in order to reduce attack + // surface); in particular: + // + // - No Unicode support + // - No escapes support + // - No string support (by proxy no attrib support) + // - element_name is matched against allowed + // elements (some people might find this + // annoying...) + // - Pseudo-elements one of :first-child, :link, + // :visited, :active, :hover, :focus - // handle ruleset - $selectors = array_map('trim', explode(',', $selector)); - $new_selectors = array(); - foreach ($selectors as $sel) { - // split on +, > and spaces - $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE); - // even indices are chunks, odd indices are - // delimiters - $nsel = null; - $delim = null; // guaranteed to be non-null after - // two loop iterations - for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) { - $x = $basic_selectors[$i]; - if ($i % 2) { - // delimiter - if ($x === ' ') { - $delim = ' '; - } else { - $delim = ' ' . $x . ' '; - } - } else { - // simple selector - $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE); - $sdelim = null; - $nx = null; - for ($j = 0, $cc = count($components); $j < $cc; $j++) { - $y = $components[$j]; - if ($j === 0) { - if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) { - $nx = $y; - } else { - // $nx stays null; this matters - // if we don't manage to find - // any valid selector content, - // in which case we ignore the - // outer $delim - } - } elseif ($j % 2) { - // set delimiter - $sdelim = $y; + // handle ruleset + $selectors = array_map('trim', explode(',', $selector)); + $new_selectors = array(); + foreach ($selectors as $sel) { + // split on +, > and spaces + $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE); + // even indices are chunks, odd indices are + // delimiters + $nsel = null; + $delim = null; // guaranteed to be non-null after + // two loop iterations + for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) { + $x = $basic_selectors[$i]; + if ($i % 2) { + // delimiter + if ($x === ' ') { + $delim = ' '; } else { - $attrdef = null; - if ($sdelim === '#') { - $attrdef = $this->_id_attrdef; - } elseif ($sdelim === '.') { - $attrdef = $this->_class_attrdef; - } elseif ($sdelim === ':') { - $attrdef = $this->_enum_attrdef; - } else { - throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split'); - } - $r = $attrdef->validate($y, $config, $context); - if ($r !== false) { - if ($r !== true) { - $y = $r; - } - if ($nx === null) { - $nx = ''; - } - $nx .= $sdelim . $y; - } - } - } - if ($nx !== null) { - if ($nsel === null) { - $nsel = $nx; - } else { - $nsel .= $delim . $nx; + $delim = ' ' . $x . ' '; } } else { - // delimiters to the left of invalid - // basic selector ignored + // simple selector + $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE); + $sdelim = null; + $nx = null; + for ($j = 0, $cc = count($components); $j < $cc; $j++) { + $y = $components[$j]; + if ($j === 0) { + if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) { + $nx = $y; + } else { + // $nx stays null; this matters + // if we don't manage to find + // any valid selector content, + // in which case we ignore the + // outer $delim + } + } elseif ($j % 2) { + // set delimiter + $sdelim = $y; + } else { + $attrdef = null; + if ($sdelim === '#') { + $attrdef = $this->_id_attrdef; + } elseif ($sdelim === '.') { + $attrdef = $this->_class_attrdef; + } elseif ($sdelim === ':') { + $attrdef = $this->_enum_attrdef; + } else { + throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split'); + } + $r = $attrdef->validate($y, $config, $context); + if ($r !== false) { + if ($r !== true) { + $y = $r; + } + if ($nx === null) { + $nx = ''; + } + $nx .= $sdelim . $y; + } + } + } + if ($nx !== null) { + if ($nsel === null) { + $nsel = $nx; + } else { + $nsel .= $delim . $nx; + } + } else { + // delimiters to the left of invalid + // basic selector ignored + } + } + } + if ($nsel !== null) { + if (!empty($scopes)) { + foreach ($scopes as $s) { + $new_selectors[] = "$s $nsel"; + } + } else { + $new_selectors[] = $nsel; } } } - if ($nsel !== null) { - if (!empty($scopes)) { - foreach ($scopes as $s) { - $new_selectors[] = "$s $nsel"; - } - } else { - $new_selectors[] = $nsel; - } - } - } - if (empty($new_selectors)) { - continue; - } - $selector = implode(', ', $new_selectors); - foreach ($style as $name => $value) { - if (!isset($css_definition->info[$name])) { - unset($style[$name]); + if (empty($new_selectors)) { continue; } - $def = $css_definition->info[$name]; - $ret = $def->validate($value, $config, $context); - if ($ret === false) { - unset($style[$name]); - } else { - $style[$name] = $ret; + $selector = implode(', ', $new_selectors); + foreach ($style as $name => $value) { + if (!isset($css_definition->info[$name])) { + unset($style[$name]); + continue; + } + $uni_ret = $this->_universal_attrdef->validate($value, $config, $context); + if ($uni_ret !== false) { + $style[$name] = $uni_ret; + continue; + } + $def = $css_definition->info[$name]; + $ret = $def->validate($value, $config, $context); + if ($ret === false) { + unset($style[$name]); + } else { + $style[$name] = $ret; + } } + $new_decls[$selector] = $style; } - $new_decls[$selector] = $style; + } else { + continue; } $new_css[$k] = $new_decls; } diff --git a/tools/htmlpurifier/HTMLPurifier/Filter/index.php b/tools/htmlpurifier/HTMLPurifier/Filter/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Filter/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule.php index 6d898f80c..9dbb98729 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule.php @@ -257,8 +257,9 @@ class HTMLPurifier_HTMLModule */ public function makeLookup($list) { + $args = func_get_args(); if (is_string($list)) { - $list = func_get_args(); + $list = $args; } $ret = array(); foreach ($list as $value) { diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php index a96ab1bef..7220c14cc 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -17,6 +17,7 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule 'class' => 'Class', 'id' => 'ID', 'title' => 'CDATA', + 'contenteditable' => 'ContentEditable', ), 'Lang' => array(), 'I18N' => array( diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php index f7e7c91c0..71dfc7744 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Iframe.php @@ -28,22 +28,28 @@ class HTMLPurifier_HTMLModule_Iframe extends HTMLPurifier_HTMLModule if ($config->get('HTML.SafeIframe')) { $this->safe = true; } + $attrs = array( + 'src' => 'URI#embedded', + 'width' => 'Length', + 'height' => 'Length', + 'name' => 'ID', + 'scrolling' => 'Enum#yes,no,auto', + 'frameborder' => 'Enum#0,1', + 'longdesc' => 'URI', + 'marginheight' => 'Pixels', + 'marginwidth' => 'Pixels', + ); + + if ($config->get('HTML.Trusted')) { + $attrs['allowfullscreen'] = 'Bool#allowfullscreen'; + } + $this->addElement( 'iframe', 'Inline', 'Flow', 'Common', - array( - 'src' => 'URI#embedded', - 'width' => 'Length', - 'height' => 'Length', - 'name' => 'ID', - 'scrolling' => 'Enum#yes,no,auto', - 'frameborder' => 'Enum#0,1', - 'longdesc' => 'URI', - 'marginheight' => 'Pixels', - 'marginwidth' => 'Pixels', - ) + $attrs ); } } diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php index 08aa23247..76fd93a6c 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy.php @@ -146,10 +146,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule $type = "info_$type"; $e = $this; } - // PHP does some weird parsing when I do - // $e->$type[$attr], so I have to assign a ref. - $f =& $e->$type; - $f[$attr] = $fix; + $e->{$type}[$attr] = $fix; break; case 'tag_transform': $this->info_tag_transform[$params['element']] = $fix; @@ -224,6 +221,7 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule */ public function makeFixes() { + return array(); } } diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php index 700a25dbc..9ee3ffcc9 100644 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php +++ b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php @@ -168,9 +168,11 @@ class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule // @vspace for img ------------------------------------------------ $r['img@vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace'); - // @width for hr, td, th ------------------------------------------ + // @width for table, hr, td, th, col ------------------------------------------ + $r['table@width'] = $r['td@width'] = $r['th@width'] = + $r['col@width'] = $r['hr@width'] = new HTMLPurifier_AttrTransform_Length('width'); return $r; diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/Tidy/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php b/tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/HTMLModule/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php b/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php index 74f83eaa7..3b6d70f6e 100644 --- a/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php +++ b/tools/htmlpurifier/HTMLPurifier/Injector/Linkify.php @@ -40,6 +40,9 @@ class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector '/\\b((?:[a-z][\\w\\-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()<>]|\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\))+(?:\\((?:[^\\s()<>]|(?:\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'".,<>?\x{00ab}\x{00bb}\x{201c}\x{201d}\x{2018}\x{2019}]))/iu', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE); + if ($bits === false) { + return; + } $token = array(); diff --git a/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php index 9ee7aa84d..42d514447 100644 --- a/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php +++ b/tools/htmlpurifier/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php @@ -31,6 +31,16 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In */ private $context; + /** + * @type SplObjectStorage + */ + private $markForDeletion; + + public function __construct() + { + $this->markForDeletion = new SplObjectStorage(); + } + public function prepare($config, $context) { $this->attrValidator = new HTMLPurifier_AttrValidator(); @@ -64,7 +74,7 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In if ($current instanceof HTMLPurifier_Token_End && $current->name === 'span') { // Mark closing span tag for deletion - $current->markForDeletion = true; + $this->markForDeletion->attach($current); // Delete open span tag $token = false; } @@ -75,7 +85,8 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In */ public function handleEnd(&$token) { - if ($token->markForDeletion) { + if ($this->markForDeletion->contains($token)) { + $this->markForDeletion->detach($token); $token = false; } } diff --git a/tools/htmlpurifier/HTMLPurifier/Injector/index.php b/tools/htmlpurifier/HTMLPurifier/Injector/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Injector/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Language/index.php b/tools/htmlpurifier/HTMLPurifier/Language/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Language/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Language/messages/index.php b/tools/htmlpurifier/HTMLPurifier/Language/messages/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Language/messages/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php b/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php index 4e35272d8..16a4f6932 100644 --- a/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php +++ b/tools/htmlpurifier/HTMLPurifier/LanguageFactory.php @@ -109,7 +109,7 @@ class HTMLPurifier_LanguageFactory } else { $class = 'HTMLPurifier_Language_' . $pcode; $file = $this->dir . '/Language/classes/' . $code . '.php'; - if (file_exists($file) || class_exists($class, false)) { + if (file_exists($file) || class_exists($class)) { $lang = new $class($config, $context); } else { // Go fallback diff --git a/tools/htmlpurifier/HTMLPurifier/Length.php b/tools/htmlpurifier/HTMLPurifier/Length.php index e70da55a9..b6ea12345 100644 --- a/tools/htmlpurifier/HTMLPurifier/Length.php +++ b/tools/htmlpurifier/HTMLPurifier/Length.php @@ -78,7 +78,7 @@ class HTMLPurifier_Length if ($this->n === '0' && $this->unit === false) { return true; } - if (!ctype_lower($this->unit)) { + if ($this->unit === false || !ctype_lower($this->unit)) { $this->unit = strtolower($this->unit); } if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) { diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer.php b/tools/htmlpurifier/HTMLPurifier/Lexer.php index e9da3ed5e..fe87fa4ba 100644 --- a/tools/htmlpurifier/HTMLPurifier/Lexer.php +++ b/tools/htmlpurifier/HTMLPurifier/Lexer.php @@ -48,6 +48,11 @@ class HTMLPurifier_Lexer */ public $tracksLineNumbers = false; + /** + * @type HTMLPurifier_EntityParser + */ + private $_entity_parser; + // -- STATIC ---------------------------------------------------------- /** @@ -96,7 +101,7 @@ class HTMLPurifier_Lexer break; } - if (class_exists('DOMDocument', false) && + if (class_exists('DOMDocument') && method_exists('DOMDocument', 'loadHTML') && !extension_loaded('domxml') ) { @@ -264,20 +269,6 @@ class HTMLPurifier_Lexer ); } - /** - * Special Internet Explorer conditional comments should be removed. - * @param string $string HTML string to process. - * @return string HTML with conditional comments removed. - */ - protected static function removeIEConditional($string) - { - return preg_replace( - '##si', // probably should generalize for all strings - '', - $string - ); - } - /** * Callback function for escapeCDATA() that does the work. * @@ -306,8 +297,8 @@ class HTMLPurifier_Lexer { // normalize newlines to \n if ($config->get('Core.NormalizeNewlines')) { - $html = str_replace("\r\n", "\n", $html); - $html = str_replace("\r", "\n", $html); + $html = str_replace("\r\n", "\n", (string)$html); + $html = str_replace("\r", "\n", (string)$html); } if ($config->get('HTML.Trusted')) { @@ -318,8 +309,6 @@ class HTMLPurifier_Lexer // escape CDATA $html = $this->escapeCDATA($html); - $html = $this->removeIEConditional($html); - // extract body from document if applicable if ($config->get('Core.ConvertDocumentToFragment')) { $e = false; diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php b/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php index ca5f25b84..7d579837c 100644 --- a/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php +++ b/tools/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php @@ -72,6 +72,9 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) { $options |= LIBXML_PARSEHUGE; } + if ($config->get('Core.RemoveBlanks') && defined('LIBXML_NOBLANKS')) { + $options |= LIBXML_NOBLANKS; + } set_error_handler(array($this, 'muteErrorHandler')); // loadHTML() fails on PHP 5.3 when second parameter is given @@ -104,7 +107,6 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer * To iterate is human, to recurse divine - L. Peter Deutsch * @param DOMNode $node DOMNode to be tokenized. * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. - * @return HTMLPurifier_Token of node appended to previously passed tokens. */ protected function tokenizeDOM($node, &$tokens, $config) { diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php b/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php index 72476ddf3..1564f283d 100644 --- a/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php +++ b/tools/htmlpurifier/HTMLPurifier/Lexer/PH5P.php @@ -4410,7 +4410,7 @@ class HTML5TreeConstructer foreach ($token['attr'] as $attr) { if (!$el->hasAttribute($attr['name'])) { - $el->setAttribute($attr['name'], $attr['value']); + $el->setAttribute($attr['name'], (string)$attr['value']); } } diff --git a/tools/htmlpurifier/HTMLPurifier/Lexer/index.php b/tools/htmlpurifier/HTMLPurifier/Lexer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Lexer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Node/index.php b/tools/htmlpurifier/HTMLPurifier/Node/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Node/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php b/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php index 33ae11397..4c3ce1758 100644 --- a/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php +++ b/tools/htmlpurifier/HTMLPurifier/Printer/ConfigForm.php @@ -32,6 +32,11 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer */ protected $compress = false; + /** + * @var HTMLPurifier_Config + */ + protected $genConfig; + /** * @param string $name Form element name for directives to be stuffed into * @param string $doc_url String documentation URL, will have fragment tagged on diff --git a/tools/htmlpurifier/HTMLPurifier/Printer/index.php b/tools/htmlpurifier/HTMLPurifier/Printer/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Printer/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php b/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php index 15b330ea3..f68fc8c30 100644 --- a/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php +++ b/tools/htmlpurifier/HTMLPurifier/PropertyListIterator.php @@ -29,6 +29,7 @@ class HTMLPurifier_PropertyListIterator extends FilterIterator /** * @return bool */ + #[\ReturnTypeWillChange] public function accept() { $key = $this->getInnerIterator()->key(); diff --git a/tools/htmlpurifier/HTMLPurifier/Strategy/index.php b/tools/htmlpurifier/HTMLPurifier/Strategy/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Strategy/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/StringHash.php b/tools/htmlpurifier/HTMLPurifier/StringHash.php index c07370197..c41ae3a76 100644 --- a/tools/htmlpurifier/HTMLPurifier/StringHash.php +++ b/tools/htmlpurifier/HTMLPurifier/StringHash.php @@ -20,6 +20,7 @@ class HTMLPurifier_StringHash extends ArrayObject * @param mixed $index * @return mixed */ + #[\ReturnTypeWillChange] public function offsetGet($index) { $this->accessed[$index] = true; diff --git a/tools/htmlpurifier/HTMLPurifier/TagTransform/index.php b/tools/htmlpurifier/HTMLPurifier/TagTransform/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/TagTransform/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/Token/Tag.php b/tools/htmlpurifier/HTMLPurifier/Token/Tag.php index d643fa64e..dcf365589 100644 --- a/tools/htmlpurifier/HTMLPurifier/Token/Tag.php +++ b/tools/htmlpurifier/HTMLPurifier/Token/Tag.php @@ -44,7 +44,7 @@ abstract class HTMLPurifier_Token_Tag extends HTMLPurifier_Token $this->name = ctype_lower($name) ? $name : strtolower($name); foreach ($attr as $key => $value) { // normalization only necessary when key is not lowercase - if (!ctype_lower($key)) { + if (!ctype_lower((string)$key)) { $new_key = strtolower($key); if (!isset($attr[$new_key])) { $attr[$new_key] = $attr[$key]; diff --git a/tools/htmlpurifier/HTMLPurifier/Token/index.php b/tools/htmlpurifier/HTMLPurifier/Token/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/Token/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php b/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php index a6645c17e..32197c0e6 100644 --- a/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php +++ b/tools/htmlpurifier/HTMLPurifier/URIFilter/HostBlacklist.php @@ -35,7 +35,7 @@ class HTMLPurifier_URIFilter_HostBlacklist extends HTMLPurifier_URIFilter public function filter(&$uri, $config, $context) { foreach ($this->blacklist as $blacklisted_host_fragment) { - if (strpos($uri->host, $blacklisted_host_fragment) !== false) { + if ($uri->host !== null && strpos($uri->host, $blacklisted_host_fragment) !== false) { return false; } } diff --git a/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php b/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php index 6e03315a1..e1393deb7 100644 --- a/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php +++ b/tools/htmlpurifier/HTMLPurifier/URIFilter/Munge.php @@ -100,11 +100,11 @@ class HTMLPurifier_URIFilter_Munge extends HTMLPurifier_URIFilter $string = $uri->toString(); // always available $this->replace['%s'] = $string; - $this->replace['%r'] = $context->get('EmbeddedURI', true); - $token = $context->get('CurrentToken', true); - $this->replace['%n'] = $token ? $token->name : null; - $this->replace['%m'] = $context->get('CurrentAttr', true); - $this->replace['%p'] = $context->get('CurrentCSSProperty', true); + $this->replace['%r'] = $context->get('EmbeddedURI', true) ?: ''; + $token = $context->get('CurrentToken', true) ?: ''; + $this->replace['%n'] = $token ? $token->name : ''; + $this->replace['%m'] = $context->get('CurrentAttr', true) ?: ''; + $this->replace['%p'] = $context->get('CurrentCSSProperty', true) ?: ''; // not always available if ($this->secretKey) { $this->replace['%t'] = hash_hmac("sha256", $string, $this->secretKey); diff --git a/tools/htmlpurifier/HTMLPurifier/URIFilter/index.php b/tools/htmlpurifier/HTMLPurifier/URIFilter/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/URIFilter/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/URIScheme/index.php b/tools/htmlpurifier/HTMLPurifier/URIScheme/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/URIScheme/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php b/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php index 8cd193352..dfad8efcf 100644 --- a/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php +++ b/tools/htmlpurifier/HTMLPurifier/URIScheme/tel.php @@ -33,11 +33,11 @@ class HTMLPurifier_URIScheme_tel extends HTMLPurifier_URIScheme $uri->host = null; $uri->port = null; - // Delete all non-numeric characters, non-x characters + // Delete all non-numeric characters, commas, and non-x characters // from phone number, EXCEPT for a leading plus sign. - $uri->path = preg_replace('/(?!^\+)[^\dx]/', '', + $uri->path = preg_replace('/(?!^\+)[^\dx,]/', '', // Normalize e(x)tension to lower-case - str_replace('X', 'x', $uri->path)); + str_replace('X', 'x', rawurldecode($uri->path))); return true; } diff --git a/tools/htmlpurifier/HTMLPurifier/UnitConverter.php b/tools/htmlpurifier/HTMLPurifier/UnitConverter.php index 166f3bf30..b5a1eab5c 100644 --- a/tools/htmlpurifier/HTMLPurifier/UnitConverter.php +++ b/tools/htmlpurifier/HTMLPurifier/UnitConverter.php @@ -261,7 +261,7 @@ class HTMLPurifier_UnitConverter */ private function round($n, $sigfigs) { - $new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1 + $new_log = (int)floor(log(abs((float)$n), 10)); // Number of digits left of decimal - 1 $rp = $sigfigs - $new_log - 1; // Number of decimal places needed $neg = $n < 0 ? '-' : ''; // Negative sign if ($this->bcmath) { @@ -276,7 +276,7 @@ class HTMLPurifier_UnitConverter } return $n; } else { - return $this->scale(round($n, $sigfigs - $new_log - 1), $rp + 1); + return $this->scale(round((float)$n, $sigfigs - $new_log - 1), $rp + 1); } } @@ -300,7 +300,7 @@ class HTMLPurifier_UnitConverter // Now we return it, truncating the zero that was rounded off. return substr($precise, 0, -1) . str_repeat('0', -$scale + 1); } - return sprintf('%.' . $scale . 'f', (float)$r); + return number_format((float)$r, $scale, '.', ''); } } diff --git a/tools/htmlpurifier/HTMLPurifier/VarParser/index.php b/tools/htmlpurifier/HTMLPurifier/VarParser/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/VarParser/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/HTMLPurifier/index.php b/tools/htmlpurifier/HTMLPurifier/index.php deleted file mode 100644 index 051e0122d..000000000 --- a/tools/htmlpurifier/HTMLPurifier/index.php +++ /dev/null @@ -1,29 +0,0 @@ - -* @copyright 2010-2021 Webkul IN -* @license https://store.webkul.com/license.html -*/ - -header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); -header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - -header('Cache-Control: no-store, no-cache, must-revalidate'); -header('Cache-Control: post-check=0, pre-check=0', false); -header('Pragma: no-cache'); - -header('Location: ../../../'); -exit; diff --git a/tools/htmlpurifier/LICENSE b/tools/htmlpurifier/LICENSE deleted file mode 100644 index 8c88a20d4..000000000 --- a/tools/htmlpurifier/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - -"asd" + ++x; */
+ $lock = '"LOCK---' . crc32(time()) . '"';
- /**
- * @return string
- */
- protected function singleLineComment()
- {
- $comment = '';
- while (true) {
- $get = $this->get();
- $comment .= $get;
- if (ord($get) <= self::ORD_LF) { // EOL reached
- // if IE conditional comment
- if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
- return "/{$comment}";
- }
- return $get;
- }
+ $matches = [];
+ preg_match('/([+-])(\s+)([+-])/S', $js, $matches);
+ if (empty($matches)) {
+ return $js;
}
+
+ $this->locks[$lock] = $matches[2];
+
+ $js = preg_replace('/([+-])\s+([+-])/S', "$1{$lock}$2", $js);
+ /* -- */
+
+ return $js;
}
/**
- * @return string
- * @throws JSMin_UnterminatedCommentException
- */
- protected function multipleLineComment()
- {
- $this->get();
- $comment = '';
- while (true) {
- $get = $this->get();
- if ($get === '*') {
- if ($this->peek() === '/') { // end of comment reached
- $this->get();
- // if comment preserved by YUI Compressor
- if (0 === strpos($comment, '!')) {
- return "\n/*!" . substr($comment, 1) . "*/\n";
- }
- // if IE conditional comment
- if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
- return "/*{$comment}*/";
- }
- return ' ';
- }
- } elseif ($get === null) {
- throw new JSMin_UnterminatedCommentException(
- "JSMin: Unterminated comment at byte "
- . $this->inputIndex . ": /*{$comment}");
- }
- $comment .= $get;
- }
- }
-
- /**
- * Get the next character, skipping over comments.
- * Some comments may be preserved.
+ * Replace "locks" with the original characters
*
- * @return string
+ * @param string $js The string to unlock
+ * @return bool
*/
- protected function next()
+ protected function unlock($js)
{
- $get = $this->get();
- if ($get !== '/') {
- return $get;
+ if (empty($this->locks)) {
+ return $js;
}
- switch ($this->peek()) {
- case '/': return $this->singleLineComment();
- case '*': return $this->multipleLineComment();
- default: return $get;
- }
- }
-}
-class JSMin_UnterminatedStringException extends Exception {}
-class JSMin_UnterminatedCommentException extends Exception {}
-class JSMin_UnterminatedRegExpException extends Exception {}
+ foreach ($this->locks as $lock => $replacement) {
+ $js = str_replace($lock, $replacement, $js);
+ }
+
+ return $js;
+ }
+}
\ No newline at end of file
diff --git a/tools/mailer/autoload.php b/tools/mailer/autoload.php
new file mode 100644
index 000000000..bec346a85
--- /dev/null
+++ b/tools/mailer/autoload.php
@@ -0,0 +1,7 @@
+
+ * Jordi Boggiano
+ */
+ function trigger_deprecation(string $package, string $version, string $message, mixed ...$args): void
+ {
+ @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED);
+ }
+}
diff --git a/tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md b/tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md
new file mode 100644
index 000000000..7932e2613
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher-contracts/CHANGELOG.md
@@ -0,0 +1,5 @@
+CHANGELOG
+=========
+
+The changelog is maintained for all Symfony contracts at the following URL:
+https://github.com/symfony/contracts/blob/main/CHANGELOG.md
diff --git a/tools/mailer/symfony/event-dispatcher-contracts/Event.php b/tools/mailer/symfony/event-dispatcher-contracts/Event.php
new file mode 100644
index 000000000..2e7f99890
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher-contracts/Event.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\EventDispatcher;
+
+use Psr\EventDispatcher\StoppableEventInterface;
+
+/**
+ * Event is the base class for classes containing event data.
+ *
+ * This class contains no event data. It is used by events that do not pass
+ * state information to an event handler when an event is raised.
+ *
+ * You can call the method stopPropagation() to abort the execution of
+ * further listeners in your event listener.
+ *
+ * @author Guilherme Blanco
+ */
+class Event implements StoppableEventInterface
+{
+ private bool $propagationStopped = false;
+
+ public function isPropagationStopped(): bool
+ {
+ return $this->propagationStopped;
+ }
+
+ /**
+ * Stops the propagation of the event to further event listeners.
+ *
+ * If multiple event listeners are connected to the same event, no
+ * further event listener will be triggered once any trigger calls
+ * stopPropagation().
+ */
+ public function stopPropagation(): void
+ {
+ $this->propagationStopped = true;
+ }
+}
diff --git a/tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php b/tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php
new file mode 100644
index 000000000..2d7840d32
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher-contracts/EventDispatcherInterface.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Contracts\EventDispatcher;
+
+use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;
+
+/**
+ * Allows providing hooks on domain-specific lifecycles by dispatching events.
+ */
+interface EventDispatcherInterface extends PsrEventDispatcherInterface
+{
+ /**
+ * Dispatches an event to all registered listeners.
+ *
+ * @template T of object
+ *
+ * @param T $event The event to pass to the event handlers/listeners
+ * @param string|null $eventName The name of the event to dispatch. If not supplied,
+ * the class of $event should be used instead.
+ *
+ * @return T The passed $event MUST be returned
+ */
+ public function dispatch(object $event, ?string $eventName = null): object;
+}
diff --git a/tools/mailer/symfony/event-dispatcher-contracts/LICENSE b/tools/mailer/symfony/event-dispatcher-contracts/LICENSE
new file mode 100644
index 000000000..7536caeae
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher-contracts/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018-present Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/tools/mailer/symfony/event-dispatcher-contracts/README.md b/tools/mailer/symfony/event-dispatcher-contracts/README.md
new file mode 100644
index 000000000..332b961cb
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher-contracts/README.md
@@ -0,0 +1,9 @@
+Symfony EventDispatcher Contracts
+=================================
+
+A set of abstractions extracted out of the Symfony components.
+
+Can be used to build on semantics that the Symfony components proved useful and
+that already have battle tested implementations.
+
+See https://github.com/symfony/contracts/blob/main/README.md for more information.
diff --git a/tools/mailer/symfony/event-dispatcher-contracts/composer.json b/tools/mailer/symfony/event-dispatcher-contracts/composer.json
new file mode 100644
index 000000000..35956eb80
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher-contracts/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "symfony/event-dispatcher-contracts",
+ "type": "library",
+ "description": "Generic abstractions related to dispatching event",
+ "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=8.1",
+ "psr/event-dispatcher": "^1"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" }
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.5-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ }
+}
diff --git a/tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php b/tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php
new file mode 100644
index 000000000..590ada9e8
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher/Attribute/AsEventListener.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher\Attribute;
+
+/**
+ * Service tag to autoconfigure event listeners.
+ *
+ * @author Alexander M. Turek
+ */
+class EventDispatcher implements EventDispatcherInterface
+{
+ private array $listeners = [];
+ private array $sorted = [];
+ private array $optimized;
+
+ public function __construct()
+ {
+ if (__CLASS__ === static::class) {
+ $this->optimized = [];
+ }
+ }
+
+ public function dispatch(object $event, ?string $eventName = null): object
+ {
+ $eventName ??= $event::class;
+
+ if (isset($this->optimized)) {
+ $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName));
+ } else {
+ $listeners = $this->getListeners($eventName);
+ }
+
+ if ($listeners) {
+ $this->callListeners($listeners, $eventName, $event);
+ }
+
+ return $event;
+ }
+
+ public function getListeners(?string $eventName = null): array
+ {
+ if (null !== $eventName) {
+ if (empty($this->listeners[$eventName])) {
+ return [];
+ }
+
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+
+ return $this->sorted[$eventName];
+ }
+
+ foreach ($this->listeners as $eventName => $eventListeners) {
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+ }
+
+ return array_filter($this->sorted);
+ }
+
+ public function getListenerPriority(string $eventName, callable|array $listener): ?int
+ {
+ if (empty($this->listeners[$eventName])) {
+ return null;
+ }
+
+ if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
+ $listener[0] = $listener[0]();
+ $listener[1] ??= '__invoke';
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => &$listeners) {
+ foreach ($listeners as &$v) {
+ if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
+ $v[0] = $v[0]();
+ $v[1] ??= '__invoke';
+ }
+ if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
+ return $priority;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public function hasListeners(?string $eventName = null): bool
+ {
+ if (null !== $eventName) {
+ return !empty($this->listeners[$eventName]);
+ }
+
+ foreach ($this->listeners as $eventListeners) {
+ if ($eventListeners) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function addListener(string $eventName, callable|array $listener, int $priority = 0): void
+ {
+ $this->listeners[$eventName][$priority][] = $listener;
+ unset($this->sorted[$eventName], $this->optimized[$eventName]);
+ }
+
+ public function removeListener(string $eventName, callable|array $listener): void
+ {
+ if (empty($this->listeners[$eventName])) {
+ return;
+ }
+
+ if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
+ $listener[0] = $listener[0]();
+ $listener[1] ??= '__invoke';
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => &$listeners) {
+ foreach ($listeners as $k => &$v) {
+ if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) {
+ $v[0] = $v[0]();
+ $v[1] ??= '__invoke';
+ }
+ if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) {
+ unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]);
+ }
+ }
+
+ if (!$listeners) {
+ unset($this->listeners[$eventName][$priority]);
+ }
+ }
+ }
+
+ public function addSubscriber(EventSubscriberInterface $subscriber): void
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (\is_string($params)) {
+ $this->addListener($eventName, [$subscriber, $params]);
+ } elseif (\is_string($params[0])) {
+ $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0);
+ } else {
+ foreach ($params as $listener) {
+ $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0);
+ }
+ }
+ }
+ }
+
+ public function removeSubscriber(EventSubscriberInterface $subscriber): void
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (\is_array($params) && \is_array($params[0])) {
+ foreach ($params as $listener) {
+ $this->removeListener($eventName, [$subscriber, $listener[0]]);
+ }
+ } else {
+ $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]);
+ }
+ }
+ }
+
+ /**
+ * Triggers the listeners of an event.
+ *
+ * This method can be overridden to add functionality that is executed
+ * for each listener.
+ *
+ * @param callable[] $listeners The event listeners
+ * @param string $eventName The name of the event to dispatch
+ * @param object $event The event object to pass to the event handlers/listeners
+ */
+ protected function callListeners(iterable $listeners, string $eventName, object $event): void
+ {
+ $stoppable = $event instanceof StoppableEventInterface;
+
+ foreach ($listeners as $listener) {
+ if ($stoppable && $event->isPropagationStopped()) {
+ break;
+ }
+ $listener($event, $eventName, $this);
+ }
+ }
+
+ /**
+ * Sorts the internal list of listeners for the given event by priority.
+ */
+ private function sortListeners(string $eventName): void
+ {
+ krsort($this->listeners[$eventName]);
+ $this->sorted[$eventName] = [];
+
+ foreach ($this->listeners[$eventName] as &$listeners) {
+ foreach ($listeners as &$listener) {
+ if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
+ $listener[0] = $listener[0]();
+ $listener[1] ??= '__invoke';
+ }
+ $this->sorted[$eventName][] = $listener;
+ }
+ }
+ }
+
+ /**
+ * Optimizes the internal list of listeners for the given event by priority.
+ */
+ private function optimizeListeners(string $eventName): array
+ {
+ krsort($this->listeners[$eventName]);
+ $this->optimized[$eventName] = [];
+
+ foreach ($this->listeners[$eventName] as &$listeners) {
+ foreach ($listeners as &$listener) {
+ $closure = &$this->optimized[$eventName][];
+ if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) {
+ $closure = static function (...$args) use (&$listener, &$closure) {
+ if ($listener[0] instanceof \Closure) {
+ $listener[0] = $listener[0]();
+ $listener[1] ??= '__invoke';
+ }
+ ($closure = $listener(...))(...$args);
+ };
+ } else {
+ $closure = $listener instanceof WrappedListener ? $listener : $listener(...);
+ }
+ }
+ }
+
+ return $this->optimized[$eventName];
+ }
+}
diff --git a/tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php b/tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php
new file mode 100644
index 000000000..99f8b1a03
--- /dev/null
+++ b/tools/mailer/symfony/event-dispatcher/EventDispatcherInterface.php
@@ -0,0 +1,66 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;
+
+/**
+ * The EventDispatcherInterface is the central point of Symfony's event listener system.
+ * Listeners are registered on the manager and events are dispatched through the
+ * manager.
+ *
+ * @author Bernhard Schussek See Twig integration for better HTML integration!
+ * @author Chris Corbyn
+ *
+ * @internal
+ */
+abstract class AbstractStream
+{
+ /** @var resource|null */
+ protected $stream;
+ /** @var resource|null */
+ protected $in;
+ /** @var resource|null */
+ protected $out;
+ protected $err;
+
+ private string $debug = '';
+
+ public function write(string $bytes, bool $debug = true): void
+ {
+ if ($debug) {
+ foreach (explode("\n", trim($bytes)) as $line) {
+ $this->debug .= sprintf("> %s\n", $line);
+ }
+ }
+
+ $bytesToWrite = \strlen($bytes);
+ $totalBytesWritten = 0;
+ while ($totalBytesWritten < $bytesToWrite) {
+ $bytesWritten = @fwrite($this->in, substr($bytes, $totalBytesWritten));
+ if (false === $bytesWritten || 0 === $bytesWritten) {
+ throw new TransportException('Unable to write bytes on the wire.');
+ }
+
+ $totalBytesWritten += $bytesWritten;
+ }
+ }
+
+ /**
+ * Flushes the contents of the stream (empty it) and set the internal pointer to the beginning.
+ */
+ public function flush(): void
+ {
+ fflush($this->in);
+ }
+
+ /**
+ * Performs any initialization needed.
+ */
+ abstract public function initialize(): void;
+
+ public function terminate(): void
+ {
+ $this->stream = $this->err = $this->out = $this->in = null;
+ }
+
+ public function readLine(): string
+ {
+ if (feof($this->out)) {
+ return '';
+ }
+
+ $line = @fgets($this->out);
+ if ('' === $line || false === $line) {
+ $metas = stream_get_meta_data($this->out);
+ if ($metas['timed_out']) {
+ throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription()));
+ }
+ if ($metas['eof']) {
+ throw new TransportException(sprintf('Connection to "%s" has been closed unexpectedly.', $this->getReadConnectionDescription()));
+ }
+ if (false === $line) {
+ throw new TransportException(sprintf('Unable to read from connection to "%s": ', $this->getReadConnectionDescription()).error_get_last()['message']);
+ }
+ }
+
+ $this->debug .= sprintf('< %s', $line);
+
+ return $line;
+ }
+
+ public function getDebug(): string
+ {
+ $debug = $this->debug;
+ $this->debug = '';
+
+ return $debug;
+ }
+
+ public static function replace(string $from, string $to, iterable $chunks): \Generator
+ {
+ if ('' === $from) {
+ yield from $chunks;
+
+ return;
+ }
+
+ $carry = '';
+ $fromLen = \strlen($from);
+
+ foreach ($chunks as $chunk) {
+ if ('' === $chunk = $carry.$chunk) {
+ continue;
+ }
+
+ if (str_contains($chunk, $from)) {
+ $chunk = explode($from, $chunk);
+ $carry = array_pop($chunk);
+
+ yield implode($to, $chunk).$to;
+ } else {
+ $carry = $chunk;
+ }
+
+ if (\strlen($carry) > $fromLen) {
+ yield substr($carry, 0, -$fromLen);
+ $carry = substr($carry, -$fromLen);
+ }
+ }
+
+ if ('' !== $carry) {
+ yield $carry;
+ }
+ }
+
+ abstract protected function getReadConnectionDescription(): string;
+}
diff --git a/tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php
new file mode 100644
index 000000000..e63514709
--- /dev/null
+++ b/tools/mailer/symfony/mailer/Transport/Smtp/Stream/ProcessStream.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Mailer\Transport\Smtp\Stream;
+
+use Symfony\Component\Mailer\Exception\TransportException;
+
+/**
+ * A stream supporting local processes.
+ *
+ * @author Fabien Potencier