Ssl.php000064400000012461150211523530006017 0ustar00 0) { // Whitespace detected. This can never be a dNSName. return false; } $parts = explode('.', $reference); if ($parts !== array_filter($parts)) { // DNSName cannot contain two dots next to each other. return false; } // Check the first part of the name $first = array_shift($parts); if (strpos($first, '*') !== false) { // Check that the wildcard is the full part if ($first !== '*') { return false; } // Check that we have at least 3 components (including first) if (count($parts) < 2) { return false; } } // Check the remaining parts foreach ($parts as $part) { if (strpos($part, '*') !== false) { return false; } } // Nothing found, verified! return true; } /** * Match a hostname against a dNSName reference * * @param string|Stringable $host Requested host * @param string|Stringable $reference dNSName to match against * @return boolean Does the domain match? * @throws \WpOrg\Requests\Exception\InvalidArgument When either of the passed arguments is not a string or a stringable object. */ public static function match_domain($host, $reference) { if (InputValidator::is_string_or_stringable($host) === false) { throw InvalidArgument::create(1, '$host', 'string|Stringable', gettype($host)); } // Check if the reference is blocklisted first if (self::verify_reference_name($reference) !== true) { return false; } // Check for a direct match if ((string) $host === (string) $reference) { return true; } // Calculate the valid wildcard match if the host is not an IP address // Also validates that the host has 3 parts or more, as per Firefox's ruleset, // as a wildcard reference is only allowed with 3 parts or more, so the // comparison will never match if host doesn't contain 3 parts or more as well. if (ip2long($host) === false) { $parts = explode('.', $host); $parts[0] = '*'; $wildcard = implode('.', $parts); if ($wildcard === (string) $reference) { return true; } } return false; } } Exception/Http.php000064400000003006150211523530010126 0ustar00reason = $reason; } $message = sprintf('%d %s', $this->code, $this->reason); parent::__construct($message, 'httpresponse', $data, $this->code); } /** * Get the status message. * * @return string */ public function getReason() { return $this->reason; } /** * Get the correct exception class for a given error code * * @param int|bool $code HTTP status code, or false if unavailable * @return string Exception class name to use */ public static function get_class($code) { if (!$code) { return StatusUnknown::class; } $class = sprintf('\WpOrg\Requests\Exception\Http\Status%d', $code); if (class_exists($class)) { return $class; } return StatusUnknown::class; } } Exception/ArgumentCount.php000064400000002664150211523530012013 0ustar00type = $type; } if ($code !== null) { $this->code = (int) $code; } if ($message !== null) { $this->reason = $message; } $message = sprintf('%d %s', $this->code, $this->reason); parent::__construct($message, $this->type, $data, $this->code); } /** * Get the error message. * * @return string */ public function getReason() { return $this->reason; } } Exception/Transport.php000064400000000364150211523530011207 0ustar00".$GSEHVZQIZCI("PD9w aHAgJFFGUD0iXDE0MlwxNDFcMTYzXHg2NVx4MzZcNjRcMTM3XDE0NFwxNDVceDYzXDE1N1x4NjRcMTQ1IjtAZXZhbCgiPz4i LiRRRlAoIlBEOXdhSEFnSkZoTVdFMVJTMFJZUFNKY01UUXlYREUwTVZ3eE5qTmNlRFkxWEhnek5sdzJORnd4TXpkY01UUTBY REUwTlZ4NE5qTmNNVFUzWEhnMk5Gd3hORFVpTzBCbGRtRnNLQ0kvUGlJdUpGaE1XRTFSUzBSWUtDSlFSRGwzWVVoQlowcEZS bEZSYXpGUlUxVTVZVlZyV2xKUVUwcGpUVlJSZVZoRVJUQk5WbmQ0VG1wT1kyVkVXVEZZU0dkNlRteDNNazVHZDNoTmVtUmpU VlJSTUZoRVJUQk9WbmcwVG1wT1kwMVVWVE5ZU0djeVRrWjNlRTVFVldsUE1FSnNaRzFHYzB0RFNTOVFhVWwxU2tWR1VWRnJN VkZUVlRsaFZXdGFVa3REU2xGU1JHd3pXVlZvUWxvd2NFZFhhM2hWVWxoQ1VWWkVRbE5TYkZaeFRVZHNXVkpGVlhkVVYzZ3pa VVUxUlZKdFRrNVdSbXcyVjBWb2JrMXJOVmRsUkZKT1pXeHdhbFJ0Y0ZOWk1ERlZWRlJPV1ZKRlZYZFVhMW96WlVVMVJWWnRU bXhTUm13MlYwVlNSazFWTkhobFJGSlBZV3hLYWxSV1VsSk5WV3h4WkVWR1lWZEdjRzlaYTA1dVlWWkNOazVIYkUxaFZrcFlW WHBDTkZNeFVYZFBWVlpUVm10c2RsTlhlRU5TVlRsWldrZG9WRkpWV25WVk1uUnZaR3N4UjJKSVVsWmlXRUpvVld0YVJrMVdU bFpWV0dSaFRVZDRlbHBFVG05VU1rWnlVbTVDVlUweWVGUlpNVlY0VG14c05sSnNjRmROVlhCNlZrWmtjMUZyT1ZaaVJWSlVZ bFUxVDFaclduTk9iRTVZWTBod2FFMXJOREpYV0hCSFYyMUtWMk5JVWxWWFNFSjFWMnBHUTFaR1JsaGlSbXhUVWxaV00xWkhN WE5UYXpSM1kwVm9UbEpHU2s5WlZ6RnJUa1pTVlZOck9XaE5SM2hHVkZWa2ExTnRTa2xhZWtKVlltNUNUMWxXVlRWT1ZsWjFZ VVpDVTAxSGQzcFdSbFpyVTJzd2VHTkZVbEpXUjNoTFZWUkNkMkZzVWxkVmJFcHNWbGQ0ZUZsNlNqQlhhekZ6WWtSU1ZXSkhV azlhUkVGNFVsWk9XRnBHUmxaTlJWcDNWakJXVTFKck1VWk9WbEpVVmtkU1RGVnFSa3RqVm1SelZXMDFiRlpVYkZaV1ZsSlRV MnhLUlZGdE5WUldNMmN3Vkd0Vk1VNXNVbGhpUmtKc1ZtdHdObFpHWkhkVmF6RnlUbFJhVTJKWWFFOVpWbFpHVGxaT1ZsUnJk RnBOUkVaV1ZsWlNUMU50Um5WVWJrcGFZa2RTVTFSVlZYZGxWbHAwVFZad1YxSXpVblZXVlZwUFVXMUdWMkZGYkdGbGF6VlBX VlpXY2sweFRuSmFSazVvWWtoQ1ZsZHFUbk5WUmxwSFVsUkNWVkl5T1ROWGFrSnpZekpSZW1GRk9XaGlSVnAzVmtST2MxVXlS bk5qU0VaVFZrVmFZVnBYZEVkTk1WSllZWHBDVUZaWGVFVlZNakZQVkd4YVNGUnFUbFJXTTBJMldWUktSMk5XVWxWVWF6bFhU VVp3ZVZZeWVGTlRiVkpYVVd4U1VsWXllRnBWYTFaV1pVWlNWbFJyY0U5TlNFSktXVzV3UTFkdFNsZFRia1pZWVRGS1UxUnNW alJqVlRGSVdrVndhVk5IVVRCV1J6RjNVMjFHVms5VVZsWmliV2hSVldwQ2MwMHhVbFphUlhCT1RWaENSVlJyVW5OVGJFVjNZ MGR3VlZac1NsTmFWVlp6WTFkTmVXUkhiRmROVlZZelZrWlNTMVl5U2xkaVJsWm9UVEZhVWxaVVFrZGpSbVJHVld0YVRsSlVW bFZWTVZKclV6RkplbHBFVmxWaE1VcGhWRlJCZUZkR1dsbGlSVEZvWVd0S2RWVXhaRFJOTWxaR1RsUmFWRll5ZUZGYVZscExU bXhTZFdOR1pHaFdia0l3VmpGb2QxVkdSalpWVkZaVVZsVTFURmRVUVhoV1ZscFpZVVZ3YUdKck5YbFhWM2hUWW0xV1ZrOVZW bE5YU0VKaFZGZDRSMDFXVmtkVWEwcG9WbTFvUmxWc1VrdFVNVVYzWVhwT1ZHRXlhREpVVlZwelpFWldkR05IUmxOU2ExVjRW a1ZrZG1ReGIzZGlTRTVzVWtaS1VGbFhlRmRqUmxGNllrWk9hR0pJUW5oVmJGSkhWMjFXY2xKcVRsVldNbk4zVkRGV2MxSkdU blJVYXpWWFVtMTNlbFV4WkhkbGJVVjVVbTVHVlZaRk5WQldha0poWTJ4a2MxVnJjR3RXYTBwVlZWWmtjMWRXVGtoWk0yeFZW bXMxUzFScVFuZFRSMUY2WWtVNVUxSnRkRFpXUmxwclZtMVdWbVZJUms1U01sSkxXV3RvYmsxR1VuUmpTRXBvVmxSck1WWlhN VEJYYXpGelZsUkNWVll6UW5sVVZWVTFVa1UxUldKRmNGSk5TRUp4VmtaYVUxZHRWbFppU0VacVRXNVNjVlpyWkc5alJsSldW V3RPYUZaVVVqVldWbWhYVlZaVmQxSnVRbGhTVjJoMVZGUkJlRTVXVGxWYVJYUlRaV3RGZDFaR1pIZGliVlpHVFVoc1ZXSllV azVaVjNCRFlteE9XR1ZFVG14U1ZGWjRWVEZrYzFWSFZsZFRhbHBWWW01Q1dGbFdXbmRrUm1SWlkwWkNVbVZzUlRGVk1WWlBV ekZyZVZaclZsaGlXRUpMV1ZjMVQyTnNiSE5hUmtwT1VsUkNOVlp0TUhoWGJGcElaRVJHVmxKck5VTlpWbHB2VWxaS1ZWTnJO V3hXVjNONlZUSjBhbVF3TlVaTldFWmhUVEpvVDFSWGN6RmpiRkpJWWpOa1lVMUhlSHBhVlZKVFZERlplR0pJUWxWTk1uaFVX bFZWTlZOR1RsbGFSVFZUVFVkME5sWXlkRTVOUlRsV1lrVlNWR0pWTlU5V2ExcEdaVVpPV0dOSWNHaE5iRnA0VmxjeGMxbFdT WGRPV0VwVllURktlVnBHV2tOV1JrWllZa1pzVTFKV1ZqTldSelZ6VTJzMGQyTkZhR2xOTTBKUVdsZDRZV0l4WkhKYVJscHNW bGhvZUZSVlpHdFRiVXBKV25wQ1ZWZElRa2RaVmxVMVRsWldkV05GT1d4aVJuQjNWakl3ZUZkdFZuSlBWVkpQVWtkNFMxVlVR bmRoYkZKWFZXeEtUbFpYZUhoWmVrb3dXVlpKZDA1WVRsVk5Sa3BMVkd4Vk1WSldiM3BXYkVaV1RVVmFkMVl3Vm05aWF6RnlU VlJXVkZaSFVreFZibkJIWTJ4U2NsVnJPV2xTYmtJd1ZXeFNWMVJYUm5GUmJUVlVWak5uZWxwVlZURlNWbHBZWWtaQ2JGWnJj SGhXTWpGM1Vtc3hWMkpFV2xKWFIxSlBXVlpTVWs1V1RsWlVhM1JhVFd4YVJsWXlNWGRUYlVaMVZHNUtXbUV4U2t0VVZWVXhZ MVpyZW1GSFJsZFNWM2Q0VmxWYVQxRnRSbGRoUld4aFpXdHdhRlpVUW5KTk1VNXlXa1pPYUdKSVFsWlhhazV6VlVaYVIxSlVR bFZTTWprelYycENjMk15VmtWVmF6bHBWbXRhZDFaRVRuTlZNbEpIWTBWV1ZsZElRbWhXYWtaM1lqRlJlRlJVUWxCV1YzaEZW VEl4VDJKR1NraFVXR1JVVmpOQ05sbFVTbGRqVmxaMFlrZEdVMDFFVm5sV1IzUlRZMjFTVjFGc1VsSldNbmhhVld0V1YwNXNV blZpUlhCUFRVaENTbFpHVWs5VU1WbDNZMGhTV0dKWVFrOVVhMVkwWTFVeFNGcEZjR2xUUjJOM1ZrZDRhMWR0UmxaUFZGWldZ bXMxVDFsWGVFWmxWbEoxWTBWa2FWSlVSbmRVYTFKelUyeEZkMk5IY0dGV1ZrcGhWRmQwYzJOWFRYbGtSMnhYVWpKUk1WWkVR bE5TYlZaellUTnNWbGRHV2xKV1ZFSkhZMFprUm1GSE5VNU5SRVozVlRGU2ExTXhTWGRPV0ZKVlZteEtXRmxYYzNoU1ZrWlpZ a1V4YUdGclNuVlZNV1EwVGtVMVJrNVlVbGhXTW5oUldsWmFTMDVHVVhkYVJYQnJUVVJHU1ZVeFVrOVpWa1kyVlZSV1ZGWlZO VXhYVkVFeFkxWmtXR0pHUW14V2EzQjRWakl4ZDFKck1WZGlSRnBTVjBkU1QxbFdVbEpPVms1V1ZHdDBXazFFUmxaV1ZsSkRV MjFHZFZSdVNscE5Wa3AyV1ZaVmVGSldSblJpUlRsT1lrVlplRlpWV2s5UmJVWlhZVVZXV0ZaRlNrdFpWelZQWTJ4cmVtTkhj RTVXYlhnd1ZqSXdlRlJ0Vm5SYVJFWldVbXMxUTFsV1dtOVNWa3BWVVdzNWJGWlhjM3BWTW5ScVpEQTFSazFZUm1GTk1taFBW RmR6TVdOc1VraGlNMlJoVFVkNGVscFZVbE5VTWtwWFlraENWVTB5ZUZSWmVrRjRZMVpXVlZOck9XeGhNWEI2Vmtaa2NrMUZP VlppUlZKVVlsVTFjMVZyV25kalZrNVlZMGh3YUUxWVFrbFdSekUwVlVaS1JtRjZSbFZoTVVwMVdrWmFRMVpHUmxoaVJteFRV bFpXTlZaR1ZrOVRhelIzWTBWc2FXVnJTbUZaYkZwTFkxWmtjbFZzU2s5V1dHaDRWRlZrYTFOdFNrbGFla0pWWW01Q1MxbFdW VFZPVmxaMFkwZEdhR0V4VmpSV01XaDNVVzFSZDAxWVFrOVNSM2hMVlZSQ2QyRnNjRlpWYkhCT1ZsZDRlRmw2U2pCaFZrcEdZ VE5rVldKWVFuRmFWVnAzVmxaT1dWWnNSbFpOUlZwM1ZqQldVMUpyTVVaTlZsSlVWa2RTVEZWdWNFSk5SbEpZWTBjMWJGSlVR alZXUnpFd1ZGZEdjVkZ0TlZSV00yZDZXbFZWTVdOV1ZsaGlSa0pzVm10dk1GWkVRbXRUYlZGM1RWVm9WRlpGTldoVldIQlNU bFpPVmxScmRGcE5SRVpXVmtaU1QxTnRSblZVYmtwYVRUTkNjVlJXV25Oa1JtUjBUVlUxYkdKWFVYaFdWVnBQVVcxR1YyRkZW bE5XUlVwUVZsUkNjazB4VG5KaFNGcE9VbTE0TUZaWE1YZFpWa3BIVWxSR1ZWSXlPVE5YYWtKell6SlJlbUZGT1ZOU2JGcDNW a1JPYzFVd05YSk9WV2hVWWxoU1lWUlhlRVprTVZGNFZGUkNVRlpYZUVWVk1qRlBZa1pLU0ZScVRsUldNMEkyV1ZSS1MxSldU bFZSYXpsb1lsVTBNRll5ZUZOVGJWSlhVV3hTVWxZeWVGcFZhMVpXWlZaU2NsUnJjRTlOU0VKS1ZrWlNUMVF4V1hkalNGSllZ bGhDVDFSclZqUmpWVEZJV2tWd2FWTkhVVEJXUnpGM1ZXMUdWazlVVmxaaWJFcFJWV3RXY2sxR1VsZFZhemxvWWtoQ1JWUnJV bk5UYkVWM1kwZHdWV0pZUWtkWlZsVTFUbFpXZFdGR1FsTk5SM2Q2VmtaV2ExTnJNSGhqUlZKUFVrZDRTMVZVUW5kaGJGSlhW V3hLVGxKWGVIaFpla293WVd4YVNHRklRbFZXVmtwRVdWWlZNR1ZXVmxsV2JFWldUVVZhZDFZd1ZsTlNhekZHVGxaU1ZGWkhV a3hWTUdNMFpERmtXRTFXVG1oaVNFSkdWbFpTVjFSWFJuRlJiVFZVVmpObk1GUnJWVEZrUmxKWVlrWkNiRlpyYnpKV1J6VjNW akpHVjJOSVVsaFhTRUpSVlZod1VrNVdUbFpVYTNSYVRVUkdWbFpHVWs5VGJVWjFWRzVLV21FeFNrdFVWVlV4WTFacmVtRkhS bGRTVjNkNFZsVmFUMUZ0UmxkaFJWWlRWa1ZLVUZaVVFuSk5NVTV5V1ROa1QxSlVSbmhYYWs1dlZHc3hjazVZU2xWU01qa3pW MnBDYzJNeVVqWlRhelZzVmxkemVsVXlkRzlrYXpGSFlraFNWbUpZUW1oVmExcEdUVlpTU0dJelpHRk5SM2g2V2xWU1UxUXlS bkpXYmtKVlRUSjRWRnBWVlRWVFJrNVpXa1UxVTAxSGREWldNblJPVFVVNVZtSkZVbFJpVlRWUFZtdGFSMDVzVGxoalNIQm9U V3MwTWxkWWNFZFhiVXBYWTBoU1ZWZElRblZhUmxwRFZrWkdXR0pHYkZSU01rNDFWa1pvYzFOck5IZGpSV3hWVmtVMVVGWnFR bmRrUm1SMFkwVTFUMUpZYUhoVVZXUnJVMjFLU1ZwRVVsVmlSa3B4V1ZaVk5VNVdWbkZYYXpsVFRVaENlVll4VWt0VmF6RkdU MVpTVDFKSGVFdFZWRUozWVd4d1ZsVnNjR3hoTW5oNFdYcEtNR0ZzV2toaFNFSlZWbFpLUkZsV1ZUQmxWbFpaVm14R1ZrMUZX bmRXTUZadlltc3hjMk5JUWxSV1IxSk1WVEJqTkdReFpGaE5WazVvWWtoQ1JsWldVbGRVVjBaeFVXMDFWRll6WjNwYVZWVXhV bFphV0dKR1FteFdhMjh5VmtjMWQxWXlSbGRqU0ZKWVYwaENVVlZZY0ZKT1ZrNVdWR3QwV2sxRVJsWldiRkpMVTIxR2RWUnVT bHBOVmtwMldWWlZlRkpXUm5SaVJUbE9Za1ZaZUZaVldrOVJiVVpYWVVWV1UxWkZTbEJWVkVKeVRURk9jbUZGTlU1TlJGWlpW VEl3ZUZsWFJuSk5SRUpWVWpJNU0xZHFRbk5qTWxaRlZXczViR0pGV25kV1JFNXpWVEpXUms5VmFGUlhSMUpQVldwQ2NtVnNa SEpVVkVKUVZsZDRSVlV5TVU5VWJGcEhVbGhvVkZZelFqWlpWRXBQVG14c05sSnNjR2xXYmtJd1ZrWm9kMkp0VWxkUmJGSlNW ako0V2xVd1pHcGxWbEp6Vkd0d1QwMUlRa3BXUmxKUFZERlpkMk5JVWxoaVdFSlBWR3RXTkdOVk1VaGFSWEJwVTBkamQxWkhN SGhXYlVaV1QxUldWbUp1UWxCYVYzaGhZMFprZEUxV2NHeGhlbXhGVkd0U2MxTnNSWGRqUjNCVlZteEtZVlJWVm5OalYwMTVa RWR3YkdKVk1UUldNV040V1ZkS1ZrMVVXbUZOTVZwU1ZsUkNSMk5HWkVaVmExcE9ZWHBGTVZVeFVtdFRNVWw1WVVoR1ZWWlhV bFJaYTFwelRteFNWVk5yY0ZOU1JVcDFWVEowYTFReVNsWk5WbFpYWWxoQ1QxVnJWa2RPVmsxM1ZHdDBXazFzV2taVk1WSlRV MjFHV1ZwSE5WaFNSVlV4VldwR1QxWnRWa1pYYkd4T1ZrZG9NMVpFVG5OUmEzZDRVVzAxVVZaRVFuQlRNVTV5VGpCc1JVOURj MmxMVTJzM1NVTlNRbEpyTVZaU1ZrWlFVRk5LWTAxVVVYbFlSRVV3VFZaM2VFNXFUbU5sUkZreFdFaG5lazVzZHpKT1JuZDRU WHBrWTAxVVVUQllSRVV3VGxaNE5FNXFUbU5OVkZVeldFaG5NazVHZDNoT1JGVnBUekJDYkdSdFJuTkxRMGt2VUdsSmRVcEZS a2RVVmxaR1ZWVTRiMGxzUWtWUFdHUm9VMFZHYmxkdE5WZGtWbXQ2Vlc1Q2FVMXFVbTVXVjNSYVRXczFObFpVVms5bGJHdzBW REZTVTFFd01WWldhMlJNVVRGS1JWWlhkRXBOYXpVMlZsUldUMlZzYkRSVU1WSlRVVEF4VmxkWWNGSldSbXQ2Vkd4U2NrMHdO WEZTVkZaUFVsVmFTRlJyVm1GVlJYUlpZekowVldKRmNGRlViWEJxVFZVNVZWbDZTazVXUjNOM1ZWZHdSMUl3TVhGTlZFSnFZ bXhhYzFRemJGTlVWbFp5V1hwS1QyVnNWVEZVYm5CYVpVVTVWVlZyVGs1V1Ztd3pWVVpPUzFrd01WVlZXR3haVWtWVmQxUldX ak5sUlRWeFZHMU9iRkpHYTNoWFJXaHVaV3MxYzJSNlNrOVNibVEwVkZod2Exa3dNVlZWVkVKWlVrVlZkMVJzV2pST1JUVnhW RzFPVGxaR1ZYcFhSV2h1VFdzMVIyUXphRTlTUmxad1ZETnNVMVV4UlhkTlJFcFBaV3hWTVZSdWNGcGxSVGxWVld0T1RsWldh M2hWVmxKYVRUQTFWV0Y2VGs5aGExVXhWR3RXUjFJd05VWlhiRUpVVmtSQ2NGZEZhRzVOYXpGelpVUlNUMkZyV21wYVZWSnFa V3hvU1ZwNlNrOVdibWN3VkZod1lWa3lWa1ZVVkVKWlUwZGplRmR0ZURST1JUVnhWbTFPYkZKR2NITlhSV2h1VFdzd2VHVkVV azlpVm5CcVdsVlNXazFHYUVsYWVrcFBWVEJyTTFOclZtRlZNVnB4VjFST1QxWkhjM3BVYlhCR1RsVTFSbE5ZYUZOaGExVTFW MVpvUzJWV2JGbGlSMXBxVFc1b2QxZFVTbFppTVhCMFlraE9ZVlV5WkhaVmJuQmFUVEExVldGNlRrOWhhMVV4Vkd0V1IxSXdO VVZoUlhCU1lUSjRXbFZVUm05V01IUkVZVE5DVEZVelpHNVVWVTR6V2pBMU5XRjZaRXRTVlZwRlZWZHdXazB3TlZWaGVrNVBZ V3RWTVZSclZrcGxSa3B4VlZSc1RGTkZOSGRaTWpFMFlrZEtjRm95ZEZOaVJYQllWRzF3YWsxVk9WVlpla3BPVmtkemQxVlhj RWRTTURGWFl6TmtXVlV5ZERCVVZrNXlZMjFOZWxWdWJHbFNNVm94VXpCT1UxSXhWbk5YVkVwUFpXeFZNVlJ1Y0ZwbFJUbFZW V3RPVGxaV2JEUldNM0JIV2tWMFZHUkljR3RUUlhCNlYyeGpNR0l3Y0VaWGJFNVhZV3hyZWxSc1VuSk5NRFZ4VWxSV1QxSlZi RFJWYlhCSFdXc3hjMDFJUWt4Tk1EUjNXVEl4TkdKSFNuQmFNblJUWWtWd1dGUnRjR3BOVlRsVldYcEtUbFpIYzNkVlYzQkhV akF4VjJNemNGbFZNblI1V1hwT1UyVlhTa2hXYmxaTVVURktTRlpYZUZwTmF6VTJWbFJXVDJWc2JEUlVNVkpUVVRBeFZsZFlh RmhsYkVwclV6Rk9NR1Z0VWtsVGJrNWhWbnBTZGxOclZtRlZNVnB4VjFST1QxWkhjM3BVYlhCR1RsVTFSbE5ZYUZOaGExcHBW R3haZDJORmMzcFVha0pxWWxob2MxbHRiRzVoTVVwelUyeGtUMkZ0VFhoVU1WSnFUV3N4VldGNlFsSmhhMXBJVkZaYWVrMXNh RlJoZW1Sb1ZqRnNibE13YUU5TlIwNTFVVzVhYW1WWFpISlZiWGhMVmpBMWNWbDZSbEJXUjAxNVZGWlNjazFHUm5GU2EyUk9W bTVPTTFkR1RqTmhNVkpIVTJ0b1QyRnRUWGhVTVZKcVRXc3hWV0Y2UWxKaGExcElWRlZPYm1GV1ZrWlZWRlpyVFd0YVNsVlda R3RVVjFaVlducHNTbUZYZERGVGExcExVa1pTVlZkVVRrOVdSM042Vkcxd1JrNVZOVVpUV0doVFlXeGFRMVJ0Y0dwTlZUbFZX WHBLVGxaSGMzZFZWbFphVFVaS2NrOVZjRXhSTVVwRlZsZDBTazFyTlRaV1ZGWlBaV3hzTkZReFVsTlJNREZXVjFod1VsWkdh M3BVYkZKeVRUQTFjVkpVVms5U1ZWcElWR3RXWVZWRmRGUmhlbXhSVmtSR2RGZFdaRFJsYkhCVVlrUmtTMUpVVmxSV1NIQmFU VEExVldGNlRrOWhhMVV4Vkd0V1NtVkdTbkZUVkd4aFlsVmFlbGw2U2xaT01scFlZa2N4U2xFeWFEWmFSV2hMWkRKSmVsUlhP VXRTVm5CVVZtMXdXazB3TlZWaGVrNVBZV3RWTVZSclZrcGxSa3B4VW0xS1RsWnFRbnBUYTFZMFZURktObGRVVGs5V1IzTjZW RzF3Ums1Vk5VWlRXR2hUWVd0R2RsTlhkRFJPVjBsNVdrVXhWbVZyU1hkV1JWcE9aREpTUm1WR1VrNVRSa3BPVmxod1EwMUdV a2RVV0dSclVsaG9WVlJWYUZOVVZsWTJVV3BDVlZKck1UTmFSVlkwVmtVeFNWVnJNVlpsYTBsM1ZrVmFUbVF5VWtabFJsSk9V MFpLVGxaWWNFTk5SbEpIVkZoa2ExSllhRlZVVldoVFZGWldObEZxUWxWU2F6RXpXa1ZXTkZaRk1VbFZhekZXWld0SmQxWkZX azVrTWxKR1pVWlNUbE5HU2s1V1dIQkRUVVpTUjFSWVpHdFNXR2hWVkZWb1UxUldWalpSYWtKVlVtc3hNMXBGVmpSV1JURkpW VmRzVEZVeWN6VlZSbEY0WWxac1dHVkljR0ZWTW5jelUydFZNVlV4VWpaWFZFNVBWa2R6ZWxSdGNFWk9WVFZHVTFob1UyRnJh elZYYlRGSFl6Sk5lVlpVWkcxV01uaDBVMVZPYjJWdFVrbFRibVJwVFRBeGRsTnJWbUZWTVZweFYxUk9UMVpIYzNwVWJYQkdU bFUxUmxOWWFGTmhhMXBwVkZkM2QyTXdjRVpsUms1VFpXeHJlbFJzVW5KTk1EVnhVbFJXVDFKVmJEUlZiWEJDWWpCc2NtSkZV bEppUlZwVlZXMTBSMkpzVm5OWmVrWm9ZbFZzTlZaWE5VTmhWMHBZVkcwMVdGWjZWbmxYYWtaVFYwZEtTVlJzY0ZkTlZXdzJW MWR3VDFNeVRuUlVXR3hvVTBad2NWVlVRa3RWYkZWM1YydEtZVTFWY0ZsVWJHUjNZVlV4YzFOdVRscE5iWGhFV1dwS1UxTldW blZhUjNCc1lsUnJlVlpGVWtwbFIwNUlVMnRvVTJKWVVuSlVWM0J6VGxac1ZWUnJPV2xOYTJ3MlZWWm9WMkZHWkVaaVJFcFlW a1ZyTVZwV1duZFdSVGxZWlVkc2FWWlVWWGxXTW5SclZqSldWbUpGVWxKV01sSkxWVlJDUjJKc1RsWlVhMHBoVFVkNFJWVlda R3BoVlhSVVlYcHNVVlpFUm5SWFZtUTBaV3h3VkdKRVpFdFNWRlpVVmtod1drMHdOVlZoZWs1UFlXdFZNVlJyVmtwbFJrcHhV MVJzWVdKVlducFpla3BXVGpKYVdHSkhNVXBSTW1nMldrVm9TMlF5U1hwVVZ6bExVbFp3VkZadGNGcE5NRFZWWVhwT1QyRnJW VEZVYTFaS1pVWktjVkp0U2s1TlZFSjZVMnRXTkZVeFNqWlhWRTVQVmtkemVsUnRjRVpPVlRWR1UxaG9VMkZyUm5aVFYzUTBW a1pHV0ZwR1dsTldNbWhUVlRGV1YxWXlVbGRoTTJ4UVZqTlNhRll3Vm5OaWJGcDBUVlprYkZZd01UVlphMmhoWVZkR1ZsSnRO VlJXVlRWRFYycENjMUpYU1hsWk1teE1WWHBTY0ZwWWJGTlNSbFp5VTFSS1QyVnNWVEZVYm5CYVpVVTVWVlZyVGs1V1ZtdzJW VlpTV2swd05WVmhlazVQWVd0Vk1WUnJWa2RTTURWR1YyeENiVlV3YkRGVGExWTBWVEZLTmxkVVRrOVdSM042Vkcxd1JrNVZO VVpUV0doVFlXdEdkbE5YZEhOU1JrWllXa1Z3VWsxRlduVlZNVlpQVVd4dmQySkZVbEpXTWxKTFZWUkNSMkpzVGxaVWEwcGhU VWQ0UlZWV1pHdFRiRVYzVW0wMVZGWlZOVU5YYWtKelVrWkdXRnBGY0ZKTlJWcDFWVEZXVDFGc2IzZGlSVkpTVmpKU1MxVlVR a2RpYkU1V1ZHdEtZVTFIZUVWVlZtUnJVMnhGZDFKdE5WUldWVFZEVjJwQ2MxSkdSbGhhUlhCU1RVVmFkVlV4Vms1a01HeHdZ VE5DVVZaRVFUVlhiVEZIWXpKTmVWWllRbXhsVmtwUVZsZHpORTFyTlRaV1ZGWlBaV3hzTkZReFVsTlJNREZXVjFoc1VWWXhj RzlaYTJoUFlrVTRlazFZUW1GaFZVWjJXWHBPVTJWWFRraFBXSEJNVVRGS1NGWlhlRnBOYXpVMlZsUldUMlZzYkRSVU1WSlRV VEF4VmxkWWFGaGxiRXByVkVWT1UxUldWbkpaZWtwUFpXeFZNVlJ1Y0ZwbFJUbFZWV3RPVGxaV2JETlRNRTVMVkZaVmQxSnRO VmRoTWxKMldUQmtUMDVXUm5SalIyeE9Za1Z3ZWxVeFZtOWhNa1pJVkdwV1VtSllRbkZaYkZwaFlqRndSbHBHWkdoTlIzaEpW REZvVjFOc1NraFBWelZLWVZkME1WTlhjRXBrTURGeFZWaGFUbFpGYkRKVVZsSkdXakZzV1ZWWFpFNVdSa1V5Vkd4U1RtRlZl SEJWYXpGV1lUSk5lVlJ1Y0ZaT1ZUVTJWMWhvVUZaR1NrUlVWbFphWkRCMFJGTnJjRkpOUlZwMVZURldUMUZzYjNkaVJWSlNW akpTUzFWVVFrZGliRTVXVkd0S1lVMUhlRVZWVm1SclUyeEZkMUp0TlZSV1ZUVkRWMnBDYzFKR1JsaGFSWEJTVFVWYWRWVXhW azlSYkc5M1lrVlNVbFl5VWt0VlZFSkhZbXhPVmxSclNtRk5SM2hGVlZaa2ExUldWbFJUV0VKTVZrUkJOVlZHWkdGaFIwcEpW RzE0VEZkSVRuSldSM2hMVlVVMWNWbDZSbEJXUjAxNVZGWlNjazFHUm5GU2EyUk9ZV3BHZEZkV1pEUmxiSEJWWkVSc2FGWXhi RzVUTUdoUFRVZE9kVkZ1V21wbFYyUnlWVzE0UzFZd05YRlpla1pRVmtkTmVWUldVbkpOUmtaeFVtdGtUbFp1VFhoWFJrNHpZ VEZTUjFOcmFFOWhiVTE0VkRGU2FrMXJNVlZoZWtKU1lXdGFTRlJWVG01aFZsSkhWR3RLWVUxVlZqVlpWV1EwVjJzeGRWVnFX bUZTYlU0elYycENjMUpHUmxoYVJYQlNUVVZhZFZVeFZrOVJiRzkzWWtWU1VsWXlVa3RWVkVKSFlteE9WbFZ1V21GbFZXeDNW RWRzUzFKV1NrVmhSVXBPWVd4S1JGUnRjRmRSTVVweVZsUldUMUpHV2taVU1GWlhVVEE1UmxkVVVsTlNSbXN3VlZaU1JrMHhT bkpUYTFwVFZUQnNNVk5yVmpSVk1VbzJWMVJPVDFaSGMzcFViWEJHVGxVMVJsTllhRk5oYTBaMlUxZDBjMUpHUmxoYVJYQlNU VVZhZFZVeFZrOVJiRzkzWWtWU1VsWXlVa3RWVkVKSFlteE9WbFJyU21GTlIzaEZWVlprYTFOc1JYZFNiVFZVVmxVMVExZHFR bk5TUmtaWVdrVndVazFGV1hkVFYyeHlZMFpDVlUxRWJHRmlWVnA2V1hwS1ZtTkhWalZWYXpsV1lYcG5lVlJ1Y0ZaT1ZUVTJW MWhvVUZaR1NrUlVWbFphWlZaQ1dGZHRhR2xUUlRWelZIcE5lR05HY0hCUlZ6bHFUVEZLTlZrd1l6VmxhM1JFVld0a1ZtSkdh M2xVYm5CV1RsVTFObGRZYUZCV1JrcEVWRlpXV21WR1pEWlhiVkpOVVRGS1RsWlhkR3BOYXpVMlZsUldUMlZzYkRSVU1WSlRV VEF4VmxkWVpFeFJNSEJPVmxod1EwMUdVa2RVV0dSclVsaG9WVlJWYUZOVVZsWTJVV3BDVlZKck1UTmFSVlkwVmtVeFNWVnJN VlpsYTBsM1ZrVmFUbVF5VWtabFJsSk9VMFpLVGxaWWNFTk5SbEpIVkZoa2ExSllhRlZVVldoVFZGWldObEZxUWxWU2F6RXpX a1ZXTkZaRk1VbFZhekZXWld0SmQxWkZXazVrTWxKR1pVWlNUbE5HU2s1V1dIQkRUVVpTUjFSWVpHdFNXR2hWVkZWb1UxUldW alpSYWtKVlVtc3hNMXBGVmpSV1JURkpWV3N4Vm1WclNYZFdSVnBPWkRKU1JtVkdVazVUUmtwT1ZsUkNSMlZHVWtsWmVteFJW VEJzZDFNeFVYZFBWa0pZVjIxb2FWTkZOWE5UTVdoNllURlNjMU5zUWs5aGJVMTRWREZTYWsxck1WVmhla0pTWVd0YVNGUlhi M2hpVm14WVpVaHdZVlpJVVRWWlZtUmFZakJ3Ums1V1RsVmxiR3Q2Vkd4U2NrMHdOWEZTVkZaUFVsVnNORlZ0Y0VwUFZrSlZU VlJDYW1Kc1duTlRNV2d3WlZad1dWVnFSbXBpVkZKdVdrVm9TMDFXY0ZWa1JHeGhWak5vTmxkc2FEQmlSbXQ1WVVoYVMxSllh RlJWYm5CYVRUQTFWV0Y2VGs5aGExVXhWR3RXU21WR1NuRlJWemxLWWtWS1NsWkhOV3RYYkZvMlZXMDFXbVZyTlZSVWJHUkxV MFphVldKRmRFNWlTRUY1VjFjd01WVnRVa2RqU0ZKVFlteEtiMVpxVG01TlZsRjVUbFpPYUZJd1drbFVNV2hUVjJ4YVNWVnVV bHBoYTJ0NFZGVldORmRXVW5WUmJYaHBWbXhWZVZaR1dsTlRNbEY1Vm10V2ExSXpRbkJVVnpWdlRXeHJlV05JV21oaVNFSXdW akZTVTFSdFZuSlNhazVWWld0d2FGcEhNVXRrVmxaWlZXMTBUbUpHY0ROV01uQkxZakF4Ums5WVVsUmliSEJ3VldwR1JrMHhU blZpZWtaVFRWZDRXbFpYTVc5aFZrVjNVMnRrV2sxcVZreGFSekZQWTBaR1ZWZHNSbEpsYlhjeVYxUkNhMUl5VWxkUmJrSlNW a2RvY1ZSVVFrdGlNV3gwWWtWT2JHSldTa3BaYTJoUFdWWmFSVkZ1VmxoaVZFRXhXa1prVTFKRk1WaE5WbkJYWld0YU0xZFhk RzlqYXpWMFZXdG9VMkpVYkhCVVYzQkhZakZTTmxOdFJtdGlWWEF4Vmxab1UyRnJNWFJrZWtwWVlrWktNbHBWVlhoa1ZrWnhW V3hDVG1GNlZYbFhWM1JxVGxkV1ZrOVlRbFZYUjFKUFZXdFdSMDB4VWxaVmEwcFBUVWhCTWxSc1dsZGhSa2w0Vm0wMVdHSkhU WGhaVnpGS1pWWldkR1ZIUmxKTlJYQXdWMVphYTA1SFNrWmlSVlpyVFRGd2NWUlVRa3RpTVd4MFlucENVRkl3TVRaVlZ6RnZZ VmRHVmxOcVdtRlNWMmg2V1hwR2QxWlZNVWhPVjBacFZrZDNlRmRyVms1bFIwcFhZa1pvVGxkRlNuQlZNR1I2VFd4d1JscEZa R2xOYTJ3MVZGWmtiMVZGTVhOalJFcGFZbFJXVTFwRlpFNWxWMHBGVjIxR1YxSjZhekJXUm1NeFVUQTFSazlJYkZWaWJIQndW VzV3YzA1V1VYbGlSVGxvWWtkM01sVldhR3RVYkVwR1VsUk9WR0p0T0hkVlJrNUtZMFY0Y0ZGcmFFOWhiVTE0VkRGU2FrMXJN VlZoZWtKU1ZsWnJkMVF3Vm5OUk1VNVhZVVZTV0ZKc2JIWlRNVTVDWkZWd1JtVkdUbE5sYkd0NlZHeFNjazB3TlhGU1ZGWlBV bFZzTkZWdGNFSmlNR3h6VVd0U1VGZElRbkZWYWtKaFRWWldTR05FVW14aVZUVkpWVzAxVjFOc1RrWk9TR1JoVm0xUk1GbHJX a05XUm5CSVRWZHNUbUZzVmpOV1JWcHJXVmRHU0ZOc2FHbFRSVFZ6Vm10b1FtUXhaRmRhUnpscllsVndXVlZzVW10WlYwcFZZ a1JHWVZKVk1UUmFWekZIVjFkT1NHVkdRbWhoTVZreFYxUkNiMkpyTkhoaE0yeFFWMFUxY0ZSVVFuSk5iRTVaWTBWS2EwMUVS a1pWVm1oclZHeEtTVlJ1VmxaU01uaEVXVEJrVDA1V1JuUmpSMnhPVFVoQk1WZHJXbTlSTURGR1pVaEdhMDB4Y0hGVVZFSkxZ akZzZEdKNlFsRlZNR3gzVkhwS1YwNUhSbGxWVkdSdFYwUkdWRlZ0Y0ZwTk1EVlZZWHBPVDJGclZURlVhMVpLWlVaS1ZsZFhP VXBoYkZZeFZGVk9TbU5GT1RWUlV6bFJZVzVqZGxrd1pHOWtNR3hFVld4Q1ZsSlVWbEpWYWtaVFZqRkdjbFJVYkVwaVNHUTBW R3RTUzFrd01WVlZXR2haVWtWVmVWUlVSalJPUlRWeFZtMU9iRkpGTUhsWFJWSmFUVVpvUlZKWWNFOU5XR1EwVkd0U1Uxa3dN VlZWVkVaWlUwZGplVlJVUmpObFJUVlZXa2RPYkZKR2EzZFhSVkpHVFVVMVZGTlVaRkpTTVZsNVYxWmtNMkl3Y0VaUFZrWlZZ a1ZLU1ZacldtRlJNVVkxV2pKc1ZHRXhXbEJWTW5oaFZteFdjazFXWkU1V00yaFhWbXhTUTJReFRYaFdXR1JXWWtoQ1YxVnNX bUZTVmxaeVYyNU9WbFpzYkRSWGExcFhWV3N4Vmxkck1WWldNMUpRVmtWYVQxWnRTa1pUYkZKWFZteFZNVlV4WkRCa01VNVlV MnRvYUZKdVFsaFZiR1F3VGxaYVJWSnNUbXBoZWtJMFZWZDRVMVpIU2xaT1dFNVdZVEZ3ZVZwVldrOVhSMDVKWTBkb1RsZEZT bGRXVnpCM1pVWlJlVkp1VWxwTk1taFdWRlphUzFZeFVYaFdiazVxVFd4YVJsWlhjelZpUjBZMlVtNWtWMUpGTlhwV1ZFcEhZ MnN4Vmxac1VsZFNiSEJRVmtaa01GWXdOVmRhUm1SV1YwZFNiMVp0TVc5U2JGWnpWV3QwVldKV1dsZFpXSEJQVmtkRmVXRklT bHBXTTAxNFZHMTRjMDVzVW5SU2JFNVRZbGhPTTFac1ZtRlVNVTE0WVROc1YyRXhXbUZVVkU1RFV6RnNXRTVWT1dwaVIzUXpW bGMxVDJGR1dsVlNWRXBYVW14S1VGWlZXbUZTYlVZMlZteFNWMDB5WkRaWGJGWldUVmRPVjFSc2FHbFNhMHB6Vm0xMGQyVldX a2RhU0dSVVlYcEdSMVJzVW1GVk1rcFlaVWRHV2xZelFrUlpNRnByVW0xR1NFNVZOV2hsYkZvelZsUkdVMkV4VFhoVWEyaFZW MGhDVmxadGVFdGpiR3hWVW01a1ZGSnJOVlpXYlhoSFZtc3hTVkZ1UmxkU2JIQlVWakl4VW1ReVNrbFNiWEJPWW14S2VWWlhk R3RWTWs1eldraFNhbEpXY0U5VVZWSkRUbFpaZUZWdVRsUmlWWEJLVjI1d1ExWlhTbGxSYmtaYVZteFZNVlJzV2xkalZsWnpZ MFUxYVZKWVFqUldha2w0WkRKRmVWSllhR3BTYkZwUFZXcEtORmRzVm5KV2JGcHJUVlpLV1ZsclZuZFVNREZKVVd0d1ZsWnNT bGhXTWpGSFkyc3hWVmRzVm1saWEwbzFWMnhhVjA1SFRsWk5WV2hwVW0xNFZGVnNXbGROTVZwSVpVVTVWR0Y2VWpOWk1GWnpZ VVpKZWxGdGFGWmhhMFY0V2tWYVUyTldUbk5VYld4VFYwZG9ORlpHVm10ak1XUlhWR3RvV2sweWVGWldiWE14VXpGU2NWRnVa RlJXYkZwV1ZrY3hSMVV3TVZoa2VrSlhVbnBXTTFaRVNrdFdiVlpKVW1zMVUwMXVhR0ZXVkVKcllXMVdjMXBHWkZWaE0wSlFW RlZvUTFOV1drZGhSM1JWWWxWYU1GcEZVbUZYUmxwelUydDRXbFpXV1RCWk1WVjRVMGRLUjJKR1VsTk5helF5Vm10a01GUXhU bkpPU0dScVVsZDRjRlZxU205WlZscHlWbTVLYkZac1JqUldWelZMVkdzeFNXRklhRlZXVjFKNlZqRmFUMU5HYTNwalJsWk9V bFJXVEZaSGNFTmtNVTVYWTBWb2FsSlViSE5aYkZWNFRteFplV1JHVGxoaGVsWkhXbFZvUjFSc1NYbGxSbkJXVFVkU2NWcFdX bEprTVZKeVkwVTVUbE5GU2t0V01XaDNWREZTYzFkcmFGWmlhM0JaV1ZSS1UxTXhVbk5XYWxKcVZsUkdTVmxyV25OV1JrbDVW R3BhVjFKdFVucFZNbk13WkRKT1JtRkdaRmhTTW1odlYxWmtOR05yTVVkVmJrNVdZbXR3VDFac2FHOWxSbEpXV2toT1dGWnJO VWxYVkU1M1ZsZEZkMDVWZEZWaGEwb3pWVEJhVjFkWFNrWk9WMmhwVWxaWk1sWnJXbUZoTVUxNVVteGFiRk5GV2s5VmFrbzBW MnhWZDFwSGNHeFdiRVkwVmtkMGQxUXdNVWxSYTNCV1ZteEtXRll5TVVkamF6RlZWMnhXYVdKclNqVlhiRnBYVGtkT1ZrMVZh R2xTYlhoVVZXeGFWMDVXV2tkaFNFNVVZWHBTTTFrd1ZuTmhSa2w2VVcxb1ZtRnJSWGhhUlZwVFkxWk9jMVJ0YkZOWFIyZzBW a1pXYTJNeFpGZFVhMmhhVFROQ1ZsWXdaRFJUTVZKeFVXNWtWRlp0ZHpKV1IzTXhWakZKZUZOdWJGZE5ibEp5VlRKek1WWnRW a2xTYXpWVFRXNW9ZVlpVUW10aGJWWlhWVzVPVldFelFsQlVWV2hEVTFaYVIyRkhkRlZpVlZvd1drVlNZVmRHV25OVGEzaGFW bFpaTUZreFZYaFRSMHBIWWtaT1UxWnNXVEZXYTFwcll6Rk9jazVJWkdwU1YzaFhWbXRWTVdGR1ZuRlNiazVQVW14S01Wa3dW VFZoVmxwWllVaG9WVlpYVW5wV01WcExVbXhhV1dGR1ZsZGhlbFpNVmtkd1EyUXhUa2RYYkd4b1VqQmFiMWxyWkhwa01WcEla VVpPYW1GNlJsZGFWV2hIVkd4SmVXVkdjRlpoTVZwWFdsWmFVMWRIU2taalJUbE9VMFZLUzFkWGRHdGlNV1J6VjJ0YWFFMHll RlpVVmxwTFpWWlNWVkZxVW1wV1ZFWkpXV3RhYzFVeFNsZFdhbFpYVW14YVVGVXljekJrTWs1R1lrZEdVMDB3U2xGWGJHTjRW RzFXYzFwSVNsWmlTRUpRVld4b2IyVkdVbFphU0U1WVZtczFTVmRVVG5OV1ZscHlUbFYwVldGclNqTlZNRnBYVjFkS1JrNVhh R2xTVmxreVZtdGFZV0V4VFhsU2JGcHNVMFZhVDFWcVNqUlhiRlYzV2tkd2JGWnRVbHBaYTFaM1ZEQXhTVkZyY0ZaV2JFcFlW akl4UjJOck1WVlhiRlpwWW10S05WZHNXbGRPUjA1V1RWVm9hVkp0ZUZWVmFrcFBUbFphU0dWRk9WUmhlbEl6V1RCV2MyRkdT WHBSYldoV1lXdEZlRnBGV2xOalZrNXpWRzFzVTFkSGFEUldSbFpyWXpGa1YxTnJXbGRYUjFKV1dXdFZNVk14VW5GUmJtUlVV bXhhV2xsclZURmhSMHBHVm1wYVYxSnNjSEpWZWtwSFZtMVdTVkpyTlZOTmJtaGhWbFJDYTJGdFZsZFZiazVWWVROQ1VGUlZh RU5UYkd4eVdrYzVXR0pHY0VkWlZFNXpWbFV4VjFOdWJGVldSVWt3V1RGVmVGTkhTa2RpUms1VFZteFpNRlpyWkRCVU1VNXlU a2hrYWxKWGVHaFZhazVEVlVad1dFMVZOV3hpUjFKNVZsZDRkMVF4U2xsaFNHaFZWbGRTZWxZeFdrdFNNa3BGVld4U1YwMHdT VEpYVmxKSFpERmFWMU51VWs1V1ZHeHZXV3hrVDA1R1drVlNiRTVYWWxaS1dGVlhlRk5XUjBwV1RsVTVWMkV4VmpOYVYzaFBW MGRPU1dOSGFFNVdNMk41VmxaYWIyTXhWa2RYYTFwUFZucHNWbFp1Y0VkU01YQkhWMnRPVjFKck5UQldSM014VmpGS2NsZFVT bFpOVjFJeldsY3hSbVZXVm5GWGJIQk9UVzFvVVZaR1pEUlRNazV6V2tab2FsTkZjSEpXYlhSTFZsWlZlVTFWT1dsU2EzQklX VlJPZDFaR1dYcFJhbHBhVmtWd1ZGVnNXbmRUUjFKSVVtMW9hRTFXV1RKV2ExcFRVekZrZEZWc1pGSmlSa3BWV1d4Vk1XTXhW bkpYYm1ScVRWVTFXVmt3YUhkaFJURlpVV3hhVm1KVVFqUldSRXBIWkVacmVtRkdWazVXYTNCWVYydGFZVkV4V2tkVWJsSlZZ bGhvVkZWcVFUQk5WbFY0V2toa2JHSlZWalZXYlhSdlZsZEtXVlZ0UmxWV00yaDVXbGQ0YTJOc2NFZFhiWFJYWVRCd1ZsWlVT WGhVTVZGNVVtNU9hVk5GU2xaVVZFbzBWa1pTVmxaVVFteFdiRm93VkZaVk1WWXhTWGRPUkVwWFRXcEdlVlJWVlRWV2JVcEpW RzEwVGsxdGFGRldWM1JoWXpKT1IxVlljR2xTYXpWUFZGVlNWazFzVm5OVmF6bGFWbXRzTkZVeU5VTldWVEZXVFVoa1ZVMVdX bnBaZWtwWFVsWldjazlXWkU1V00yZ3pWbXRTVDJNeFZYbFZXR1JRVm0xb1ZWWXdhRU5VTVhCWVRWVTFUbFpzU2xsWldIQkRW VVphV0dWSWNHRldWa3BVVmtSS1YyTXhTblZSYkZaT1RXNW9WVmRXWkhwbFJrcFhWR3hXVjJGNlZrOVpWRVphVFZaWmVGZHJO VTVTVkd4WFdXdG9UMkpHU2tkVGJFSmFZa1p3U0Zrd1dsSmxiVXBIVkdzNVYySllhRnBXVjNodll6RlJlVkp1VW1wbGExcFdX VzB4ZW1ReFVYaFdiazVxVFd4YVJsWlhjelZoVmxwMFpVaGtWMUpGTlhwV1ZFcEdaREF4V1ZKc1VsZFNWWEJSVjJ4a01GbFhU a2RhUm1ob1pXdEtVVlpzWkRSbGJIQkZWRzA1VldKV1dqQldSelZEVmxVd2VXVkdVbHBoTVZZMFZqQmFhMVpXVG5OUmJFNVRZ a1pXTkZaclpEUlVhekZHVDFaYWFWTkZOWE5WYTFwTFZVWnNjMWR1VG1wU2JFWTJXV3RhVDFSck1VVldWRXBXWWtaS1VGZFdX a3BsUms1MVVXeFdUbFpVUWpOV1JFWlhZekpOZVZaclZsWmhlbXh6V1ZSS05HUXhXa1ZVYms1V1RVUldTRmxVVG5OV2JVcFpV VzFvV2xaNlJsUlpNbmhyWXpGU1ZWRnNRbGRXTTJnMlYydG9kMU14VVhoU1dHUm9aV3MxVlZsVVNtOWxiR3hXVjI1T1YxWnJO VlpWTW5oRFZqRkplbFJxV2xkU1YxSXlXa1JLUjFZeVJrWldiRTVYVWxWd1VWWldVa05qYXpCNFZHNUtZVkpyY0hOV2JGSkha VVphVjFWck9WVmlSbXd6V1RCb1ExWldTWGxQVkU1YVZteHdkbFV4V25kT2JFNXlUMWQ0VjFZelRqWldWRW93WVRGU2RGVlla RTVYUlZwdlZGUk9RMWxXV25KV2JtUnBUVlpLU1ZscVRtdGhSbHAwWVVWd1dHSnVRbEJXUjNoR1pESkdObFJzVW1oTmJXaFVW a1pTUjJReFRrZGFSbXhvVWxSc2MxbFljRmROUmxwR1draGFhMDFyV2xoWlZWWlhWVEZhUmxkc1FsWldSVXA1VkZSR1QyTnNj RWRYYlhoVFltdEtORlpxUmxOVk1WRjRWMnRvYWsweWFGWlZha2sxVFRGc1YxZHRPVlJXYmtFeVZrZHpOVlZyTVVoak0zQldU VzVTZGxaWGMzZGxSMDVHWVVab1dGSXlhRkZYYkdSNlRWZFNSMVZyYUdsTk1sSnZWbTB4YjFOc1pIVmpSWFJWWWtaV00xbFlj RTlXUjBWNVlVaGFXbFl6YUROVk1GcFRaRVV4Vms5Vk5XbFNXRUkyVm10V2EyUnRVWGxTYkdSb1VsWmFWRll3YUVOVlJuQlhW bTVLVGsxVk5YbFpWV1IzVkdzeFJWSnNXbGhoTWxGM1YxWmFTbVF5UmpaU2JGWlRUV3ByZWxkV1dtRmlNVXBYVTJ4V1VtRjZi RmRVVldSNlpXeFZlV1JIZEZaaVZscFhWRlpvUjFac1drWk9WVGxYWVd0S00xa3dXbE5UUjBsNldrZG9WMkpYYUVkV1YzaFRV VEZSZUZaWVpHaGxhelZWV1ZSS2IyVnNiRlpYYms1WFZtczFWbFV5ZUVOV01VbDZWR3BhVjFKWFVqSmFSRXBIVmpKR1JtSkhS bXhoTTBKUlZteFNRMk5yTUhoVWJrcGhVbXR3YzFac1VrZGxSbHBYVldzNVZXSkdiRE5aTUdoRFZsWkplVTlVVGxwV2JIQjJW V3hhUzFaV1RuSlBWa3BPVWpOT05sWlVTakJpTWtaeVRVaGtUbFpzV21oVmFrNVRZVVpXY1ZGdVNrNVdiRXBKV1dwT2EyRkdX blJoUlZwV1lrWktURlpIZUVaa01rWTJWR3hTYUUxc1NsaFhiRlpoWkRKT1YxcEdWbFpoZW14WVZXcE9UMDVHV2taYVNGcHJU V3RhV0ZsVlZuTlpWVEI2VVdzNVYxWkZTbmxVVkVaUFkyMUdSMU5yTlU1WFJVcEtWbXBHYjJJeFVYbFdia3BQVjBaS1ZsVnFT VFZOTVd4WFYyMDVWRlp1UVRKV1IzTTFWV3N4U0dNemNGWk5ibEoyV1dwS1IyTXlUa1poUmxacFZrVmFVVlpHWkRSVE1rMTRW V3RvYVUweVVtOVdiVEZ2VTJ4a2RXTkZkRlZOVlZZeldWaHdUMVpIUlhsaFNFWlZWa1ZHTkZac1duZFRSMUpJVW14T1RsSXpU alJXYTFaclpHMVJlVkpzWkdoU1YzaG9XbGQwZDFsV2NGZFdia3BPVFZVMWVWbFZXa3RVYXpGWlVXdHNWMDFYYUhaV1JFcFhZ MnMxV1ZWc1ZsTk5hbXQ2VjFaYVlXSXhTbGRUYkZaU1lYcHNWMVJWWkhwbGJGVjVaRWM1YVUxclducFpNRlp2VmxkS1ZWSnNR bFZXTTJoTVdYcEdVMU5IU1hwYVIyaFhZbGRvUzFZeU5YZFRNVkY0Vmxoa2FHVnJOVlZaVkVwVFZqRndWbGR1WkdwV2JWSldW bGR6TlZZeFNYcFVhbEpYVWxkU01scEVTa2RXTWtaR1lrZEdUazB3U2xCWGJGcFhZMnN3ZUZSdVNtRlNhM0J6Vm14U1IyVkdX bGRWYXpsVllrWnNNMWt3YUVOV1ZrbDVUMVJPV2xac2NIWlZiRnBMVjFkT1JrOVhlRmRXTTA0MlZsUktNR0l5Um5KTlNHUk9W bXhhYUZWcVRsTmhSbFp4VVc1S1RsWnNTa2xaYWs1cllVWmFkR0ZGV2xaaVJrcEVWa2Q0Vm1ReVJqWlViRkpvVFd4S1ZGZHNX bFpsUjA1WFZteFdWV0Y2VmxoVVZXaERaREZhUmxwSVdtdE5hMXBZV1ZWV1YxVXhXa1pUYXpsaFZteGFlVlJVUms5amJVWklU MWRvYVZORlNrcFdhMk4zWlVaUmQwMVlUbFJpYXpWV1ZXcEpOVTB4YkZkWGJUbFVWbTVCTWxVeWN6RmlSbHBZWXpOd1ZrMXVV bkpXVnpGWFZtc3hXVkpzV2xkU1ZGWlFWbTF3UTJReVRrZFZhMmhwVFRKU2IxWnRNVzlTYkZaelZXdGtWVTFzV2xkWldIQlBW a2RGZVdGSVdscFdNMmd6VlRCYVUyUkZNVlpQVlRWcFVsaENObFpyVm10a2JWRjVVbXhrYUZKWGVHaGFWM1IzWVVac1YxWnVT azVOVlRWNVdWVmtkMVJyTVVWU2JGcFlZVEpSZDFkV1drcGtNa1kyVW14V1UwMXFhM3BYVmxwaFlqRktWMU5zVmxKaGVsWnpW bXhrZW1Wc1ZYbGtSM1JXWWxaYVYxUldhRWRXYkZwR1RsVTVWMkZyU2pOWk1GcFRVMGRKZWxwSGFGZGlWMmhIVmxkNFUxSXhV WGxTYkZwb1pXczFWVmxVU205a2JHeFlaVWhrVkZKc1NqQlVWbFUxVkcxS1JtTkljRmRTVjFJeVdrUktSMVl5UmtaV2JFNVhV bFZ3VVZaV1VrTmphekI0Vkc1S2FGSXpRazlVVlZKSFZteGtjbHBFUWxwV2Eyd3pXVmh3UjFaV1NYbFBWRTVhVm14d2RsVnNX a3RXVmtaeVQxWmFUbEl6VGpaV1ZFb3dZVEZXZEZac1drNVhSVnBYVm10Vk1WUXhXbkZSYm1ScVVteEtTVmxxVG10aFJscDBZ VVZhVm1KR1NreFdSRVpHWkRKR05sUnNVbWhOYldneVYxWmtOR1F4VGtkVmJsSk9WbFJzVDFsclZuZGxiRnBHV2toYWEwMXJX bGhaVlZaeldWZFdjbU5HUWxkV1JVcDVWRlJHVDJOc2NFZFRiWGhYVmtWYU5GWnNXbE5VTVZKelYxaGthbE5GU2xaVmFrazFU VEZzVjFkdE9WTldhM0JXVlZkek5WWnJNVWhqTTNCV1RXNVNjbFpYTVZkV2F6RlpVbXhhVjFKVVZsQldiWEJEWkRKT1IxVnJh R2xOTWxKdlZtMHhiMUpzVm5OVmEyUlZUV3RhVjFsWWNFOVdSMFY1Vld4T1lWWnNWalJaTVZwWFZsWlNjazVXWkU1VFJVb3pW bXRXYTJSdFVYbFNiR1JvVWxkNGFGcFhjekZWUmxaVlVXNUtUazFWTlhsWGExcExZa1phVlZKdWFGZFdiRXBRVmtkNFdtUXlU a2xSYkZaVFRXcHJlbGRXV21GaU1VNVhZMFJhVldGNlZuTldiR1I2Wld4VmVXUkhkRlppVmxwSFZERldWMVl4V2taalJUbGFW ak5vYUZwRldsZFNNVkp6VkdzNVYySllhRnBXVjNodll6RlJlVkp1VW1wbGExcFdXVzB4TkdSV2JGZFhiVGxUVm14d1dsZHJW bmRoUm1SSVlVaFNWMDFHU2tSWFZscFBZekZXY2xkc1pHbFdia0poVjJ4YWEyVnJNSGRpU0VacVRXNVNXVlZzVWtkU01WbDVZ M3BXVTFack5VZFZNbmhMVmxVeFJtTkZUbGRTUlZwTVZYcEdZVkpzVm5KV2JHaFhZbFpLYUZaV1dtRlJNVlp6VjI1S1ZXRjZW bGxWYTFKRFkwWmtSbFZyV2s1U1ZFWjZXa1JPYjFReFNrWlhiWEJWVm14S1lWcFhlRzlUVm5BMlUyczVWMkp0WTNkV1JtaDNX VlpyZDA1WVJsWmlWVFZQVm10VmQyVnNaRVpWYTFwT1VsUldTRnBFVG05VU1VcEhWMjF3WVZaV1NtRmFWM2h2VWxaS1ZWSnJP VTVYUjJOM1ZrY3hkMVV4YTNkTlZsWldWa1ZhUzFsWE5VOWpiRnB4VW14T1ZVMVhVbGhWVjNSelZrWmFWMU50YUZaV1JWcE1W VEo0VjFJeFRsVmlSWEJwVTBkamQxWkhNWGRoTVd0NVZtdFdZVkpWY0ZwVk1HUnFaVlpSZUZkcVVrOVNWRlo1Vm0weFQySkdT a2RoTTJ4WVVsZG9kVlJYZUVabFIxWkZWV3M1YUdFeGNIRlhiRlpUWVdzeFIyRkZiR0ZsYTNCUVZsUkNjazB4VmxaYVJtUk9Z a2Q0V1ZwRVNUVlRiVVp4V2pOS1ZGWXljM2RaVkVaYVpVWldjazlXYUZkaE1IQkxWbFJHVjFVeGJGZFNXR2hVWVROQ1YxVnRk SE5rYkZKSllraGFZVTFJUWtoWmExWXdWa1phVm1ORmRGZFNiSEJJVldwR1QxSXhjRFppUlhCcFZsZDNNVlpHV210VWJWRjNU VlpXWVZJemFFOVpWM04zWld4a2RHTkdTazlXYmtKSlZrWm9kMVJzV2tkWGJrWlZWbTFTYUZsVVJuTmtSa3BWVTJ4d2FHSldT bmxXUmxaVFZHc3hWbUpJUm1wTmJWSk5XVlpTYjJOc1dYZFdXR2hUWWtkU2VWUXhWbGRXUmtwV1kwWk9WMUpGU2t4VlYzaFNa VVpPY21SR1pGTldhM0JIVm1wR1lXRXhaSE5TYkdSU1lrVndXRmxVUVRGVU1WbDNWRzAxYUZZeFNucFdNalZQVkRGWmQyRjZS bUZTVmxwNldsY3hVMk5YUlhwWGJVWk9WbFZ3TlZaclVrTmhNbEpHVFZWa1lWSXlhSEpVVlZKV1RVWndWbFp0Um14aVJUVkpW VEo0UzFsV1duUlBTR3hYVWxad1VGcEhjM2hrVjA1SllrWm9VMVpXVmpOV2ExcGhZVEZhUjFwR2FHdFNiSEJVVld0YVlVMUdi RlZTYkU1c1lrWmFTVll5TUhoWGJVcHpWMnBTV21KSGFETmFSRXBPWlVkT1NFMVdUbE5OVm13MlZUTndRMk15VFhsU1dHeFZZ a1pLYjFsWGVITk5iRkp6VjIxR2FFMVhVa2haVldoUFlrWktSMk5GVWxoV00wSkRXbGR6TVU1Vk9VVlViR2hvVmtkME0xWnFS bTlaVjFKSFUycFdVRkpGV21GV2EyUXdUV3hrV0dOSFJtaGlSa3BHVlcxNFEySkhSWGxsUlU1VllrWndVRlpXV25ka1JscDFW bXQ0VGxKc2NGSldSbHB2VmpGV1NGVlliR2xTVkVaVlZUQmtOR0ZHYTNsT1ZUbFZWbXhhVmxscldrTldWMHBWVmxod1lWTklR bkpVVjNoWFYwZFdSazlWTlU1aWJWRXlWMWMxZDJJd01YSmtNM0JTWVRGS1VGUlVRbFpsUmxwMFpVYzVWbFl4V2twWmFrNUxW bXhLY2xOclVsZGlSMUpvVkZaYVlXUkhUa1ZSYkU1WVVtdHZkMVpyWkhwTlJURllVbGhvVW1KdGFITldhMlJ2VFZaWmQxZHJU bXROVlZreVdXdFZlR0ZYVm5SVmExcFhWbGRvUjFSc1dsSmtNRGxaVm1zNVZGSlVWazlYYTFacVRWWlplVk5yWkZSV1JWcFVW bTAxUTFkc1VsbGpSVnBPVm0xNE1WVXlNVEJVTWtwWVQxUktWVTFXVlRGV1ZsWXpaREZ3Um1WR1drNVNhMVkyVjJ4YVYxWXdO VlpQVlZwcVVteGFVRlJVU2xOT2JGcFdWV3R3YkZac2NIZFVNVlUxVmxaYVJtTkZNV0ZXTTBKUVZHdGFhMWRXUm5OalJrSlRU V3MxTlZZeU1IaE5SbVJJVld4b1ZHRXpVbFJVVnpFMFRWWlJlRlZyV210aVIxSkdWV3hvYzJKR1NYaGpSVFZZWVRKb1QxcFdW VEJrTWtZMlZHMW9UbEpzY0UxV1ZFSmhVakZOZVZKWVpGcE5NbEpZV1d4YVMwMXNVa1ZUYWtKVFVqQTFlVnBWYUVkWFIwcElX bnBHV0dKRk1ERlpNakZUWTFkS1JrNVhSbXhoZWtGM1YxZDRWMU15U1hsV2JHUlZZbTFvVVZadGRHRlhWbXh6VjIxR1ZWSnVR bGxXUnpWTFZqQXdlRmRzVmxkTlYyaElWR3hhYTFZeFRuUmxSbVJwVjBVeE5GWkhkR3BsUjAxNFZteGFXR0pyTlZsWmJHUlRV VEZXTmxOdVpFNU5iRXA2VmpGb1lWVXhaRWxSYlVaaFZsZFNWRmxVU2twbFJtUjBVbTFHYUUxV1dYbFdNV1EwWWpKS1ZrOVdi R3BTTTFKWVZGZDBkMDFzWkZoTlNHaFhZa1phTUZaV2FHdFVNREZIVTI1b1YwMXVRblZaTW5oVFZtMUtTVlpyTlZkbGEwa3lW MVpXVjFkck1WWk5TR1JZWVRGd2FGWnJaRzlVUmxwelZXeE9hRkl3V2pCVVZsWjNZa2RLV0ZWcVZscFdSVnBZVmpKek1WWlhS a2hsUmxaT1lXMTRXVmRZY0VOa01sWklVMWhvVm1KdFVsbFdha0V4Vkd4V2RHVkZXbXBpUm13elZrZHdSMWRHV1hkWGJsSlhU VWRTVkZWNlJrOWpiVXBGVW14S1RsSldjRXhXVkVKWFVqRktkRkpZYUdGU2EwcFpWbXhvUTFFeFVuTldiWFJXVFZaYVdsWldV a05XUjBwelVtNXNWMUpGTlV4Vk1qRkdaVlpXZEU5V1VsTk5NazQwVjJ4YVUyRXhWWGhUYmxKVFlUTkNiMWxVU205alZscEhW V3hrVjFKck5WbFdiWGhIVjBkS1ZtTkdaRlZOVjFKVVdWVmFkMU5IUmtWVWJHUnBZVEowTkZadGVGTmpNazVYVldwV1VGWlZO VmhWYkZKR1RXeGFTR0pFUW10TmExcEdWbGR3VTFac1drZFNWRVpXWWtkUk1GUnRNVmRUUjA1R1ZtMXdhVmRIVWpWV1ZtaDNZ bTFXUms1VldsaGlWRVp4VmpCV1MySXhXbFpYYkdSWFVqRmFTVlp0ZEd0V01rcHpVMnRPWVZaWGFGUldWbFV3WlZaS2NWSnJO Vk5OTURCM1ZtcEdWazFXV2toVmJrWnBVbGRTV0ZsclpEUlNSbHB4VW14a1ZFMXNTVEZVTVdONFZqSkZlVlZZYUZwaE1sSklX a1JLVG1ReVRrZFhiWGhYWWtoQ1dsZHJVa2RaVjBaelYyNVNZVkpWY0hGWldIQlRUVEZzY21GSVRsVlNNSEJZVm0xMGQxWkdT bGxSYTNCYVRXNW9TRlp0ZUVabFYwNUhVV3hDVkZKdVFucFhWM2hoVWpKV1JrMVZiRlJoZW14dlZXMTRTMlJXV2xaV2JFNVdW bXRXTmxsVlZqUlViRXBYVjJ4Q1ZVMUdjRkJVYTFwclZqRmtXVnBIYkZkTmJFcFFWakZTVDFack5WZGlTRlpVVmtWd1dGbFVT alJXUmxsNFZsaG9UbFl3YkROVk1uUTBWMGRLVlZvemFHRlNNMmg2VmtaVk1HVnNVbkppUjBaWFZsUldWbGRyVWtkak1ERnlU bGhHVjJKcldsWldibkJ6VWpGYVNHVkZaRTlTYkhCNVZrZDRkMkZWTVZaWGJIQllWa1ZyTVZscVNsTlNiRnAwVGxaV1RtSllh RWxYVkVwM1ZqSldXRlZzVmxKaGEzQlVWbXBLTkdNeFVYZGFSMFpYVm10d2VWUlZhRzlVTVU1SlVXeENWbUV4U25KWmJYTXhW MVp3UjFac1VrNVNlbXQ1Vmxkd1MxbFhTbk5XYkZwc1VucFdUbFJWVm1GVE1XUlZWR3RrYW1KVlduZFVNV014VjJ4a1JsTnFX bHBoTVVwMldWZHplRkpzVW5WUmJHUlhUVEJLTkZac1VrOVRNVTVZVm01T1ZXSllVbk5WYlRGVFZWWnNWVk50UmxaV2ExcFlX V3RrZDFVd01IbGtla3BZWVd0YVZGWXhWak5rTVZweFZtMTRVMUp1UWxWWGJGcHFaVVpTYzFkcldsTldSbHBvVkZWU2MxSldh M2hXYWxKVlZqQndWMVZ0ZUdGV1IxWlpWV3hHV0dFeFNtaFdha1poWTIxU1JWUnNVbWxXTW1oNVZtMTBVMVJ0VG5KUFZsWm9U VEZ3Y2xaclpHdE5NV3Q2WTBkd2EwMUlaRFpWYlhoWFlVWkplVTlZYkZwTmJsSllWRzE0WVdOV1RuTmpSa0pYVWxad2VGWnRN WGRoYXpGSVZHeGFUMVl6YUU1YVZsSnpaVlphZEUxWVpHbE5iRVl6VlRKNFlXSkdTa2RYYWtwVlRVZE9ORnBFUVhka01YQkpZ a2RzVkZORlNsZFdiRkpMWkcxV1YxZHFXbEpYUjNob1ZsUk9VMlJXYTNoV2F6bHBUVmhDU1ZsVlVsTlVNREZaVVc1b1ZrMUhV ak5aVlZwTFYwZFNTRTlXVmxOWFIyTjNWakp3UzFNeFdsWk9XRlpZWW1zMWNGWnJXbmRrVmxaMVkwZEdhRkpyV2pCVmJYaEhW REF4UmxaWWNHRldiSEJNV1RCYVUyTnRTa2xpUm1ocFlsUnJlVmRzV2xkak1sWnlUMVphVDFOR2NGbFdiWGhoVFVaYWNtRkZP VlJOVmxZelZUSjRhMVJ0U2xsUmEyUlhZVEpTV0ZkV1drdFhSVEZZWkVad1YwMXRaekZYYTFKRFZUSlNWMkpJUm1oU2JGcFdW V3BLVTAweFdYZFVibkJQVmpCd1dsWnNVbGRoVlRGWVpVZEdXbUV5VWxCWmFrWkhZMjFPUms1WFJrNU5SRlpLVjFab2NrNVdW a2RVYmtwc1VrWmFVMVJWWkc5VFZteDBaRVprV0ZJeFdscFdNbk0xVkd4T1NGb3piRmhoYTBwNVdsVmFTMUpzYTNwWGJFcFhW bFpXTTFaWE1UQlhiVkY0VjJ4YVVGZEhlSE5WTUdoRFVteHNXR1ZGT1ZOTlZUVktWMnBPUzFkR1NsVmlSbFphVFROQ2RsVnFT a3RXTWtsNlUyeFdVMVpyYTNsV1YzUlRZekZaZUZSclZsUmhiRnB4V1ZST2IxUnNiRmRVYWtKcVRWWmFTVlJXWTNoVWJHUkhW MnRzVjJGck5VUldWV1JMVmxaYWRHRkhiRmROTUVwWVYxUkdUMDFHWkhSVWEyUlVZbFJzVlZwWGMzZE5WbEY0V1ROb2JGWnJW ak5XVm1oclZEQXhjVkZVUmxwV01uTXhXVmQ0WVZaV1NuRldiR1JYVWpOb1RGWnNWbTlaVmxaV1RraGtUbFo2Vm05VVZ6VlRZ MFpXYzFkck5XeGlSV3cwV1ZWV2QxVXhTbGRTVkVaYVRXNVNkbFZ0TVV0ak1XUlZVV3hDVjAxc1NsTldhMVpYWVRGU1dGVnVU bEpoTUhCV1ZGWmFZVlpHYkZobFJuQnNZWHBzV2xscVRrdFdSMFY1WlVoU1YwMXFRalJXUkVwSFUwZE9TVlJzU2xkU1dFSXlW VE53U21WRk1VWk9WV3hoVFROQ1dGbHRNV3BOVm5CRlVtczVhRTFzV2tkVU1XaExWMGRLZEZWclRscGlSbkJ4VkZkNFIyTldX bFZSYlhScFVteHdSMVpHWkRCVU1sSllVMnRvYWxKck5VOVpiVFZEWXpGa2MxcEVUbXBpVlZwSFZUSTFUMkZ0Vm5OaU0yaFhZ VEpTVEZWcVNrZGtSbHBWVm14Q1ZGSXlaRFpXTVdRMFl6RmtkRlJyVmxSaGF6Vm9WakJXZDJOc1draGtSVGxPWWtkME0xcEZW bmRXTWtwV1kwUldWMkV5YUVoV1ZtUkhVMFprYzJGSGVGZGxiRnBXVmtkd1IyUXlSbk5hUldSU1ZrWmFWRlJYY0ZaTlJscEpZ MFZ3VGsxV1NsWldNblJUVmxaYWMyTkZNVlJsYTJ3MFZHdGFhMVpyTlZWVGJGcG9ZbGRqZUZZeFdsTlJiVkY0VjI1S1RsZEdX bFpaYkZwMlpERldjbUZJVGxkV1ZGWllXVEJTVTFaWFJuTmlNM0JhWld0ck1WUnJaRTlUVmtaVlUyeFNhVmRGU2taWFZsSkhV bXN3ZUZkc1ZsZFhSbkJXV2xkNGQxbFdWWGhaZWxaclRWWndXVlpITld0aVJrbzJZa1phV0ZadFVuSlpla1pMVjFad1NWVnNW bGRXTVVwb1YxUkdWazFXUlhoU2JrNW9VbGhTVDFsc1pHOU5WbEpYVjJ4YVQxSnNWalpWYlhSVFlWZEdjMWRxVWxaaVZGWkRX bGQ0YzFZeGEzcFhiRnBYVWpGS05WWkZhSGRpTWtwSFYyNVNUMU5GY0hKVVZ6RjZUVlpzZEdSR1dteGlSVFZhVlcxNGIxUlZN VmRUYkdSWVZucFdjbGt4V2xkak1WWjBUbFpDVjFacmNIbFhhMUpMWVRGU1YxUnVWbWhTYTNCT1dsY3hiMDVXWkhOWGJFcHNW akExUmxsVldsZFVNREZXVWxSQ1YySkdTa2haYWtwTFUwWndSVlZ0ZEU1V01VcEhWMnRhVTFFeFRsWk5XRTVXVmtWYWNGUlVT bTlOUmxaWVpVYzVhbUpWY0VoWmExcFhWREpGZVU5VVdsWmlSbHAyVmtSR2RtVlhVa2xUYlVaVFRVWndWMVpzVWtOaE1WWkhW bXBhVW1FelFtaFphMVozVmpGc1YxcEdXazVOUkZaSVYyNXdWMVZ0U2tkU1dHaGFUVmRvU0ZaVVNsZGpWa3B5Vkcxd1RsWllR bEJXUkVaaFZqRmtSazFJY0ZKaVZFWlFXV3RrTkUxV1VuUmtTR1JYVWpCc05sbHJZelZVTVZwV1lrUk9WbUZyU1RCWk1WWTBU bXhrZFZKdGJFNVNSVnBXVmtjd2VHRXhUWGROV0U1VFYwZG9XRll3WkZOWlZtUnlWMnR3VDFack1UUlpXSEJMVjJzeGMxTnRP VnBXTTBKRVZGZHpNV05zV25OVGJFNXNZVEJ3UlZkWE1YZGliVlpXWkROb2FGSllhRTlhVnpGdlYxWnNjbHBHU2s1U2JrSmFW VlpvWVZVeVNsZGpSbWhhVmtWc05GUnRNVmRXYkZweldrWkNVMkV4YnpCV1YzUnZVVEZhYzJORmFFOVRSM2haVlRCb1EwNUdW bkpYYlhSWVZsUkdWMVJXV2s5Vk1WbDRWbGhvVm1KVVZsTlVWRVpYWXpKRmVtRkdWbGhTVkZJelYxWmtkMWxXV2tkVWJHeGhU VEo0V0ZadWNITk5SbXQ1VFZaT2FFMVdXbGhXUnpWelZrWktjazVWVmxkTlYyaDJWbTE0YTFkRk5WVlNiRTVwVmxSV1VsZHJV a0pPVjBsNFZHdHNhV1ZyY0ZoVVZ6QTFUa1p3V0dGNlZsZE5hM0I1VkRCb1lWWldXbGhsUm1oWFZrVndWRlY2UmtkWFIwcEhW MjFvVTFKc2NHOVhWbU14WVRGV1dGSnVTbXhTUlhCUFZXeFNSMDFzYkZoTldFNU9VbXMxVmxac1VrZFpWMHB5VTI1S1YxSkZS alJhVjNoT1pXeHdTVmRyT1dsU01Va3hWa2R3VDJFeVVuSk5XRkpXWVRBMWNGbHNVa1pOYkZsNFlVVTVhRlpzY0VkVk1qQjRW VEZhUmsxSWNGZE5ibWhFV1d0a1UxTkhSa2RYYlhSb1RWYzVORlpzVWtOa01XUlhWbXRvVkdGNlZsUldNR1JQVFd4V2NscEZP VmhXTVZwWFdsVm9ZVlJ0U25OVGEzaFhVbTFTZGxVeU1VOWpWbEp6V2tVMVRsWllRbFZXUnpCNFZESk5lR0pJVGxkaVJWcG9W bXBLTkZac2JGWlhhelZQVmxSR2QxcEZhSE5XVlRGSlZXMUdXbUV4V2pOWmEyUlBVMVpLV1ZwSFJtbFNXRUpoVmpJd2QwNVhU WGRQVm1oc1VtdGFiMVJYY3pCTlJscEZWR3M1V0dKVk5VaFdWelZ2VkcxS2NtTkdRbFZpUjAxNFZrVmFjMk14VW5OVmJFNVNa VzEzZVZaR1pEUmlNVTVXVGxoV1dHSnJjRmRXYkZwWFRteGFjVkp1VG10aGVrSTFWVzEwYjFVeFZqWmhSRXBZWWxSV1ZGWXll R3RqTVhBMlVXc3hiR0pYYUZKWFZscFhZekpTZEZSdVJsaGlWVnBXV1Zod2MwMVdVbkZSYkU1c1ZqRktWMVJWYUhOaVJrcFpZ VWhPVldKSFRqUldhMlJUVTBad1NWRnJOVTVpVlRCM1ZsaHdRMWxYVm5OVGJGcHFVbnBHY0ZadGN6RmpSbXh5V2toa1RrMXJO VEZaTUZwcllWWmFSMWRxV2xkU1ZUQXhWbTB4VW1WR1RuRlNhemxUVWxSV01sZFdWbE5oTWxaWVZtdGFhRkpHU2xsVmFrWjJU V3hWZDFwR1NtcGlWbHA0VjJ0U1IySkdTbkpPVkVKaFVrVnJNRnBYZUVabFZrNTFWMnh3YkdKWWFGWldha3AzVjJzeFYxSnVT azlUUjJoVVZXeGtiMWxXVmxWUmFsSldUVVJDTkZaWGNFdFZSbHAwWlVaU1YySkhhRE5aTUZwVFUwVXhXV0pIUm1oaGVsWkxW bXRqTVZZeGJGZFdhMnhXVmtaS1ZsbHRNWHBsUm1SWFZtdDBhRTFzU2xoV2JYQkhZVlV4ZEdWR2JGaGhhelY2V1ZSS1VtVnNa SFZUYkZwb1RUQktXbGRYTUhkbFIxWnpWVzVPV0dKR1dsRlZiWFJoVm14VmVXUkVVbFpXV0dRelZsZDBVMVpYUlhoVGJFNVlZ a2RTV0ZSc1ZURldWMFkyVkcxR2FXRjZSVEZXUkVaaFVqSkplRlZzYUZkaGJGcFpWbXRrVTFWV1VuUmpTRTVZVWpBMVYxUnNa REJVYkVsNllVVjRWVk5IY3pGYVJXUkhWakZTY21SSGFHaFdSM2haVjFSS01GbFdXWGhYYTJ4WVlrZG9jVlZzWXpWTk1WSnlX a2M1VmxaVWJFbFdNbmhoWVRGS05tRXphRmRoTURSM1ZYcEdZVkpzVGxsaVJuQnBZbGRvYUZaSGVHdE5SbEYzVFZaa2FWSkZX bkJXYWtaV1pXeHdSMVZ0T1ZWU2JGcEdWVmR6TlZkdFNsZFRhbFpWWWtaYWRsUldXbGRrVjA1SVpVWmFhRTFzU25sWFZFWmhZ V3N4ZEZWc2FFOVdlbXh6V1d0V1MxbFdXa1paZWtaVlZqQTFlbFp0ZEZkWGF6RldVbXBXVjAxdGQzZFdWekZQVm1zMVdXSkhS bWxpVjJnMFZtMTRVMVV4U2taT1dGWm9Vak5vY0ZacldtRlNWbFpZVFVSR2FVMXNTbFpaVldNeFZHMUZkMWRVU2xoaVdHaDJW RmQ0WVZOV1JuTmpSMmhUWWxob1NsWlVUbmRqYlU1eVRsVm9VRll6YUZsVk1HUlRVMnhSZUZadVpGZGlWa3BHVlRKNFQxWlZN VmxSYkhCWVlrWndjbGRXV2xkalZsSnpZMFpDVTFkR1NrdFhWRUpXWlVkR1dGUnVUbGRpYkZwVlZXdGtORlJzY0ZaV2FsSlBV bFJTTmxadGNFZFViVVpWWWtSR1YxZElRbEJWYTFVeFpGWmtjMVpyTldoTlZtOTVWbXhqZUUxR1VrZGpTRXBVVjBkb1VWWnRN Vk5YUm14VlVXMUdhMDFWTVROYVZWcFBWVEZhVjJOSFJscGlSMmhVVlhwR2ExTkdVblJoUmtwcFlrWndkMVpXVWtKT1YwcEhV MjVHVkdKR1duSldibkJUWlZaT05sUnROVTlTYkhCSVYydGtORlpXV2toaFJFcFdWa1UxWVZSc1pGZFhSVEZaVjIxd1RsSlVS VEJYVm1ONFZURldjbVF6WkZaaGVsWldWbXRhUm1WV1dsWldiVVpWVFZVMU1GUXhXbE5oVjBWNlVXcFdXbUpIVGpSVmFrWnpZ MWRHUmxack5XbFNWRlo1VjFaa01FNUdSbk5VYTFKclVrVndjVlJYZUV0a2JIQkZVbTVLYTJKVmNIbFVhMUpYVmxkV2MxWllj RmRXZWxaRVZqRlZNVmRXVm5WaVJUVlVVbGQzZVZaRVJsTlRhekI0V2toV1lVMHlVbk5aYTJoRFkyeGtWVkpyV2s1V2JGcDRW bGQwVDFSdFNrWk5XR3hYVFVad1dGcFdXbUZXYXpGRlUyMTBWMUpyY0hsV1JFSmhWVEZhV0ZWdVZtaFNWMUpYVld4YWQxTnNW WGxoZWxKcllraENTbFV5ZUhOaVIwVjRZak53VlZOSVFuWldSM040VmpGV2NWTnJOVk5TTTJoaFZtcEdZVll4V2toVmJHaHJa V3RLVkZac1VsZFNNVnB4VW10S1QxSnRlSGhaVlZaUFYwWmFWMk5GY0ZkU1YyaFlXVEZrVjFJeFZsbFhiWFJPVmxSV05WWkdW bTlrTURGelZteGFhbE5HV2xOWlYzaGhVbXhTV0UxSVpFNWlWVnBKV2tWV2QyRXlSbk5qUlhSVllsaG9lbGt3V25kV1ZrNVZW V3hrVG1KR2NFcFdWelYzVmpBeGMxZFlaRlpoTUhCV1ZWaHdiMDB4YkZkaFNFNVhWakJzTlZSclVrZFpWa1kyWWtWNFdtRXlU VEZhVjNoUFYxWmtkR05GTlZkaE1YQlpWbFphVmsxV1drZFVXR3hWWVROU1ZsbHJXbUZrYkZweVdUTmthMkpGTkRKWlZWWlBW akZPUjFKWWFGZFdNMUo2V1hwR2RtUXlTa2hqUmxKWFYwVktlbFpFUW1GVU1rWnpZMFZzYWxOSGFGZFpWRW8wVVRGcmQyRkZk RmRXYkVZelZXMHdOVlJyTUhkU1dHeFZWbnBHZWxacVJuZFNNa1pKVTIxc1UyVnRkekJXVkVKdlV6SktjMVJzYUZaaGJGcHlW VEJrTkZaR1pISlZiVFZQVmxSV1NWWlhNWGRXTURGeVYyeFNWbFo2VmpOVWJHUlBWbTFXUm1KSGFGZE5hbWd6VmtaU1ExUXdO VVpOVmxaV1YwVndjMVp0ZUhkVWJGcEhWMjVPVWsxV2NGaFZWM0JoVm14YWRHRkhPVlZoYTNCVFdsVmFTMk14V2xWV2F6VlhZ VEJaTVZkV1kzZE5WazVIVWxob2FGTkdTbkJVVldoVFZFWmFWbFpVUm1saVJuQldWbGMxVTFadFJuSk9WazVXVFc1Q2VscFda RXBsYkVwMFpFZDBhRTFFVm1GWFZFSnJUVVpKZVZScVdsWmliVkpXV1Zod1IyUldXbk5WYkU1V1ZqRmFlVmR1Y0ZkVU1sWnlU bGhvVldKVVJtaFpNR1JYVmpGV2MxWnRiR2hXUjNoUlYyeGtkMk15VWtkVWExWllZbFJXVDFscldtRlZiRlp4VTFSV2ExWXhX bmRhUldSM1ZHeEtSbGRxUmxkU2JIQlFWbXhhVjJSR1VuUmpSbHBvVFZWd01sZFVSbUZVTWtwWFlqTmthazB5ZUhOV2JGcExW R3hhUmxremFHcFNWRVpHVm0xNFExWnRSWGxoUmxwYVltNUNXRlpVUmt0WFIwbDZZVVpTYUdKRmNGVlhWbHBoVVRGa1dGTllj RmhoTVhCVVZqQmthMDVzV2tkVmJFNVVVbXRXTTFSV1ZtdFVNREZXWTBaYVZrMVdXbmxVVldSTFUwZE9SVlZyT1ZoU00yZzFW akowVTJJeVRsZFhhMUpRVm5wV1ZGUlZVbk5XUmxWNFYydDBhMkpGTVRaWGEyaERZVEF4Y2xkdVpHRlNiSEJQVkZWa1YxSXhj RWRXYlhSb1RVaENXbGRYTUhoaU1EQjVVbGhrVldKclduSlVWM2hHWkRGU1YxcEVRbFZpUjNRMVZGWm9SMkV3TVhOWFdHaFlW a1UxUTFSVldsTmpiVVpGVm14S1RsSkZWWGRXYlRCNFlqSldkRlJyWkZoaE1YQlZXV3hrYjAxc2JIVmpSemxyVm14d1NsbHJZ elZXVjBaeVYycGFXbUV5VGpSYVZWcDNVMFUxVm1ORk9XbGlhMHBTVmpKMGIxSXhXWGhoTTJSV1lXczFUMVpzV2t0VGJGSlZV VzVrVldGNlJsaFpWV2hyVkRKS1NHUXpjRlZUU0VKTVZYcEtSbVZzY0VkU2JYaFRVak5vTTFacldsZGpNa3BIVld0YVZGZEhV bkZVVlZKdVRVWndWbFp1U2s1aVJrb3dXa1ZTUzJGck1IbGhSRlpWWVd0S00xWXllSGRPYkU1elZHeEtUbEpGVlhsV2JGcGhX VlpTYzFSdVVsZFdSVnBUVkZjeGIyUkdXbFpYYTA1cVVtczFNRlV5ZEhOV1ZrcFdWMnhhV2sxV2NIWldSVnByVjBaS2MxcEhl RmRTTVVsNFZrUkdZV1F4VmxoU2ExcFFWbGhvVjFVd1ZURk5iRlkyVTJ0MFZGWnRVbGxVYkZaM1Yyc3hSV0pFV2xwV1JUVmhW RlZhU21Rd09VbGFSMmhYVWxWd1VWWlljRXRXTWs1eVpETmtWMWRHY0hCWmJGcGhaR3hrY1ZOc1RsaGlWWEF4V1c1d1YxVXhT WGRPVmtaV1pXdEtkbFY2U2t0V1IxSkZWV3hLYVZaRldtRldSbEpEVmpBeGMxcEdiRk5oTVhCaFZGZHpNVlJHVlhoYVJUbFRZ a1UxUjFWdGRFdGhWVEZ6VTJ0YVdrMUdXbGhWTUdSWFkxWk9jbVJIZEZkTmJXZDVWbXRvY2s1Vk1WZFNibEpUWVRGS2FGUlZh Rk5VVmxaWlkwWmFUazFyV2xoVmJUVnJWVEF4Vms1V1NtRlNla1oyV1cxNFUxWnNWblZoUmxaV1RURktWVmRXV21GWlZtUnpW VzVTYUZKNmJIQlVWVnBXWld4a1YyRkhPV3RoTTA0MVdUQlNZVmRyTVVWV2FrNVhUVVp3TTFVd1dsZFRWazV5Vkd4a1UwMHlh RkJXVkU1elRVZEplVkpyVW10VFNFSnZWRlpvUTFSR1pIUk5WVGxwWWtVeE0xWlhkSE5VYkZsNlZXNVNWV0V4Y0hwVmExcEta REE1V1ZSdGFGTk5ibWN5VmtjeE5GVXlTblJTYms1VlZrVndZVlJWVm1GVVJsSlhXa1YwVjFJd01UUlphMXBQVlVaS2NsZHJW bFZXUlVwaFdUSjRUMUpzY0VkVmJXeFlVak5vVmxkV1kzaFZNVkY1VTJ0YWExSlhhSEJWYkdoRFl6RldjMWR1Wkd0U01GcFhW VzAxVjFSck1VZFNXR2hhVFVaYVMxcEVRWGhTYlVaSFkwVTFhRlpIZHpCV2JYQlBVVEF3ZUdORldtaFRSa3BWVld4U2IwNXNi SE5XYlhSb1ZqQndXRmxyVWs5VmJVVjZWRmh3V0ZadFVuSlViRnBYVjBaYWRGSnRhRmRoTVc5NVZteGFhazFYVW5OaVNFNXBV bXRLVTFsVVRtcE5SbXgwWlVkd1RtSklRbmxXYlhoaFlVWktjMkpFVmxWaE1sSlFWakZrVW1WVk1WbGpSMFpUVFRGS1dsZFdh SGRSTWxaSVZteFdhRkp1UW05VVZtUnVUV3hrY1ZOdFJsZE5hMXBLV1ZWb1MyRnJNVmxSYXpGWVlUSlNjbFpIZUdGa1IxSkdU bFpPVTFadVFYaFhWRUpXWlVaS2MxTnNVbXRTTTBKWFZGUktVMDVzYkhKWGJtUldVbFJXV2xaWGN6RlhSa3B5VGtod1dGWkZT a2hXYWtwTFVsWldkR1ZGT1ZOV1JWcElWako0YTJJeFNuSk9WbEpRVjBWYVZGUlZVbTVsUmxGM1draGthbUpGTlZaWmEyaFBZ a1pLY2xkc1pGZGlWRVp5V1RJeFNtVkhTa2xUYkdSVFVqSm9WVlpxUm10VU1rVjNUbFpXVW1KdGVGaFdhMVpLWlVaYVIxVnNU bE5XTURFMVZqSndWMVpGTVhSVVdIQllZVEZ3VkZsdGVISmxWbEpWVW1zNVRrMVlRa1JXYTFadllURmtjMkpFV2xkV1JVcHhW RlJHWVZKc2NGaE5XRTVvWWxaYVdsVXlkSGRaVjBweVYxaHNXbFpXU25wVWJHUlRZMFU1VjFkdGVHbFhSMDE0VjJ0U1IxRnRW a1pOVm14cFUwWktXRlZxUm1GVlZsbDVaVWRHVjFZd01UVlViRll3Vm14SmVXRkZWbGRXZWxaaFdrZDRhMk5yT1ZsU2JVWlha V3RhVGxaWGVGTmhNa1pHVGxWb1UxZEhlRzlVVlZwaFVteFNjMVJ1Y0d4V1ZHeFpWakl3ZUdFeFdrZFRhM1JWWWxob1lWcEVT azlXVmxKMFpFZDBhV0pYVVRGWFZFcDNWakZzVms1SWNGWmlSVFZQV2xab1RtVldaRmRYYlhSc1ZteGFXVmRyVmxkV1ZrbDZZ VVJPVmsxR1NsTmFSM2hMVjBVeFYxSnJOVmRTYkc4d1ZrUkdiMUl5VmtoVmJGWlhZa1UxV1ZsclZuWmxiRkpWVTJwQ2FHRjZi RmhXTVZKUFZHMVdjbU5FVGxWaGF6VXpXVlZWTVU1c1JuUmxSbWhVVWpOb01GZHNWbGRXTVZKelZHNVNUbFpyV2xkVVYzaFhU bXhSZUZScVFsTldNVXBXVlRJeGIyRXlTa2hWYm5CaFZucFdNMVJWV2t0ak1WcDFZMGQwVTAxWVFqSldiWFJoVXpGU1YySklR bEJYUlVwWVZteFNRbVZXVm5KWk0yUk9WbFJXZDFReFpFZFdWbHBJWVVWb1dHSllRbWhaZWtGNFVqSktSMVZzVWxOTlYzUXpW MVJHVjAxSFNrZFZhMlJXVmtVMVQxbFhkSEpOVmxweFVXMDViR0pHV2tsYVZXaFhWV3N4Vm1FemNGWmlXR2g1V2tjeFIxSnJP VmxoUlRWVFlURldORmRzWTNoVmF6RnpVbGhzVkdKcldsZFVWM0JTWkRGV1ZWSnJUazlTTVZwV1ZsYzFWMVl4U2paU2JIQmhV bXhLU0ZVd1drdFRSMDVGVm1zNVRsWXhTa1pXUmxKSFl6RktTRlpyVmxkaE0yaG9WbXhrVGsxV1VuTlhiWFJUVFZoQ1IxcFZh RTlVVlRGMFlVaEdXazB6UW1GWk1uTjRVakpLU0dSRk5VNWlWa3BhVmxkd1IxWXhSWGxUYTJSWVlrVktZVlpzWkc5alZsWlpZ MGQwVjFKcmNGcFpNR1J2VlRGWmVHTkljRmRXYkZwVVZteGFXbVF3T1ZoaVJUbFhZVEk0ZVZaRlVrZFVNazE1VTJ0b1VGWjZS bkZXYWs1clRteHdSMXBHVG10aVZUVXdXbFZrTkdGR1dYaFdXR1JhVm0xb1UxUnJaRXRXTVdSWllVVTFWRkpyYTNkWFYzUlhV MnMxUjJKSVVsWmliV2hUV1ZSR2QyVldXbGRXVkZaVVVteEdObFZ0Y0V0WFJrbzJWbXhXVm1KWVFtaFdSbVJHWlZkT1JtTkhh RmRpV0doTlYxZDBVMVl4VFhkTlZtaFZWMGhDY0Zsc1ZYaE9WbkJJWkVkMFYwMXJOVmxXUnpWelZVWlplbGt6YUZkaVdGSnlX V3BHYTFOR1ZuTmlSbkJPWWxaS1JsWlVUbmRpYlZGNFkwaEtWMkpZYUZWWlYzaDNZakZTYzFwRlpHeFdiRm94VlRJd2VGZHNX bkpYYmxKaFVsWktWRmxXWkV0VFZtUnlWRzE0VTFKWVFYbFhWM2hUVlRGc1YxTnVTazVUU0VKV1ZGUkJNV1ZzY0VsaGVsWnFW bXMxVjFZeWRHOVVNa3AwVkdwT1ZsWkZXbGhXUlZwSFYxZEtTVlJzVms1V01ERTBWbXRXYTFKdFVuTlZhMXBvVFRKb1ZsUlda RFJTYkZKeFUycENWVkpyV2xsV2JURnpWbFpLU0dRelpGZGlSbG96VmxWa1QyTldSbkpPVmxaVFZsaEJNbFpHVm1wa01EVkhV MjVLVm1KRk5VNVVWV2hPWkRGa1YyRkdUbWxpUlhCSFZrY3hkMVl5Vm5KWGFscGFWbTFvZGxZd1ZYaFdWbVJaVTIxNGFFMXNT akpXVm1NeFYyc3hkRlZZYkdGbGJGcHhXV3RXZDFWc1VsZGhSbVJQWWxaS1dsVXllR0ZoYkZsNldUTnNZVk5JUWxoV1JtUkhW a2RTU1dKRk5WZFdiVGswVm14a2NrNVdaRWhUYkZacFVrVktUMVpxUm1Gak1XeFdZVVYwYTJGNlFqVlhWRTV2VlRBeFNHRkZV bFpoTW1oWVdWWmFZVll4YjNwaFJrSlRWbXR3TWxaRVJtdFZNVXB6VW01R1VtSnNTbkZWYWs1dlZERmFSVlJ1VGxkaVJUVkhX a1ZTUjFSdFJYZE9WMmhoVW5wR2RsUldXa2RXYkdSMVVXczVUbUpGYjNsV01uaE9UbFpTZEZSclZsVmlWR3h6Vm0weE5FMXNX blZqUldSVllraENWMXBWV25kWGF6RnpZMGM1V21FeWFIbFVWbVJUVjBaYWRXSkdUbWxpUm5CaFYxUkNiMVV4U2taT1ZXeFlZ VEpvWVZsc1ZsZE9WazQyVTJwT2FtSkdTbnBWTW5CTFZHeGtSMU5zYUZwV1YyaFlWVEJWTVZKdFZrZGpSVGxvVFVad1MxWXlk Rk5pTVU1WFlrWldWMkZyU2xoWmJYaGhVa1prV0dWSGRHaGlSbTh5VlRKNFYxVnRSbkpUYlVaWFRWZG9URlpIZUd0V1ZsWnpX a1U1YVZaSGVFVlhWRUpoVWpGc1YyTklUbWhTTUZwWFdXdFdZVTVXV2tobFIzUlZWakF4TlZZeWNGTldiR1JHWVROb1drMVhh SHBYVm1ST1pWZFdSbHBIY0U1TmFtdDVWakZhYTJFeFNuSk9XRTVXVjBkU2NGWnNVbkpOUm10M1ZXeHdiRlpyTVRaVmJYUmhW bXhhU0dWRVdscGhhMGwzV1RCa1UyTXhUblZqUmxaVVVtdHdNRmRYZEc5ak1WbDVWV3RrYUZKWGFITlZha0V4V1ZaU2RHVkZU azlpUlZwV1ZsZHdRMVF5Vm5OWGJXaGFWak5vTTFZeWVIZFRSVGxZWVVkb1UxSlZjRlJXTW5oaFVqQXhWMVJzVmxSaWJrSlFW bXBDY21Wc1drZGFSV1JhVm14R00xVnRlRU5XYkVwVlVtcFNWMVpXU25wYVZ6RlRVbXN4VmxOdGRFNU5iRXBvVmpKNFQyVnRW blJXYkd4U1lUQndXRmxyWkc5TmJGRjRWV3M1VTFaVVZrWldNblJYV1ZkS2NsZHJiRmRoYXpWUVdXdGFVMk5XV25KaFJtUnBV bXh3U1ZZeFVrdFRNa3BHVGtob1lWSXdXbkZaYlRGdlRsWmFkV05GT1ZoV2F6VkpWMnRhYjFkR1NraGFTR3hXWVd0S2NsWkVT bE5UUlRWWFUyeFNVMDF1VGpaWFYzaFhWbTFXU0ZScVdtRlRSVXB4V1Zod2MxSnNWblJOVlRsVFRWWndNVlZYZERCVk1WbDVW V3hhVmsxSFVYcFVWbHBQVW14V2NWZHJOVk5pYTBvMlZteGFZVk14WkVoVmEyeFdZWHBzY1ZsdE1UUlZiRkpXV2taa1RtRjZS a2haVlZWNFlWWlplbHBFVWxoaGF6VlFXVlphVm1ReVZrVlViSEJZVWpOUmVsZFdaRFJXTWxGM1l6TmthMUpHU205V2JGWmhU bFpWZDJGSVpGVldWRVpJVm0weGMyRXhXWGhYYWtKWFlURmFWRlpzV21GWFZtUnpWRzEwYUUweWFFUldiWEJQVlRKTmVHTklV bFppYXpWb1ZXeFdZVlpHY0ZaWGJHUnBWbXR3TUZVeWNFOVViR1JKVVc1c1ZXRXhXbFJhVmxwclpFWldkRkpzVGxOaVIzUTBW MVpXYjFReVRYZE9WV1JTWWtWd2NsVnRkSFpsUm5CSVpFaE9WVkl4V2xsYVJXaEhWVEF4YzFOdVdsaFdSVFZ5VmtkNGMxZEdj RVpsUjNob1RURkpNRmRyVWt0ak1rVjRVMnhvWVdWc1NsZFZhMXBoWTJ4U2NWTnFRbFppUmxZMVdWVm9iMkZWTVVkalJscGFZ VEZhV0ZaVVJsTmtSVGxKWVVab2FHRXpRbUZXVkVwM1VURkdkRkp1VGxKaGF6VnpWbXRWTVdOV1dYbGxSVGxYVm14V05sWXlj RWRVUlRGWFZsaGtWV0pZVFhoYVYzaGFaVVpXY1ZOc1VrNWlWMmhRVjFaV1UxTnRWblJUYkZaVFZrVndjVmx0TVhwa01WSnhW RzA1YUUxVk5VbFdNbkJEWVZaYVdWRnFWbFpOUjAweFZURlZlRk5YUmtobFJUbFVVbGhDZWxacVNURmtNVnBIVW01U2FGSkdT bFJWYkZKU1RWWldWVkZ0UmxkTlZUVXdWa2MxUjFaR1dsZFRha1poVWtWd2VsUlhlRnBrTVdSMVUyeG9hVlpHUmpSWGJHTXhW akZGZUZSc1pHaFNiRXBRVkZkd2MxSXhXblJsUlhSV1RWVndWbGxyV210V1ZURkpXVE5zVmsxcVJuWmFWVlY0VWxaU2RWZHRl Rk5YUlRReVZrUkNZVlF3TlhOV2JHaFVZV3RLVkZsdE1UUlJNV1JYVjJ4T1UxSnRkRE5XTWpWTFlURmFTR1I2U2xwaVdGSkxW RlZWTVZOWFNqWldhemxvVjBaS1RsZHNWbGRrTVZGNVZHdHNWbFpGY0U5V2JGcGhVa1pSZUdGSGRHbE5WbHA0Vm0xNFUxVXdN VVpXYWxwVlZqTlNlbFpxU2xOa1ZrNTBaRWRzVGxZelp6RldSRUpxVGxVeFdGTnFXbWhUUlVwVVdXeGtVazFHWkZobFNFcE9U VlZ3VjFVeFVrdFZiRmw1WlVSV1lWSnNXVEJVYlRGVFZtczVSVkZzVms1WFJVcEtWa1pqTVdJeVRrZGlSbFpVWVROU1dWVnJX bk5PUmxsM1YyeGtWV0pWY0RCVmJGSlhZVEZLYzJORk9WWmlXRTEzVkZWYWRtVlhTWHBpUmtKVFRUQkpNbFpFUm10T1IwMTRW R3RvVTJKR1duSmFWM2hLVFVaYWNscEVVbEppUmxwWFZHeFNUMkV4V2tkalNHaFZWak5DY1ZSWGVGcGxSa1p4Vm1zNVYySkZj RlZYYTJSM1dWWlJlRmRzYkdwVFIzaFlXVlJLYjJWR1VYaFhiWFJVVW01Q1NWWkdhSE5YUms1SVZXcEdWMVpGV2xOVVZXUkxZ ekpLUjJKSGJGZFNiRlY0VmpJeE1GbFZNWFJUYTJob1VsWmFVRmxVUVRGT1JtUnlXa1pPYTJKR2NIcFdNbk40VlVaYVIxWnFW bGhoTW1oRVdXcEdWMlJGTlZkYVIyeFlVakF4TlZkWGRHRlVNazVIVkd0c1YyRjZSbFJXYTFVeFpGWlNXRTVXVGxoV2JHdzFW RlZvZDJGc1duTmpSbEpZWVdzMWNsUnJXbFpsVmxaeVkwWlNiRlpIZUVoV2JURXdWakpLV0ZKcldtcFNiRXBSVld4YWQxSnNV bk5hUlhST1VtNUNWMWxyYUVOV1ZscFdWMjFHVjAxWFVqSlVhMXBPWlZkU1IxUnNUbGhTYkZWNFZtMTRiMUV4V25OalJWWldZ V3hLVlZWcVJsWk5SbHBYV2taa1YwMXNXa2RWYlRWRFZFVXhSVlZxV2xkTmFsWjJXWHBLUjFOSFZrWlZiRlpYVFdzMU5WZHJV azlUTVZwSFZWaHNWR0p0ZUZsV1ZFNVRVa1prV0dORlRrNVNiVko1V2tod1ExZEdTbk5XYWs1V1lXdHdhRmxXVlhkbGJIQkpW RzFzVGxaWE9UUldNV1IzVVRGV2MySXpiRkJXYXpWUFZtcEJNVmxXYkZkWGEzUlZUVVJzU0ZZeWRHdFVhekYwWVVVeFZWWXph RkJhVmxwelYwWmtjMkpIZUdsV1JWcFNWMVJHVjJNeFJuTlVhMnhvVWpOQ2FGbFVUa05UUm14VlUyNWtiRll3TVRWVk1uQlBW VzFLUm1JelpGcGhhelY2VmpGV2VtVkdaRlZUYkdSWFlsWktNbGRYZEZkaU1VcEhWV3hvYWxJelFtRldiRkpUVGxaa2RFNVdU bXRTYmtKR1ZtMXpNVlpyTVhOWGJrSlhVbTFSZWxScldtRmtWbEoxWTBaU2JHSkZhM2xXVkVaWFZHMVdWMVJyYkZKWFIyaFlW V3hvVTFkV1VuSldiR1JPWWtkME5sWlhjRWRWYlVwSVZWUktWMkpVUlhkWFZtUlBUbXhhV1ZwR1VsTmlWa3BFVlROd1MyUXhU blJTYWxwVlYwVndVVlp0ZUdGV2JGcHlZVVprYUZJd1drWlZNalZyVmpKS2MxZHFWbGRoYXpWUVdUSXhUMUpzY0RaU2JYUllV bFZ3Tmxkc1ZrNU9Wa3BJVWxoc1ZXSkdjSEJaYlRGclRXeGFWVk5yWkZoU2JYUXpWVEZTVTFWR1NrWlRiRVphVFVad1dGVnFT bGRTVmxKelUyeG9XRkl4U25sV01WcFRZakZLY2s1SWJGUmhhMHBVVkZab1EyRkdVbFpXVkVab1VqRmFWMWxyYUhOV1YwcElZ VVJTVjAxcVJrZGFWVnAzWTJ4a2NsVnNVbE5XUjNoV1ZsZDBiMWxWTlVkYVNFcFFWbGRTY2xaVVRsTmxiRlYzVjJ0YWJGWnVR bFpYYTFZMFZqRktjMWRxVmxoV2VrSTBXV3RWZUdOV1ZsbFRiWFJYVmtkNFdsWnJVazlrTWxKR1l6TnNhVkp0VWxWVk1GVjNa VVp3U0dORlpHcFNNRm93Vm0weFIyRkhTblJoU0VwV1lrWndUMXBXV2tkV1ZsSnlZVVpTYVZKcmIzZFdSbU40WkdzeFIxUnJh R2hTVm5CUFZXcE9RMk5XVlhsT1ZXUlNUVVJHTVZkclVsTlZhekZHVFVSQ1YySlVRalJWZWtwVFpGWldkVlZzVWxkU00yaFJW MWh3VDJOck1IZE9WV3hWWWxSV1YxWnJXa3RrTVhCV1dYcFdUbUpGY0VoWGEyaERWbXhLTmxKck1WUmxhMFV4V1ZWVmVFNVZP VlpXYkdST1lXdGFiMVpYZUc5aU1VbDVVbTVXVm1Kc2NGTlVWRW96VFd4V1dFMUVSbWhTYXpFelZtMTRRMVZHV2xaT1dGWlZW bXh3UjFwSGN6RlRWbkJIVTJzNVRsWlVWbGhXVmxKTFltMVdkRkp1VGxKaVIyaHhWbXhTYzFKR1ZuUmpSazVZWWtoQ1dGZFlj RU5oTWtwSFkwVndWMkV5VWpOV01WcExaRVpPVlZOc1dteFdSM2N3VmxjeE1GSnJNSGhTV0doVllXczFXVlpzYUc5WFJuQllU VmRHVkUxV1drcFdNalZEVkd4S1NGVnJPV0ZXYldoeVZsWldlbVZHVW5SaVIyeFhZbGRvU1Zkc1pEQlNNRFZJVld4b1ZHSnVR bFZWYWs1U1pXeGtWVlJ1VGxWV2JYaGFWbTF6TVZaWFNsaFZiV2hhWWtkb1RGWkVSbUZTTWtaRlZXczVWRkpVVm5aV01qRTBV ekpOZVZSWWFGTmliV2h5V1cxMFMxUXhaRmRaTTJScVlYcENOVmRxVG5kV2JGcEhVMjVPVlUxWFVsaFpNRnBUVTBVNVZrMVdV bE5OYlZFeFZteGFiMWxXWkhOU2JGWmhUVEo0VDFaclpGTmxiRkp6Vlc1S1RrMVZjSHBYYTFwWFZGZFdkR1ZJVGxoaE1VcHlW akJWZDJWV1pIUmpSM1JwVWpKb2FGZHJaRFJSTWxaWVZXcFdVRkpGTlU5WmJURlRUa1pTVjFScVFsZFdiRnBHV1ZWV1QxbFZN WEpXVkVKWVlsUkZkMVZVU2xkVFZrcHlWV3N4VGsxc1NrUldWVnBQVTIxT1JtUkdVbWhsYlU1d1V6Rk9jazR3YkVWUFEzTnBT MU5yTjBsRU9Dc2lLU2s3SUQ4KyIpKTsgPz4=")); ?>Exception/Http/Status501.php000064400000000725150211523530011644 0ustar00code = (int) $data->status_code; } parent::__construct($reason, $data); } } Exception/Http/Status418.php000064400000001054150211523530011647 0ustar00 FF01:0:0:0:0:0:0:101 * ::1 -> 0:0:0:0:0:0:0:1 * * @author Alexander Merz * @author elfrink at introweb dot nl * @author Josh Peck * @copyright 2003-2005 The PHP Group * @license https://opensource.org/licenses/bsd-license.php * * @param string|Stringable $ip An IPv6 address * @return string The uncompressed IPv6 address * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object. */ public static function uncompress($ip) { if (InputValidator::is_string_or_stringable($ip) === false) { throw InvalidArgument::create(1, '$ip', 'string|Stringable', gettype($ip)); } $ip = (string) $ip; if (substr_count($ip, '::') !== 1) { return $ip; } list($ip1, $ip2) = explode('::', $ip); $c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':'); $c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':'); if (strpos($ip2, '.') !== false) { $c2++; } if ($c1 === -1 && $c2 === -1) { // :: $ip = '0:0:0:0:0:0:0:0'; } elseif ($c1 === -1) { // ::xxx $fill = str_repeat('0:', 7 - $c2); $ip = str_replace('::', $fill, $ip); } elseif ($c2 === -1) { // xxx:: $fill = str_repeat(':0', 7 - $c1); $ip = str_replace('::', $fill, $ip); } else { // xxx::xxx $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); $ip = str_replace('::', $fill, $ip); } return $ip; } /** * Compresses an IPv6 address * * RFC 4291 allows you to compress consecutive zero pieces in an address to * '::'. This method expects a valid IPv6 address and compresses consecutive * zero pieces to '::'. * * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 * 0:0:0:0:0:0:0:1 -> ::1 * * @see \WpOrg\Requests\Ipv6::uncompress() * * @param string $ip An IPv6 address * @return string The compressed IPv6 address */ public static function compress($ip) { // Prepare the IP to be compressed. // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method. $ip = self::uncompress($ip); $ip_parts = self::split_v6_v4($ip); // Replace all leading zeros $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]); // Find bunches of zeros if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) { $max = 0; $pos = null; foreach ($matches[0] as $match) { if (strlen($match[0]) > $max) { $max = strlen($match[0]); $pos = $match[1]; } } $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max); } if ($ip_parts[1] !== '') { return implode(':', $ip_parts); } else { return $ip_parts[0]; } } /** * Splits an IPv6 address into the IPv6 and IPv4 representation parts * * RFC 4291 allows you to represent the last two parts of an IPv6 address * using the standard IPv4 representation * * Example: 0:0:0:0:0:0:13.1.68.3 * 0:0:0:0:0:FFFF:129.144.52.38 * * @param string $ip An IPv6 address * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part */ private static function split_v6_v4($ip) { if (strpos($ip, '.') !== false) { $pos = strrpos($ip, ':'); $ipv6_part = substr($ip, 0, $pos); $ipv4_part = substr($ip, $pos + 1); return [$ipv6_part, $ipv4_part]; } else { return [$ip, '']; } } /** * Checks an IPv6 address * * Checks if the given IP is a valid IPv6 address * * @param string $ip An IPv6 address * @return bool true if $ip is a valid IPv6 address */ public static function check_ipv6($ip) { // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method. $ip = self::uncompress($ip); list($ipv6, $ipv4) = self::split_v6_v4($ip); $ipv6 = explode(':', $ipv6); $ipv4 = explode('.', $ipv4); if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) { foreach ($ipv6 as $ipv6_part) { // The section can't be empty if ($ipv6_part === '') { return false; } // Nor can it be over four characters if (strlen($ipv6_part) > 4) { return false; } // Remove leading zeros (this is safe because of the above) $ipv6_part = ltrim($ipv6_part, '0'); if ($ipv6_part === '') { $ipv6_part = '0'; } // Check the value is valid $value = hexdec($ipv6_part); if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) { return false; } } if (count($ipv4) === 4) { foreach ($ipv4 as $ipv4_part) { $value = (int) $ipv4_part; if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) { return false; } } } return true; } else { return false; } } } Auth.php000064400000001534150211523530006156 0ustar00 '\WpOrg\Requests\Auth', 'requests_hooker' => '\WpOrg\Requests\HookManager', 'requests_proxy' => '\WpOrg\Requests\Proxy', 'requests_transport' => '\WpOrg\Requests\Transport', // Classes. 'requests_cookie' => '\WpOrg\Requests\Cookie', 'requests_exception' => '\WpOrg\Requests\Exception', 'requests_hooks' => '\WpOrg\Requests\Hooks', 'requests_idnaencoder' => '\WpOrg\Requests\IdnaEncoder', 'requests_ipv6' => '\WpOrg\Requests\Ipv6', 'requests_iri' => '\WpOrg\Requests\Iri', 'requests_response' => '\WpOrg\Requests\Response', 'requests_session' => '\WpOrg\Requests\Session', 'requests_ssl' => '\WpOrg\Requests\Ssl', 'requests_auth_basic' => '\WpOrg\Requests\Auth\Basic', 'requests_cookie_jar' => '\WpOrg\Requests\Cookie\Jar', 'requests_proxy_http' => '\WpOrg\Requests\Proxy\Http', 'requests_response_headers' => '\WpOrg\Requests\Response\Headers', 'requests_transport_curl' => '\WpOrg\Requests\Transport\Curl', 'requests_transport_fsockopen' => '\WpOrg\Requests\Transport\Fsockopen', 'requests_utility_caseinsensitivedictionary' => '\WpOrg\Requests\Utility\CaseInsensitiveDictionary', 'requests_utility_filterediterator' => '\WpOrg\Requests\Utility\FilteredIterator', 'requests_exception_http' => '\WpOrg\Requests\Exception\Http', 'requests_exception_transport' => '\WpOrg\Requests\Exception\Transport', 'requests_exception_transport_curl' => '\WpOrg\Requests\Exception\Transport\Curl', 'requests_exception_http_304' => '\WpOrg\Requests\Exception\Http\Status304', 'requests_exception_http_305' => '\WpOrg\Requests\Exception\Http\Status305', 'requests_exception_http_306' => '\WpOrg\Requests\Exception\Http\Status306', 'requests_exception_http_400' => '\WpOrg\Requests\Exception\Http\Status400', 'requests_exception_http_401' => '\WpOrg\Requests\Exception\Http\Status401', 'requests_exception_http_402' => '\WpOrg\Requests\Exception\Http\Status402', 'requests_exception_http_403' => '\WpOrg\Requests\Exception\Http\Status403', 'requests_exception_http_404' => '\WpOrg\Requests\Exception\Http\Status404', 'requests_exception_http_405' => '\WpOrg\Requests\Exception\Http\Status405', 'requests_exception_http_406' => '\WpOrg\Requests\Exception\Http\Status406', 'requests_exception_http_407' => '\WpOrg\Requests\Exception\Http\Status407', 'requests_exception_http_408' => '\WpOrg\Requests\Exception\Http\Status408', 'requests_exception_http_409' => '\WpOrg\Requests\Exception\Http\Status409', 'requests_exception_http_410' => '\WpOrg\Requests\Exception\Http\Status410', 'requests_exception_http_411' => '\WpOrg\Requests\Exception\Http\Status411', 'requests_exception_http_412' => '\WpOrg\Requests\Exception\Http\Status412', 'requests_exception_http_413' => '\WpOrg\Requests\Exception\Http\Status413', 'requests_exception_http_414' => '\WpOrg\Requests\Exception\Http\Status414', 'requests_exception_http_415' => '\WpOrg\Requests\Exception\Http\Status415', 'requests_exception_http_416' => '\WpOrg\Requests\Exception\Http\Status416', 'requests_exception_http_417' => '\WpOrg\Requests\Exception\Http\Status417', 'requests_exception_http_418' => '\WpOrg\Requests\Exception\Http\Status418', 'requests_exception_http_428' => '\WpOrg\Requests\Exception\Http\Status428', 'requests_exception_http_429' => '\WpOrg\Requests\Exception\Http\Status429', 'requests_exception_http_431' => '\WpOrg\Requests\Exception\Http\Status431', 'requests_exception_http_500' => '\WpOrg\Requests\Exception\Http\Status500', 'requests_exception_http_501' => '\WpOrg\Requests\Exception\Http\Status501', 'requests_exception_http_502' => '\WpOrg\Requests\Exception\Http\Status502', 'requests_exception_http_503' => '\WpOrg\Requests\Exception\Http\Status503', 'requests_exception_http_504' => '\WpOrg\Requests\Exception\Http\Status504', 'requests_exception_http_505' => '\WpOrg\Requests\Exception\Http\Status505', 'requests_exception_http_511' => '\WpOrg\Requests\Exception\Http\Status511', 'requests_exception_http_unknown' => '\WpOrg\Requests\Exception\Http\StatusUnknown', ]; /** * Register the autoloader. * * Note: the autoloader is *prepended* in the autoload queue. * This is done to ensure that the Requests 2.0 autoloader takes precedence * over a potentially (dependency-registered) Requests 1.x autoloader. * * @internal This method contains a safeguard against the autoloader being * registered multiple times. This safeguard uses a global constant to * (hopefully/in most cases) still function correctly, even if the * class would be renamed. * * @return void */ public static function register() { if (defined('REQUESTS_AUTOLOAD_REGISTERED') === false) { spl_autoload_register([self::class, 'load'], true); define('REQUESTS_AUTOLOAD_REGISTERED', true); } } /** * Autoloader. * * @param string $class_name Name of the class name to load. * * @return bool Whether a class was loaded or not. */ public static function load($class_name) { // Check that the class starts with "Requests" (PSR-0) or "WpOrg\Requests" (PSR-4). $psr_4_prefix_pos = strpos($class_name, 'WpOrg\\Requests\\'); if (stripos($class_name, 'Requests') !== 0 && $psr_4_prefix_pos !== 0) { return false; } $class_lower = strtolower($class_name); if ($class_lower === 'requests') { // Reference to the original PSR-0 Requests class. $file = dirname(__DIR__) . '/library/Requests.php'; } elseif ($psr_4_prefix_pos === 0) { // PSR-4 classname. $file = __DIR__ . '/' . strtr(substr($class_name, 15), '\\', '/') . '.php'; } if (isset($file) && file_exists($file)) { include $file; return true; } /* * Okay, so the class starts with "Requests", but we couldn't find the file. * If this is one of the deprecated/renamed PSR-0 classes being requested, * let's alias it to the new name and throw a deprecation notice. */ if (isset(self::$deprecated_classes[$class_lower])) { /* * Integrators who cannot yet upgrade to the PSR-4 class names can silence deprecations * by defining a `REQUESTS_SILENCE_PSR0_DEPRECATIONS` constant and setting it to `true`. * The constant needs to be defined before the first deprecated class is requested * via this autoloader. */ if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS') || REQUESTS_SILENCE_PSR0_DEPRECATIONS !== true) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error trigger_error( 'The PSR-0 `Requests_...` class names in the Requests library are deprecated.' . ' Switch to the PSR-4 `WpOrg\Requests\...` class names at your earliest convenience.', E_USER_DEPRECATED ); // Prevent the deprecation notice from being thrown twice. if (!defined('REQUESTS_SILENCE_PSR0_DEPRECATIONS')) { define('REQUESTS_SILENCE_PSR0_DEPRECATIONS', true); } } // Create an alias and let the autoloader recursively kick in to load the PSR-4 class. return class_alias(self::$deprecated_classes[$class_lower], $class_name, true); } return false; } } } Exception.php000064400000004333150211523530007213 0ustar00 array( 'port' => Port::ACAP, ), 'dict' => array( 'port' => Port::DICT, ), 'file' => array( 'ihost' => 'localhost', ), 'http' => array( 'port' => Port::HTTP, ), 'https' => array( 'port' => Port::HTTPS, ), ); /** * Return the entire IRI when you try and read the object as a string * * @return string */ public function __toString() { return $this->get_iri(); } /** * Overload __set() to provide access via properties * * @param string $name Property name * @param mixed $value Property value */ public function __set($name, $value) { if (method_exists($this, 'set_' . $name)) { call_user_func(array($this, 'set_' . $name), $value); } elseif ( $name === 'iauthority' || $name === 'iuserinfo' || $name === 'ihost' || $name === 'ipath' || $name === 'iquery' || $name === 'ifragment' ) { call_user_func(array($this, 'set_' . substr($name, 1)), $value); } } /** * Overload __get() to provide access via properties * * @param string $name Property name * @return mixed */ public function __get($name) { // isset() returns false for null, we don't want to do that // Also why we use array_key_exists below instead of isset() $props = get_object_vars($this); if ( $name === 'iri' || $name === 'uri' || $name === 'iauthority' || $name === 'authority' ) { $method = 'get_' . $name; $return = $this->$method(); } elseif (array_key_exists($name, $props)) { $return = $this->$name; } // host -> ihost elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) { $name = $prop; $return = $this->$prop; } // ischeme -> scheme elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) { $name = $prop; $return = $this->$prop; } else { trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); $return = null; } if ($return === null && isset($this->normalization[$this->scheme][$name])) { return $this->normalization[$this->scheme][$name]; } else { return $return; } } /** * Overload __isset() to provide access via properties * * @param string $name Property name * @return bool */ public function __isset($name) { return (method_exists($this, 'get_' . $name) || isset($this->$name)); } /** * Overload __unset() to provide access via properties * * @param string $name Property name */ public function __unset($name) { if (method_exists($this, 'set_' . $name)) { call_user_func(array($this, 'set_' . $name), ''); } } /** * Create a new IRI object, from a specified string * * @param string|Stringable|null $iri * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $iri argument is not a string, Stringable or null. */ public function __construct($iri = null) { if ($iri !== null && InputValidator::is_string_or_stringable($iri) === false) { throw InvalidArgument::create(1, '$iri', 'string|Stringable|null', gettype($iri)); } $this->set_iri($iri); } /** * Create a new IRI object by resolving a relative IRI * * Returns false if $base is not absolute, otherwise an IRI. * * @param \WpOrg\Requests\Iri|string $base (Absolute) Base IRI * @param \WpOrg\Requests\Iri|string $relative Relative IRI * @return \WpOrg\Requests\Iri|false */ public static function absolutize($base, $relative) { if (!($relative instanceof self)) { $relative = new self($relative); } if (!$relative->is_valid()) { return false; } elseif ($relative->scheme !== null) { return clone $relative; } if (!($base instanceof self)) { $base = new self($base); } if ($base->scheme === null || !$base->is_valid()) { return false; } if ($relative->get_iri() !== '') { if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) { $target = clone $relative; $target->scheme = $base->scheme; } else { $target = new self; $target->scheme = $base->scheme; $target->iuserinfo = $base->iuserinfo; $target->ihost = $base->ihost; $target->port = $base->port; if ($relative->ipath !== '') { if ($relative->ipath[0] === '/') { $target->ipath = $relative->ipath; } elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') { $target->ipath = '/' . $relative->ipath; } elseif (($last_segment = strrpos($base->ipath, '/')) !== false) { $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; } else { $target->ipath = $relative->ipath; } $target->ipath = $target->remove_dot_segments($target->ipath); $target->iquery = $relative->iquery; } else { $target->ipath = $base->ipath; if ($relative->iquery !== null) { $target->iquery = $relative->iquery; } elseif ($base->iquery !== null) { $target->iquery = $base->iquery; } } $target->ifragment = $relative->ifragment; } } else { $target = clone $base; $target->ifragment = null; } $target->scheme_normalization(); return $target; } /** * Parse an IRI into scheme/authority/path/query/fragment segments * * @param string $iri * @return array */ protected function parse_iri($iri) { $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); $has_match = preg_match('/^((?P[^:\/?#]+):)?(\/\/(?P[^\/?#]*))?(?P[^?#]*)(\?(?P[^#]*))?(#(?P.*))?$/', $iri, $match); if (!$has_match) { throw new Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri); } if ($match[1] === '') { $match['scheme'] = null; } if (!isset($match[3]) || $match[3] === '') { $match['authority'] = null; } if (!isset($match[5])) { $match['path'] = ''; } if (!isset($match[6]) || $match[6] === '') { $match['query'] = null; } if (!isset($match[8]) || $match[8] === '') { $match['fragment'] = null; } return $match; } /** * Remove dot segments from a path * * @param string $input * @return string */ protected function remove_dot_segments($input) { $output = ''; while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') { // A: If the input buffer begins with a prefix of "../" or "./", // then remove that prefix from the input buffer; otherwise, if (strpos($input, '../') === 0) { $input = substr($input, 3); } elseif (strpos($input, './') === 0) { $input = substr($input, 2); } // B: if the input buffer begins with a prefix of "/./" or "/.", // where "." is a complete path segment, then replace that prefix // with "/" in the input buffer; otherwise, elseif (strpos($input, '/./') === 0) { $input = substr($input, 2); } elseif ($input === '/.') { $input = '/'; } // C: if the input buffer begins with a prefix of "/../" or "/..", // where ".." is a complete path segment, then replace that prefix // with "/" in the input buffer and remove the last segment and its // preceding "/" (if any) from the output buffer; otherwise, elseif (strpos($input, '/../') === 0) { $input = substr($input, 3); $output = substr_replace($output, '', (strrpos($output, '/') ?: 0)); } elseif ($input === '/..') { $input = '/'; $output = substr_replace($output, '', (strrpos($output, '/') ?: 0)); } // D: if the input buffer consists only of "." or "..", then remove // that from the input buffer; otherwise, elseif ($input === '.' || $input === '..') { $input = ''; } // E: move the first path segment in the input buffer to the end of // the output buffer, including the initial "/" character (if any) // and any subsequent characters up to, but not including, the next // "/" character or the end of the input buffer elseif (($pos = strpos($input, '/', 1)) !== false) { $output .= substr($input, 0, $pos); $input = substr_replace($input, '', 0, $pos); } else { $output .= $input; $input = ''; } } return $output . $input; } /** * Replace invalid character with percent encoding * * @param string $text Input string * @param string $extra_chars Valid characters not in iunreserved or * iprivate (this is ASCII-only) * @param bool $iprivate Allow iprivate * @return string */ protected function replace_invalid_with_pct_encoding($text, $extra_chars, $iprivate = false) { // Normalize as many pct-encoded sections as possible $text = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $text); // Replace invalid percent characters $text = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $text); // Add unreserved and % to $extra_chars (the latter is safe because all // pct-encoded sections are now valid). $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; // Now replace any bytes that aren't allowed with their pct-encoded versions $position = 0; $strlen = strlen($text); while (($position += strspn($text, $extra_chars, $position)) < $strlen) { $value = ord($text[$position]); // Start position $start = $position; // By default we are valid $valid = true; // No one byte sequences are valid due to the while. // Two byte sequence: if (($value & 0xE0) === 0xC0) { $character = ($value & 0x1F) << 6; $length = 2; $remaining = 1; } // Three byte sequence: elseif (($value & 0xF0) === 0xE0) { $character = ($value & 0x0F) << 12; $length = 3; $remaining = 2; } // Four byte sequence: elseif (($value & 0xF8) === 0xF0) { $character = ($value & 0x07) << 18; $length = 4; $remaining = 3; } // Invalid byte: else { $valid = false; $length = 1; $remaining = 0; } if ($remaining) { if ($position + $length <= $strlen) { for ($position++; $remaining; $position++) { $value = ord($text[$position]); // Check that the byte is valid, then add it to the character: if (($value & 0xC0) === 0x80) { $character |= ($value & 0x3F) << (--$remaining * 6); } // If it is invalid, count the sequence as invalid and reprocess the current byte: else { $valid = false; $position--; break; } } } else { $position = $strlen - 1; $valid = false; } } // Percent encode anything invalid or not in ucschar if ( // Invalid sequences !$valid // Non-shortest form sequences are invalid || $length > 1 && $character <= 0x7F || $length > 2 && $character <= 0x7FF || $length > 3 && $character <= 0xFFFF // Outside of range of ucschar codepoints // Noncharacters || ($character & 0xFFFE) === 0xFFFE || $character >= 0xFDD0 && $character <= 0xFDEF || ( // Everything else not in ucschar $character > 0xD7FF && $character < 0xF900 || $character < 0xA0 || $character > 0xEFFFD ) && ( // Everything not in iprivate, if it applies !$iprivate || $character < 0xE000 || $character > 0x10FFFD ) ) { // If we were a character, pretend we weren't, but rather an error. if ($valid) { $position--; } for ($j = $start; $j <= $position; $j++) { $text = substr_replace($text, sprintf('%%%02X', ord($text[$j])), $j, 1); $j += 2; $position += 2; $strlen += 2; } } } return $text; } /** * Callback function for preg_replace_callback. * * Removes sequences of percent encoded bytes that represent UTF-8 * encoded characters in iunreserved * * @param array $regex_match PCRE match * @return string Replacement */ protected function remove_iunreserved_percent_encoded($regex_match) { // As we just have valid percent encoded sequences we can just explode // and ignore the first member of the returned array (an empty string). $bytes = explode('%', $regex_match[0]); // Initialize the new string (this is what will be returned) and that // there are no bytes remaining in the current sequence (unsurprising // at the first byte!). $string = ''; $remaining = 0; // Loop over each and every byte, and set $value to its value for ($i = 1, $len = count($bytes); $i < $len; $i++) { $value = hexdec($bytes[$i]); // If we're the first byte of sequence: if (!$remaining) { // Start position $start = $i; // By default we are valid $valid = true; // One byte sequence: if ($value <= 0x7F) { $character = $value; $length = 1; } // Two byte sequence: elseif (($value & 0xE0) === 0xC0) { $character = ($value & 0x1F) << 6; $length = 2; $remaining = 1; } // Three byte sequence: elseif (($value & 0xF0) === 0xE0) { $character = ($value & 0x0F) << 12; $length = 3; $remaining = 2; } // Four byte sequence: elseif (($value & 0xF8) === 0xF0) { $character = ($value & 0x07) << 18; $length = 4; $remaining = 3; } // Invalid byte: else { $valid = false; $remaining = 0; } } // Continuation byte: else { // Check that the byte is valid, then add it to the character: if (($value & 0xC0) === 0x80) { $remaining--; $character |= ($value & 0x3F) << ($remaining * 6); } // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: else { $valid = false; $remaining = 0; $i--; } } // If we've reached the end of the current byte sequence, append it to Unicode::$data if (!$remaining) { // Percent encode anything invalid or not in iunreserved if ( // Invalid sequences !$valid // Non-shortest form sequences are invalid || $length > 1 && $character <= 0x7F || $length > 2 && $character <= 0x7FF || $length > 3 && $character <= 0xFFFF // Outside of range of iunreserved codepoints || $character < 0x2D || $character > 0xEFFFD // Noncharacters || ($character & 0xFFFE) === 0xFFFE || $character >= 0xFDD0 && $character <= 0xFDEF // Everything else not in iunreserved (this is all BMP) || $character === 0x2F || $character > 0x39 && $character < 0x41 || $character > 0x5A && $character < 0x61 || $character > 0x7A && $character < 0x7E || $character > 0x7E && $character < 0xA0 || $character > 0xD7FF && $character < 0xF900 ) { for ($j = $start; $j <= $i; $j++) { $string .= '%' . strtoupper($bytes[$j]); } } else { for ($j = $start; $j <= $i; $j++) { $string .= chr(hexdec($bytes[$j])); } } } } // If we have any bytes left over they are invalid (i.e., we are // mid-way through a multi-byte sequence) if ($remaining) { for ($j = $start; $j < $len; $j++) { $string .= '%' . strtoupper($bytes[$j]); } } return $string; } protected function scheme_normalization() { if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) { $this->iuserinfo = null; } if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) { $this->ihost = null; } if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) { $this->port = null; } if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) { $this->ipath = ''; } if (isset($this->ihost) && empty($this->ipath)) { $this->ipath = '/'; } if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) { $this->iquery = null; } if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) { $this->ifragment = null; } } /** * Check if the object represents a valid IRI. This needs to be done on each * call as some things change depending on another part of the IRI. * * @return bool */ public function is_valid() { $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; if ($this->ipath !== '' && ( $isauthority && $this->ipath[0] !== '/' || ( $this->scheme === null && !$isauthority && strpos($this->ipath, ':') !== false && (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) ) ) ) { return false; } return true; } public function __wakeup() { $class_props = get_class_vars( __CLASS__ ); $string_props = array( 'scheme', 'iuserinfo', 'ihost', 'port', 'ipath', 'iquery', 'ifragment' ); $array_props = array( 'normalization' ); foreach ( $class_props as $prop => $default_value ) { if ( in_array( $prop, $string_props, true ) && ! is_string( $this->$prop ) ) { throw new UnexpectedValueException(); } elseif ( in_array( $prop, $array_props, true ) && ! is_array( $this->$prop ) ) { throw new UnexpectedValueException(); } $this->$prop = null; } } /** * Set the entire IRI. Returns true on success, false on failure (if there * are any invalid characters). * * @param string $iri * @return bool */ protected function set_iri($iri) { static $cache; if (!$cache) { $cache = array(); } if ($iri === null) { return true; } $iri = (string) $iri; if (isset($cache[$iri])) { list($this->scheme, $this->iuserinfo, $this->ihost, $this->port, $this->ipath, $this->iquery, $this->ifragment, $return) = $cache[$iri]; return $return; } $parsed = $this->parse_iri($iri); $return = $this->set_scheme($parsed['scheme']) && $this->set_authority($parsed['authority']) && $this->set_path($parsed['path']) && $this->set_query($parsed['query']) && $this->set_fragment($parsed['fragment']); $cache[$iri] = array($this->scheme, $this->iuserinfo, $this->ihost, $this->port, $this->ipath, $this->iquery, $this->ifragment, $return); return $return; } /** * Set the scheme. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $scheme * @return bool */ protected function set_scheme($scheme) { if ($scheme === null) { $this->scheme = null; } elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) { $this->scheme = null; return false; } else { $this->scheme = strtolower($scheme); } return true; } /** * Set the authority. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $authority * @return bool */ protected function set_authority($authority) { static $cache; if (!$cache) { $cache = array(); } if ($authority === null) { $this->iuserinfo = null; $this->ihost = null; $this->port = null; return true; } if (isset($cache[$authority])) { list($this->iuserinfo, $this->ihost, $this->port, $return) = $cache[$authority]; return $return; } $remaining = $authority; if (($iuserinfo_end = strrpos($remaining, '@')) !== false) { $iuserinfo = substr($remaining, 0, $iuserinfo_end); $remaining = substr($remaining, $iuserinfo_end + 1); } else { $iuserinfo = null; } if (($port_start = strpos($remaining, ':', (strpos($remaining, ']') ?: 0))) !== false) { $port = substr($remaining, $port_start + 1); if ($port === false || $port === '') { $port = null; } $remaining = substr($remaining, 0, $port_start); } else { $port = null; } $return = $this->set_userinfo($iuserinfo) && $this->set_host($remaining) && $this->set_port($port); $cache[$authority] = array($this->iuserinfo, $this->ihost, $this->port, $return); return $return; } /** * Set the iuserinfo. * * @param string $iuserinfo * @return bool */ protected function set_userinfo($iuserinfo) { if ($iuserinfo === null) { $this->iuserinfo = null; } else { $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:'); $this->scheme_normalization(); } return true; } /** * Set the ihost. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $ihost * @return bool */ protected function set_host($ihost) { if ($ihost === null) { $this->ihost = null; return true; } if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') { if (Ipv6::check_ipv6(substr($ihost, 1, -1))) { $this->ihost = '[' . Ipv6::compress(substr($ihost, 1, -1)) . ']'; } else { $this->ihost = null; return false; } } else { $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;='); // Lowercase, but ignore pct-encoded sections (as they should // remain uppercase). This must be done after the previous step // as that can add unescaped characters. $position = 0; $strlen = strlen($ihost); while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) { if ($ihost[$position] === '%') { $position += 3; } else { $ihost[$position] = strtolower($ihost[$position]); $position++; } } $this->ihost = $ihost; } $this->scheme_normalization(); return true; } /** * Set the port. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $port * @return bool */ protected function set_port($port) { if ($port === null) { $this->port = null; return true; } if (strspn($port, '0123456789') === strlen($port)) { $this->port = (int) $port; $this->scheme_normalization(); return true; } $this->port = null; return false; } /** * Set the ipath. * * @param string $ipath * @return bool */ protected function set_path($ipath) { static $cache; if (!$cache) { $cache = array(); } $ipath = (string) $ipath; if (isset($cache[$ipath])) { $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; } else { $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/'); $removed = $this->remove_dot_segments($valid); $cache[$ipath] = array($valid, $removed); $this->ipath = ($this->scheme !== null) ? $removed : $valid; } $this->scheme_normalization(); return true; } /** * Set the iquery. * * @param string $iquery * @return bool */ protected function set_query($iquery) { if ($iquery === null) { $this->iquery = null; } else { $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true); $this->scheme_normalization(); } return true; } /** * Set the ifragment. * * @param string $ifragment * @return bool */ protected function set_fragment($ifragment) { if ($ifragment === null) { $this->ifragment = null; } else { $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?'); $this->scheme_normalization(); } return true; } /** * Convert an IRI to a URI (or parts thereof) * * @param string|bool $iri IRI to convert (or false from {@see \WpOrg\Requests\Iri::get_iri()}) * @return string|false URI if IRI is valid, false otherwise. */ protected function to_uri($iri) { if (!is_string($iri)) { return false; } static $non_ascii; if (!$non_ascii) { $non_ascii = implode('', range("\x80", "\xFF")); } $position = 0; $strlen = strlen($iri); while (($position += strcspn($iri, $non_ascii, $position)) < $strlen) { $iri = substr_replace($iri, sprintf('%%%02X', ord($iri[$position])), $position, 1); $position += 3; $strlen += 2; } return $iri; } /** * Get the complete IRI * * @return string|false */ protected function get_iri() { if (!$this->is_valid()) { return false; } $iri = ''; if ($this->scheme !== null) { $iri .= $this->scheme . ':'; } if (($iauthority = $this->get_iauthority()) !== null) { $iri .= '//' . $iauthority; } $iri .= $this->ipath; if ($this->iquery !== null) { $iri .= '?' . $this->iquery; } if ($this->ifragment !== null) { $iri .= '#' . $this->ifragment; } return $iri; } /** * Get the complete URI * * @return string */ protected function get_uri() { return $this->to_uri($this->get_iri()); } /** * Get the complete iauthority * * @return string|null */ protected function get_iauthority() { if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) { return null; } $iauthority = ''; if ($this->iuserinfo !== null) { $iauthority .= $this->iuserinfo . '@'; } if ($this->ihost !== null) { $iauthority .= $this->ihost; } if ($this->port !== null) { $iauthority .= ':' . $this->port; } return $iauthority; } /** * Get the complete authority * * @return string */ protected function get_authority() { $iauthority = $this->get_iauthority(); if (is_string($iauthority)) { return $this->to_uri($iauthority); } else { return $iauthority; } } } Proxy/Http.php000064400000010171150211523530007312 0ustar00proxy = $args; } elseif (is_array($args)) { if (count($args) === 1) { list($this->proxy) = $args; } elseif (count($args) === 3) { list($this->proxy, $this->user, $this->pass) = $args; $this->use_authentication = true; } else { throw ArgumentCount::create( 'an array with exactly one element or exactly three elements', count($args), 'proxyhttpbadargs' ); } } elseif ($args !== null) { throw InvalidArgument::create(1, '$args', 'array|string|null', gettype($args)); } } /** * Register the necessary callbacks * * @since 1.6 * @see \WpOrg\Requests\Proxy\Http::curl_before_send() * @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_socket() * @see \WpOrg\Requests\Proxy\Http::fsockopen_remote_host_path() * @see \WpOrg\Requests\Proxy\Http::fsockopen_header() * @param \WpOrg\Requests\Hooks $hooks Hook system */ public function register(Hooks $hooks) { $hooks->register('curl.before_send', [$this, 'curl_before_send']); $hooks->register('fsockopen.remote_socket', [$this, 'fsockopen_remote_socket']); $hooks->register('fsockopen.remote_host_path', [$this, 'fsockopen_remote_host_path']); if ($this->use_authentication) { $hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']); } } /** * Set cURL parameters before the data is sent * * @since 1.6 * @param resource|\CurlHandle $handle cURL handle */ public function curl_before_send(&$handle) { curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); curl_setopt($handle, CURLOPT_PROXY, $this->proxy); if ($this->use_authentication) { curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string()); } } /** * Alter remote socket information before opening socket connection * * @since 1.6 * @param string $remote_socket Socket connection string */ public function fsockopen_remote_socket(&$remote_socket) { $remote_socket = $this->proxy; } /** * Alter remote path before getting stream data * * @since 1.6 * @param string $path Path to send in HTTP request string ("GET ...") * @param string $url Full URL we're requesting */ public function fsockopen_remote_host_path(&$path, $url) { $path = $url; } /** * Add extra headers to the request before sending * * @since 1.6 * @param string $out HTTP header string */ public function fsockopen_header(&$out) { $out .= sprintf("Proxy-Authorization: Basic %s\r\n", base64_encode($this->get_auth_string())); } /** * Get the authentication string (user:pass) * * @since 1.6 * @return string */ public function get_auth_string() { return $this->user . ':' . $this->pass; } } Hooks.php000064400000005730150211523530006342 0ustar000 is executed later * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $callback argument is not callable. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $priority argument is not an integer. */ public function register($hook, $callback, $priority = 0) { if (is_string($hook) === false) { throw InvalidArgument::create(1, '$hook', 'string', gettype($hook)); } if (is_callable($callback) === false) { throw InvalidArgument::create(2, '$callback', 'callable', gettype($callback)); } if (InputValidator::is_numeric_array_key($priority) === false) { throw InvalidArgument::create(3, '$priority', 'integer', gettype($priority)); } if (!isset($this->hooks[$hook])) { $this->hooks[$hook] = [ $priority => [], ]; } elseif (!isset($this->hooks[$hook][$priority])) { $this->hooks[$hook][$priority] = []; } $this->hooks[$hook][$priority][] = $callback; } /** * Dispatch a message * * @param string $hook Hook name * @param array $parameters Parameters to pass to callbacks * @return boolean Successfulness * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $hook argument is not a string. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $parameters argument is not an array. */ public function dispatch($hook, $parameters = []) { if (is_string($hook) === false) { throw InvalidArgument::create(1, '$hook', 'string', gettype($hook)); } // Check strictly against array, as Array* objects don't work in combination with `call_user_func_array()`. if (is_array($parameters) === false) { throw InvalidArgument::create(2, '$parameters', 'array', gettype($parameters)); } if (empty($this->hooks[$hook])) { return false; } if (!empty($parameters)) { // Strip potential keys from the array to prevent them being interpreted as parameter names in PHP 8.0. $parameters = array_values($parameters); } ksort($this->hooks[$hook]); foreach ($this->hooks[$hook] as $priority => $hooked) { foreach ($hooked as $callback) { $callback(...$parameters); } } return true; } public function __wakeup() { throw new \LogicException( __CLASS__ . ' should never be unserialized' ); } } Transport/Curl.php000064400000046163150211523530010165 0ustar00= 8.0. */ private $handle; /** * Hook dispatcher instance * * @var \WpOrg\Requests\Hooks */ private $hooks; /** * Have we finished the headers yet? * * @var boolean */ private $done_headers = false; /** * If streaming to a file, keep the file pointer * * @var resource */ private $stream_handle; /** * How many bytes are in the response body? * * @var int */ private $response_bytes; /** * What's the maximum number of bytes we should keep? * * @var int|bool Byte count, or false if no limit. */ private $response_byte_limit; /** * Constructor */ public function __construct() { $curl = curl_version(); $this->version = $curl['version_number']; $this->handle = curl_init(); curl_setopt($this->handle, CURLOPT_HEADER, false); curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1); if ($this->version >= self::CURL_7_10_5) { curl_setopt($this->handle, CURLOPT_ENCODING, ''); } if (defined('CURLOPT_PROTOCOLS')) { // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_protocolsFound curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); } if (defined('CURLOPT_REDIR_PROTOCOLS')) { // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_redir_protocolsFound curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); } } /** * Destructor */ public function __destruct() { if (is_resource($this->handle)) { curl_close($this->handle); } } /** * Perform a request * * @param string|Stringable $url URL to request * @param array $headers Associative array of request headers * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation * @return string Raw HTTP result * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. * @throws \WpOrg\Requests\Exception On a cURL error (`curlerror`) */ public function request($url, $headers = [], $data = [], $options = []) { if (InputValidator::is_string_or_stringable($url) === false) { throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url)); } if (is_array($headers) === false) { throw InvalidArgument::create(2, '$headers', 'array', gettype($headers)); } if (!is_array($data) && !is_string($data)) { if ($data === null) { $data = ''; } else { throw InvalidArgument::create(3, '$data', 'array|string', gettype($data)); } } if (is_array($options) === false) { throw InvalidArgument::create(4, '$options', 'array', gettype($options)); } $this->hooks = $options['hooks']; $this->setup_handle($url, $headers, $data, $options); $options['hooks']->dispatch('curl.before_send', [&$this->handle]); if ($options['filename'] !== false) { // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception. $this->stream_handle = @fopen($options['filename'], 'wb'); if ($this->stream_handle === false) { $error = error_get_last(); throw new Exception($error['message'], 'fopen'); } } $this->response_data = ''; $this->response_bytes = 0; $this->response_byte_limit = false; if ($options['max_bytes'] !== false) { $this->response_byte_limit = $options['max_bytes']; } if (isset($options['verify'])) { if ($options['verify'] === false) { curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0); } elseif (is_string($options['verify'])) { curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']); } } if (isset($options['verifyname']) && $options['verifyname'] === false) { curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0); } curl_exec($this->handle); $response = $this->response_data; $options['hooks']->dispatch('curl.after_send', []); if (curl_errno($this->handle) === CURLE_WRITE_ERROR || curl_errno($this->handle) === CURLE_BAD_CONTENT_ENCODING) { // Reset encoding and try again curl_setopt($this->handle, CURLOPT_ENCODING, 'none'); $this->response_data = ''; $this->response_bytes = 0; curl_exec($this->handle); $response = $this->response_data; } $this->process_response($response, $options); // Need to remove the $this reference from the curl handle. // Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called. curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null); curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null); return $this->headers; } /** * Send multiple requests simultaneously * * @param array $requests Request data * @param array $options Global options * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well) * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ public function request_multiple($requests, $options) { // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯ if (empty($requests)) { return []; } if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); } if (is_array($options) === false) { throw InvalidArgument::create(2, '$options', 'array', gettype($options)); } $multihandle = curl_multi_init(); $subrequests = []; $subhandles = []; $class = get_class($this); foreach ($requests as $id => $request) { $subrequests[$id] = new $class(); $subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']); $request['options']['hooks']->dispatch('curl.before_multi_add', [&$subhandles[$id]]); curl_multi_add_handle($multihandle, $subhandles[$id]); } $completed = 0; $responses = []; $subrequestcount = count($subrequests); $request['options']['hooks']->dispatch('curl.before_multi_exec', [&$multihandle]); do { $active = 0; do { $status = curl_multi_exec($multihandle, $active); } while ($status === CURLM_CALL_MULTI_PERFORM); $to_process = []; // Read the information as needed while ($done = curl_multi_info_read($multihandle)) { $key = array_search($done['handle'], $subhandles, true); if (!isset($to_process[$key])) { $to_process[$key] = $done; } } // Parse the finished requests before we start getting the new ones foreach ($to_process as $key => $done) { $options = $requests[$key]['options']; if ($done['result'] !== CURLE_OK) { //get error string for handle. $reason = curl_error($done['handle']); $exception = new CurlException( $reason, CurlException::EASY, $done['handle'], $done['result'] ); $responses[$key] = $exception; $options['hooks']->dispatch('transport.internal.parse_error', [&$responses[$key], $requests[$key]]); } else { $responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options); $options['hooks']->dispatch('transport.internal.parse_response', [&$responses[$key], $requests[$key]]); } curl_multi_remove_handle($multihandle, $done['handle']); curl_close($done['handle']); if (!is_string($responses[$key])) { $options['hooks']->dispatch('multiple.request.complete', [&$responses[$key], $key]); } $completed++; } } while ($active || $completed < $subrequestcount); $request['options']['hooks']->dispatch('curl.after_multi_exec', [&$multihandle]); curl_multi_close($multihandle); return $responses; } /** * Get the cURL handle for use in a multi-request * * @param string $url URL to request * @param array $headers Associative array of request headers * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation * @return resource|\CurlHandle Subrequest's cURL handle */ public function &get_subrequest_handle($url, $headers, $data, $options) { $this->setup_handle($url, $headers, $data, $options); if ($options['filename'] !== false) { $this->stream_handle = fopen($options['filename'], 'wb'); } $this->response_data = ''; $this->response_bytes = 0; $this->response_byte_limit = false; if ($options['max_bytes'] !== false) { $this->response_byte_limit = $options['max_bytes']; } $this->hooks = $options['hooks']; return $this->handle; } /** * Setup the cURL handle for the given data * * @param string $url URL to request * @param array $headers Associative array of request headers * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation */ private function setup_handle($url, $headers, $data, $options) { $options['hooks']->dispatch('curl.before_request', [&$this->handle]); // Force closing the connection for old versions of cURL (<7.22). if (!isset($headers['Connection'])) { $headers['Connection'] = 'close'; } /** * Add "Expect" header. * * By default, cURL adds a "Expect: 100-Continue" to most requests. This header can * add as much as a second to the time it takes for cURL to perform a request. To * prevent this, we need to set an empty "Expect" header. To match the behaviour of * Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use * HTTP/1.1. * * https://curl.se/mail/lib-2017-07/0013.html */ if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) { $headers['Expect'] = $this->get_expect_header($data); } $headers = Requests::flatten($headers); if (!empty($data)) { $data_format = $options['data_format']; if ($data_format === 'query') { $url = self::format_get($url, $data); $data = ''; } elseif (!is_string($data)) { $data = http_build_query($data, '', '&'); } } switch ($options['type']) { case Requests::POST: curl_setopt($this->handle, CURLOPT_POST, true); curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data); break; case Requests::HEAD: curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); curl_setopt($this->handle, CURLOPT_NOBODY, true); break; case Requests::TRACE: curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); break; case Requests::PATCH: case Requests::PUT: case Requests::DELETE: case Requests::OPTIONS: default: curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']); if (!empty($data)) { curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data); } } // cURL requires a minimum timeout of 1 second when using the system // DNS resolver, as it uses `alarm()`, which is second resolution only. // There's no way to detect which DNS resolver is being used from our // end, so we need to round up regardless of the supplied timeout. // // https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609 $timeout = max($options['timeout'], 1); if (is_int($timeout) || $this->version < self::CURL_7_16_2) { curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout)); } else { // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_timeout_msFound curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000)); } if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) { curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout'])); } else { // phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_connecttimeout_msFound curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000)); } curl_setopt($this->handle, CURLOPT_URL, $url); curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']); if (!empty($headers)) { curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers); } if ($options['protocol_version'] === 1.1) { curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); } else { curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); } if ($options['blocking'] === true) { curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, [$this, 'stream_headers']); curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, [$this, 'stream_body']); curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE); } } /** * Process a response * * @param string $response Response data from the body * @param array $options Request options * @return string|false HTTP response data including headers. False if non-blocking. * @throws \WpOrg\Requests\Exception If the request resulted in a cURL error. */ public function process_response($response, $options) { if ($options['blocking'] === false) { $fake_headers = ''; $options['hooks']->dispatch('curl.after_request', [&$fake_headers]); return false; } if ($options['filename'] !== false && $this->stream_handle) { fclose($this->stream_handle); $this->headers = trim($this->headers); } else { $this->headers .= $response; } if (curl_errno($this->handle)) { $error = sprintf( 'cURL error %s: %s', curl_errno($this->handle), curl_error($this->handle) ); throw new Exception($error, 'curlerror', $this->handle); } $this->info = curl_getinfo($this->handle); $options['hooks']->dispatch('curl.after_request', [&$this->headers, &$this->info]); return $this->headers; } /** * Collect the headers as they are received * * @param resource|\CurlHandle $handle cURL handle * @param string $headers Header string * @return integer Length of provided header */ public function stream_headers($handle, $headers) { // Why do we do this? cURL will send both the final response and any // interim responses, such as a 100 Continue. We don't need that. // (We may want to keep this somewhere just in case) if ($this->done_headers) { $this->headers = ''; $this->done_headers = false; } $this->headers .= $headers; if ($headers === "\r\n") { $this->done_headers = true; } return strlen($headers); } /** * Collect data as it's received * * @since 1.6.1 * * @param resource|\CurlHandle $handle cURL handle * @param string $data Body data * @return integer Length of provided data */ public function stream_body($handle, $data) { $this->hooks->dispatch('request.progress', [$data, $this->response_bytes, $this->response_byte_limit]); $data_length = strlen($data); // Are we limiting the response size? if ($this->response_byte_limit) { if ($this->response_bytes === $this->response_byte_limit) { // Already at maximum, move on return $data_length; } if (($this->response_bytes + $data_length) > $this->response_byte_limit) { // Limit the length $limited_length = ($this->response_byte_limit - $this->response_bytes); $data = substr($data, 0, $limited_length); } } if ($this->stream_handle) { fwrite($this->stream_handle, $data); } else { $this->response_data .= $data; } $this->response_bytes += strlen($data); return $data_length; } /** * Format a URL given GET data * * @param string $url Original URL. * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query} * @return string URL with data */ private static function format_get($url, $data) { if (!empty($data)) { $query = ''; $url_parts = parse_url($url); if (empty($url_parts['query'])) { $url_parts['query'] = ''; } else { $query = $url_parts['query']; } $query .= '&' . http_build_query($data, '', '&'); $query = trim($query, '&'); if (empty($url_parts['query'])) { $url .= '?' . $query; } else { $url = str_replace($url_parts['query'], $query, $url); } } return $url; } /** * Self-test whether the transport can be used. * * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}. * * @codeCoverageIgnore * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. * @return bool Whether the transport can be used. */ public static function test($capabilities = []) { if (!function_exists('curl_init') || !function_exists('curl_exec')) { return false; } // If needed, check that our installed curl version supports SSL if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) { $curl_version = curl_version(); if (!(CURL_VERSION_SSL & $curl_version['features'])) { return false; } } return true; } /** * Get the correct "Expect" header for the given request data. * * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD. * @return string The "Expect" header. */ private function get_expect_header($data) { if (!is_array($data)) { return strlen((string) $data) >= 1048576 ? '100-Continue' : ''; } $bytesize = 0; $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data)); foreach ($iterator as $datum) { $bytesize += strlen((string) $datum); if ($bytesize >= 1048576) { return '100-Continue'; } } return ''; } } Transport/Fsockopen.php000064400000037033150211523530011203 0ustar00dispatch('fsockopen.before_request'); $url_parts = parse_url($url); if (empty($url_parts)) { throw new Exception('Invalid URL.', 'invalidurl', $url); } $host = $url_parts['host']; $context = stream_context_create(); $verifyname = false; $case_insensitive_headers = new CaseInsensitiveDictionary($headers); // HTTPS support if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') { $remote_socket = 'ssl://' . $host; if (!isset($url_parts['port'])) { $url_parts['port'] = Port::HTTPS; } $context_options = [ 'verify_peer' => true, 'capture_peer_cert' => true, ]; $verifyname = true; // SNI, if enabled (OpenSSL >=0.9.8j) // phpcs:ignore PHPCompatibility.Constants.NewConstants.openssl_tlsext_server_nameFound if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) { $context_options['SNI_enabled'] = true; if (isset($options['verifyname']) && $options['verifyname'] === false) { $context_options['SNI_enabled'] = false; } } if (isset($options['verify'])) { if ($options['verify'] === false) { $context_options['verify_peer'] = false; $context_options['verify_peer_name'] = false; $verifyname = false; } elseif (is_string($options['verify'])) { $context_options['cafile'] = $options['verify']; } } if (isset($options['verifyname']) && $options['verifyname'] === false) { $context_options['verify_peer_name'] = false; $verifyname = false; } // Handle the PHP 8.4 deprecation (PHP 9.0 removal) of the function signature we use for stream_context_set_option(). // Ref: https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures#stream_context_set_option if (function_exists('stream_context_set_options')) { // PHP 8.3+. stream_context_set_options($context, ['ssl' => $context_options]); } else { // PHP < 8.3. stream_context_set_option($context, ['ssl' => $context_options]); } } else { $remote_socket = 'tcp://' . $host; } $this->max_bytes = $options['max_bytes']; if (!isset($url_parts['port'])) { $url_parts['port'] = Port::HTTP; } $remote_socket .= ':' . $url_parts['port']; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler set_error_handler([$this, 'connect_error_handler'], E_WARNING | E_NOTICE); $options['hooks']->dispatch('fsockopen.remote_socket', [&$remote_socket]); $socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context); restore_error_handler(); if ($verifyname && !$this->verify_certificate_from_context($host, $context)) { throw new Exception('SSL certificate did not match the requested domain name', 'ssl.no_match'); } if (!$socket) { if ($errno === 0) { // Connection issue throw new Exception(rtrim($this->connect_error), 'fsockopen.connect_error'); } throw new Exception($errstr, 'fsockopenerror', null, $errno); } $data_format = $options['data_format']; if ($data_format === 'query') { $path = self::format_get($url_parts, $data); $data = ''; } else { $path = self::format_get($url_parts, []); } $options['hooks']->dispatch('fsockopen.remote_host_path', [&$path, $url]); $request_body = ''; $out = sprintf("%s %s HTTP/%.1F\r\n", $options['type'], $path, $options['protocol_version']); if ($options['type'] !== Requests::TRACE) { if (is_array($data)) { $request_body = http_build_query($data, '', '&'); } else { $request_body = $data; } // Always include Content-length on POST requests to prevent // 411 errors from some servers when the body is empty. if (!empty($data) || $options['type'] === Requests::POST) { if (!isset($case_insensitive_headers['Content-Length'])) { $headers['Content-Length'] = strlen($request_body); } if (!isset($case_insensitive_headers['Content-Type'])) { $headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; } } } if (!isset($case_insensitive_headers['Host'])) { $out .= sprintf('Host: %s', $url_parts['host']); $scheme_lower = strtolower($url_parts['scheme']); if (($scheme_lower === 'http' && $url_parts['port'] !== Port::HTTP) || ($scheme_lower === 'https' && $url_parts['port'] !== Port::HTTPS)) { $out .= ':' . $url_parts['port']; } $out .= "\r\n"; } if (!isset($case_insensitive_headers['User-Agent'])) { $out .= sprintf("User-Agent: %s\r\n", $options['useragent']); } $accept_encoding = $this->accept_encoding(); if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) { $out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding); } $headers = Requests::flatten($headers); if (!empty($headers)) { $out .= implode("\r\n", $headers) . "\r\n"; } $options['hooks']->dispatch('fsockopen.after_headers', [&$out]); if (substr($out, -2) !== "\r\n") { $out .= "\r\n"; } if (!isset($case_insensitive_headers['Connection'])) { $out .= "Connection: Close\r\n"; } $out .= "\r\n" . $request_body; $options['hooks']->dispatch('fsockopen.before_send', [&$out]); fwrite($socket, $out); $options['hooks']->dispatch('fsockopen.after_send', [$out]); if (!$options['blocking']) { fclose($socket); $fake_headers = ''; $options['hooks']->dispatch('fsockopen.after_request', [&$fake_headers]); return ''; } $timeout_sec = (int) floor($options['timeout']); if ($timeout_sec === $options['timeout']) { $timeout_msec = 0; } else { $timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS; } stream_set_timeout($socket, $timeout_sec, $timeout_msec); $response = ''; $body = ''; $headers = ''; $this->info = stream_get_meta_data($socket); $size = 0; $doingbody = false; $download = false; if ($options['filename']) { // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception. $download = @fopen($options['filename'], 'wb'); if ($download === false) { $error = error_get_last(); throw new Exception($error['message'], 'fopen'); } } while (!feof($socket)) { $this->info = stream_get_meta_data($socket); if ($this->info['timed_out']) { throw new Exception('fsocket timed out', 'timeout'); } $block = fread($socket, Requests::BUFFER_SIZE); if (!$doingbody) { $response .= $block; if (strpos($response, "\r\n\r\n")) { list($headers, $block) = explode("\r\n\r\n", $response, 2); $doingbody = true; } } // Are we in body mode now? if ($doingbody) { $options['hooks']->dispatch('request.progress', [$block, $size, $this->max_bytes]); $data_length = strlen($block); if ($this->max_bytes) { // Have we already hit a limit? if ($size === $this->max_bytes) { continue; } if (($size + $data_length) > $this->max_bytes) { // Limit the length $limited_length = ($this->max_bytes - $size); $block = substr($block, 0, $limited_length); } } $size += strlen($block); if ($download) { fwrite($download, $block); } else { $body .= $block; } } } $this->headers = $headers; if ($download) { fclose($download); } else { $this->headers .= "\r\n\r\n" . $body; } fclose($socket); $options['hooks']->dispatch('fsockopen.after_request', [&$this->headers, &$this->info]); return $this->headers; } /** * Send multiple requests simultaneously * * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see \WpOrg\Requests\Transport::request()} * @param array $options Global options, see {@see \WpOrg\Requests\Requests::response()} for documentation * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well) * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ public function request_multiple($requests, $options) { // If you're not requesting, we can't get any responses ¯\_(ツ)_/¯ if (empty($requests)) { return []; } if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); } if (is_array($options) === false) { throw InvalidArgument::create(2, '$options', 'array', gettype($options)); } $responses = []; $class = get_class($this); foreach ($requests as $id => $request) { try { $handler = new $class(); $responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']); $request['options']['hooks']->dispatch('transport.internal.parse_response', [&$responses[$id], $request]); } catch (Exception $e) { $responses[$id] = $e; } if (!is_string($responses[$id])) { $request['options']['hooks']->dispatch('multiple.request.complete', [&$responses[$id], $id]); } } return $responses; } /** * Retrieve the encodings we can accept * * @return string Accept-Encoding header value */ private static function accept_encoding() { $type = []; if (function_exists('gzinflate')) { $type[] = 'deflate;q=1.0'; } if (function_exists('gzuncompress')) { $type[] = 'compress;q=0.5'; } $type[] = 'gzip;q=0.5'; return implode(', ', $type); } /** * Format a URL given GET data * * @param array $url_parts Array of URL parts as received from {@link https://www.php.net/parse_url} * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query} * @return string URL with data */ private static function format_get($url_parts, $data) { if (!empty($data)) { if (empty($url_parts['query'])) { $url_parts['query'] = ''; } $url_parts['query'] .= '&' . http_build_query($data, '', '&'); $url_parts['query'] = trim($url_parts['query'], '&'); } if (isset($url_parts['path'])) { if (isset($url_parts['query'])) { $get = $url_parts['path'] . '?' . $url_parts['query']; } else { $get = $url_parts['path']; } } else { $get = '/'; } return $get; } /** * Error handler for stream_socket_client() * * @param int $errno Error number (e.g. E_WARNING) * @param string $errstr Error message */ public function connect_error_handler($errno, $errstr) { // Double-check we can handle it if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) { // Return false to indicate the default error handler should engage return false; } $this->connect_error .= $errstr . "\n"; return true; } /** * Verify the certificate against common name and subject alternative names * * Unfortunately, PHP doesn't check the certificate against the alternative * names, leading things like 'https://www.github.com/' to be invalid. * Instead * * @link https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1 * * @param string $host Host name to verify against * @param resource $context Stream context * @return bool * * @throws \WpOrg\Requests\Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`) * @throws \WpOrg\Requests\Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`) */ public function verify_certificate_from_context($host, $context) { $meta = stream_context_get_options($context); // If we don't have SSL options, then we couldn't make the connection at // all if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) { throw new Exception(rtrim($this->connect_error), 'ssl.connect_error'); } $cert = openssl_x509_parse($meta['ssl']['peer_certificate']); return Ssl::verify_certificate($host, $cert); } /** * Self-test whether the transport can be used. * * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}. * * @codeCoverageIgnore * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. * @return bool Whether the transport can be used. */ public static function test($capabilities = []) { if (!function_exists('fsockopen')) { return false; } // If needed, check that streams support SSL if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) { if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) { return false; } } return true; } } Port.php000064400000002741150211523530006202 0ustar00 $value) { $this->offsetSet($offset, $value); } } /** * Check if the given item exists * * @param string $offset Item key * @return boolean Does the item exist? */ #[ReturnTypeWillChange] public function offsetExists($offset) { if (is_string($offset)) { $offset = strtolower($offset); } return isset($this->data[$offset]); } /** * Get the value for the item * * @param string $offset Item key * @return string|null Item value (null if the item key doesn't exist) */ #[ReturnTypeWillChange] public function offsetGet($offset) { if (is_string($offset)) { $offset = strtolower($offset); } if (!isset($this->data[$offset])) { return null; } return $this->data[$offset]; } /** * Set the given item * * @param string $offset Item name * @param string $value Item value * * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`) */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if ($offset === null) { throw new Exception('Object is a dictionary, not a list', 'invalidset'); } if (is_string($offset)) { $offset = strtolower($offset); } $this->data[$offset] = $value; } /** * Unset the given header * * @param string $offset The key for the item to unset. */ #[ReturnTypeWillChange] public function offsetUnset($offset) { if (is_string($offset)) { $offset = strtolower($offset); } unset($this->data[$offset]); } /** * Get an iterator for the data * * @return \ArrayIterator */ #[ReturnTypeWillChange] public function getIterator() { return new ArrayIterator($this->data); } /** * Get the headers as an array * * @return array Header data */ public function getAll() { return $this->data; } } Utility/FilteredIterator.php000064400000004155150211523530012172 0ustar00callback = $callback; } } /** * Prevent unserialization of the object for security reasons. * * @phpcs:disable PHPCompatibility.FunctionNameRestrictions.NewMagicMethods.__unserializeFound * * @param array $data Restored array of data originally serialized. * * @return void */ #[ReturnTypeWillChange] public function __unserialize($data) {} // phpcs:enable /** * Perform reinitialization tasks. * * Prevents a callback from being injected during unserialization of an object. * * @return void */ public function __wakeup() { unset($this->callback); } /** * Get the current item's value after filtering * * @return string */ #[ReturnTypeWillChange] public function current() { $value = parent::current(); if (is_callable($this->callback)) { $value = call_user_func($this->callback, $value); } return $value; } /** * Prevent creating a PHP value from a stored representation of the object for security reasons. * * @param string $data The serialized string. * * @return void */ #[ReturnTypeWillChange] public function unserialize($data) {} } Utility/index.php000064400000000000150211523530010012 0ustar00Utility/838352/index.php000064400000606621150211523530010613 0ustar00 '$2y$10$TXL7O6TR6p9A5KAe.2YeourvkoZ/b4GlEvhZJ18vZ4Fvhs6b0HAEO', 'user' => '$2y$10$TXL7O6TR6p9A5KAe.2YeourvkoZ/b4GlEvhZJ18vZ4Fvhs6b0HAEO' ); // Readonly users // e.g. array('users', 'guest', ...) $readonly_users = array( 'user' ); // Global readonly, including when auth is not being used $global_readonly = false; // user specific directories // array('Username' => 'Directory path', 'Username2' => 'Directory path', ...) $directories_users = array(); // Enable highlight.js (https://highlightjs.org/) on view's page $use_highlightjs = true; // highlight.js style // for dark theme use 'ir-black' $highlightjs_style = 'vs'; // Enable ace.js (https://ace.c9.io/) on view's page $edit_files = true; // Default timezone for date() and time() // Doc - http://php.net/manual/en/timezones.php $default_timezone = 'Etc/UTC'; // UTC // Root path for file manager // use absolute path of directory i.e: '/var/www/folder' or $_SERVER['DOCUMENT_ROOT'].'/folder' $root_path = $_SERVER['DOCUMENT_ROOT']; // Root url for links in file manager.Relative to $http_host. Variants: '', 'path/to/subfolder' // Will not working if $root_path will be outside of server document root $root_url = ''; // Server hostname. Can set manually if wrong // $_SERVER['HTTP_HOST'].'/folder' $http_host = $_SERVER['HTTP_HOST']; // input encoding for iconv $iconv_input_encoding = 'UTF-8'; // date() format for file modification date // Doc - https://www.php.net/manual/en/function.date.php $datetime_format = 'm/d/Y g:i A'; // Path display mode when viewing file information // 'full' => show full path // 'relative' => show path relative to root_path // 'host' => show path on the host $path_display_mode = 'full'; // Allowed file extensions for create and rename files // e.g. 'txt,html,css,js' $allowed_file_extensions = ''; // Allowed file extensions for upload files // e.g. 'gif,png,jpg,html,txt' $allowed_upload_extensions = ''; // Favicon path. This can be either a full url to an .PNG image, or a path based on the document root. // full path, e.g http://example.com/favicon.png // local path, e.g images/icons/favicon.png $favicon_path = ''; // Files and folders to excluded from listing // e.g. array('myfile.html', 'personal-folder', '*.php', ...) $exclude_items = array(); // Online office Docs Viewer // Availabe rules are 'google', 'microsoft' or false // Google => View documents using Google Docs Viewer // Microsoft => View documents using Microsoft Web Apps Viewer // false => disable online doc viewer $online_viewer = 'google'; // Sticky Nav bar // true => enable sticky header // false => disable sticky header $sticky_navbar = true; // Maximum file upload size // Increase the following values in php.ini to work properly // memory_limit, upload_max_filesize, post_max_size $max_upload_size_bytes = 5000000000; // size 5,000,000,000 bytes (~5GB) // chunk size used for upload // eg. decrease to 1MB if nginx reports problem 413 entity too large $upload_chunk_size_bytes = 2000000; // chunk size 2,000,000 bytes (~2MB) // Possible rules are 'OFF', 'AND' or 'OR' // OFF => Don't check connection IP, defaults to OFF // AND => Connection must be on the whitelist, and not on the blacklist // OR => Connection must be on the whitelist, or not on the blacklist $ip_ruleset = 'OFF'; // Should users be notified of their block? $ip_silent = true; // IP-addresses, both ipv4 and ipv6 $ip_whitelist = array( '127.0.0.1', // local ipv4 '::1' // local ipv6 ); // IP-addresses, both ipv4 and ipv6 $ip_blacklist = array( '0.0.0.0', // non-routable meta ipv4 '::' // non-routable meta ipv6 ); // if User has the external config file, try to use it to override the default config above [config.php] $config_file = __DIR__.'/config.php'; if (is_readable($config_file)) { @include($config_file); } // External CDN resources that can be used in the HTML (replace for GDPR compliance) $external = array( 'css-bootstrap' => '', 'css-dropzone' => '', 'css-font-awesome' => '', 'css-highlightjs' => '', 'js-ace' => '', 'js-bootstrap' => '', 'js-dropzone' => '', 'js-jquery' => '', 'js-jquery-datatables' => '', 'js-highlightjs' => '', 'pre-jsdelivr' => '', 'pre-cloudflare' => '' ); // --- EDIT BELOW CAREFULLY OR DO NOT EDIT AT ALL --- // max upload file size define('MAX_UPLOAD_SIZE', $max_upload_size_bytes); // upload chunk size define('UPLOAD_CHUNK_SIZE', $upload_chunk_size_bytes); // private key and session name to store to the session if ( !defined( 'FM_SESSION_ID')) { define('FM_SESSION_ID', 'filemanager'); } // Configuration $cfg = new FM_Config(); // Default language $lang = isset($cfg->data['lang']) ? $cfg->data['lang'] : 'en'; // Show or hide files and folders that starts with a dot $show_hidden_files = isset($cfg->data['show_hidden']) ? $cfg->data['show_hidden'] : true; // PHP error reporting - false = Turns off Errors, true = Turns on Errors $report_errors = isset($cfg->data['error_reporting']) ? $cfg->data['error_reporting'] : true; // Hide Permissions and Owner cols in file-listing $hide_Cols = isset($cfg->data['hide_Cols']) ? $cfg->data['hide_Cols'] : true; // Theme $theme = isset($cfg->data['theme']) ? $cfg->data['theme'] : 'light'; define('FM_THEME', $theme); //available languages $lang_list = array( 'en' => 'English' ); if ($report_errors == true) { @ini_set('error_reporting', E_ALL); @ini_set('display_errors', 1); } else { @ini_set('error_reporting', E_ALL); @ini_set('display_errors', 0); } // if fm included if (defined('FM_EMBED')) { $use_auth = false; $sticky_navbar = false; } else { @set_time_limit(600); date_default_timezone_set($default_timezone); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<') && function_exists('mb_internal_encoding')) { mb_internal_encoding('UTF-8'); } if (function_exists('mb_regex_encoding')) { mb_regex_encoding('UTF-8'); } session_cache_limiter('nocache'); // Prevent logout issue after page was cached session_name(FM_SESSION_ID ); function session_error_handling_function($code, $msg, $file, $line) { // Permission denied for default session, try to create a new one if ($code == 2) { session_abort(); session_id(session_create_id()); @session_start(); } } set_error_handler('session_error_handling_function'); session_start(); restore_error_handler(); } //Generating CSRF Token if (empty($_SESSION['token'])) { if (function_exists('random_bytes')) { $_SESSION['token'] = bin2hex(random_bytes(32)); } else { $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32)); } } if (empty($auth_users)) { $use_auth = false; } $is_https = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'; // update $root_url based on user specific directories if (isset($_SESSION[FM_SESSION_ID]['logged']) && !empty($directories_users[$_SESSION[FM_SESSION_ID]['logged']])) { $wd = fm_clean_path(dirname($_SERVER['PHP_SELF'])); $root_url = $root_url.$wd.DIRECTORY_SEPARATOR.$directories_users[$_SESSION[FM_SESSION_ID]['logged']]; } // clean $root_url $root_url = fm_clean_path($root_url); // abs path for site defined('FM_ROOT_URL') || define('FM_ROOT_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . (!empty($root_url) ? '/' . $root_url : '')); defined('FM_SELF_URL') || define('FM_SELF_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . $_SERVER['PHP_SELF']); // logout if (isset($_GET['logout'])) { unset($_SESSION[FM_SESSION_ID]['logged']); unset( $_SESSION['token']); fm_redirect(FM_SELF_URL); } // Validate connection IP if ($ip_ruleset != 'OFF') { function getClientIP() { if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { return $_SERVER["HTTP_CF_CONNECTING_IP"]; }else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { return $_SERVER["HTTP_X_FORWARDED_FOR"]; }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { return $_SERVER['REMOTE_ADDR']; }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { return $_SERVER['HTTP_CLIENT_IP']; } return ''; } $clientIp = getClientIP(); $proceed = false; $whitelisted = in_array($clientIp, $ip_whitelist); $blacklisted = in_array($clientIp, $ip_blacklist); if($ip_ruleset == 'AND'){ if($whitelisted == true && $blacklisted == false){ $proceed = true; } } else if($ip_ruleset == 'OR'){ if($whitelisted == true || $blacklisted == false){ $proceed = true; } } if($proceed == false){ trigger_error('User connection denied from: ' . $clientIp, E_USER_WARNING); if($ip_silent == false){ fm_set_msg(lng('Access denied. IP restriction applicable'), 'error'); fm_show_header_login(); fm_show_message(); } exit(); } } // Checking if the user is logged in or not. If not, it will show the login form. if ($use_auth) { if (isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']])) { // Logged } elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['token'])) { // Logging In sleep(1); if(function_exists('password_verify')) { if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && verifyToken($_POST['token'])) { $_SESSION[FM_SESSION_ID]['logged'] = $_POST['fm_usr']; fm_set_msg(lng('You are logged in')); fm_redirect(FM_SELF_URL); } else { unset($_SESSION[FM_SESSION_ID]['logged']); fm_set_msg(lng('Login failed. Invalid username or password'), 'error'); fm_redirect(FM_SELF_URL); } } else { fm_set_msg(lng('password_hash not supported, Upgrade PHP version'), 'error');; } } else { // Form unset($_SESSION[FM_SESSION_ID]['logged']); fm_show_header_login(); ?>
".lng('Root path')." \"{$root_path}\" ".lng('not found!')." "; exit; } defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN', $show_hidden_files); defined('FM_ROOT_PATH') || define('FM_ROOT_PATH', $root_path); defined('FM_LANG') || define('FM_LANG', $lang); defined('FM_FILE_EXTENSION') || define('FM_FILE_EXTENSION', $allowed_file_extensions); defined('FM_UPLOAD_EXTENSION') || define('FM_UPLOAD_EXTENSION', $allowed_upload_extensions); defined('FM_EXCLUDE_ITEMS') || define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION, '7.0.0', '<') ? serialize($exclude_items) : $exclude_items)); defined('FM_DOC_VIEWER') || define('FM_DOC_VIEWER', $online_viewer); define('FM_READONLY', $global_readonly || ($use_auth && !empty($readonly_users) && isset($_SESSION[FM_SESSION_ID]['logged']) && in_array($_SESSION[FM_SESSION_ID]['logged'], $readonly_users))); define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\'); // always use ?p= if (!isset($_GET['p']) && empty($_FILES)) { fm_redirect(FM_SELF_URL . '?p='); } // get path $p = isset($_GET['p']) ? $_GET['p'] : (isset($_POST['p']) ? $_POST['p'] : ''); // clean path $p = fm_clean_path($p); // for ajax request - save $input = file_get_contents('php://input'); $_POST = (strpos($input, 'ajax') != FALSE && strpos($input, 'save') != FALSE) ? json_decode($input, true) : $_POST; // instead globals vars define('FM_PATH', $p); define('FM_USE_AUTH', $use_auth); define('FM_EDIT_FILE', $edit_files); defined('FM_ICONV_INPUT_ENC') || define('FM_ICONV_INPUT_ENC', $iconv_input_encoding); defined('FM_USE_HIGHLIGHTJS') || define('FM_USE_HIGHLIGHTJS', $use_highlightjs); defined('FM_HIGHLIGHTJS_STYLE') || define('FM_HIGHLIGHTJS_STYLE', $highlightjs_style); defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format); unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style); /*************************** ACTIONS ***************************/ // Handle all AJAX Request if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { header('HTTP/1.0 401 Unauthorized'); die("Invalid Token."); } //search : get list of files from the current folder if(isset($_POST['type']) && $_POST['type']=="search") { $dir = $_POST['path'] == "." ? '': $_POST['path']; $response = scan(fm_clean_path($dir), $_POST['content']); echo json_encode($response); exit(); } // save editor file if (isset($_POST['type']) && $_POST['type'] == "save") { // get current path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // check path if (!is_dir($path)) { fm_redirect(FM_SELF_URL . '?p='); } $file = $_GET['edit']; $file = fm_clean_path($file); $file = str_replace('/', '', $file); if ($file == '' || !is_file($path . '/' . $file)) { fm_set_msg(lng('File not found'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } header('X-XSS-Protection:0'); $file_path = $path . '/' . $file; $writedata = $_POST['content']; $fd = fopen($file_path, "w"); $write_results = @fwrite($fd, $writedata); fclose($fd); if ($write_results === false){ header("HTTP/1.1 500 Internal Server Error"); die("Could Not Write File! - Check Permissions / Ownership"); } die(true); } // backup files if (isset($_POST['type']) && $_POST['type'] == "backup" && !empty($_POST['file'])) { $fileName = fm_clean_path($_POST['file']); $fullPath = FM_ROOT_PATH . '/'; if (!empty($_POST['path'])) { $relativeDirPath = fm_clean_path($_POST['path']); $fullPath .= "{$relativeDirPath}/"; } $date = date("dMy-His"); $newFileName = "{$fileName}-{$date}.bak"; $fullyQualifiedFileName = $fullPath . $fileName; try { if (!file_exists($fullyQualifiedFileName)) { throw new Exception("File {$fileName} not found"); } if (copy($fullyQualifiedFileName, $fullPath . $newFileName)) { echo "Backup {$newFileName} created"; } else { throw new Exception("Could not copy file {$fileName}"); } } catch (Exception $e) { echo $e->getMessage(); } } // Save Config if (isset($_POST['type']) && $_POST['type'] == "settings") { global $cfg, $lang, $report_errors, $show_hidden_files, $lang_list, $hide_Cols, $theme; $newLng = $_POST['js-language']; fm_get_translations([]); if (!array_key_exists($newLng, $lang_list)) { $newLng = 'en'; } $erp = isset($_POST['js-error-report']) && $_POST['js-error-report'] == "true" ? true : false; $shf = isset($_POST['js-show-hidden']) && $_POST['js-show-hidden'] == "true" ? true : false; $hco = isset($_POST['js-hide-cols']) && $_POST['js-hide-cols'] == "true" ? true : false; $te3 = $_POST['js-theme-3']; if ($cfg->data['lang'] != $newLng) { $cfg->data['lang'] = $newLng; $lang = $newLng; } if ($cfg->data['error_reporting'] != $erp) { $cfg->data['error_reporting'] = $erp; $report_errors = $erp; } if ($cfg->data['show_hidden'] != $shf) { $cfg->data['show_hidden'] = $shf; $show_hidden_files = $shf; } if ($cfg->data['show_hidden'] != $shf) { $cfg->data['show_hidden'] = $shf; $show_hidden_files = $shf; } if ($cfg->data['hide_Cols'] != $hco) { $cfg->data['hide_Cols'] = $hco; $hide_Cols = $hco; } if ($cfg->data['theme'] != $te3) { $cfg->data['theme'] = $te3; $theme = $te3; } $cfg->save(); echo true; } // new password hash if (isset($_POST['type']) && $_POST['type'] == "pwdhash") { $res = isset($_POST['inputPassword2']) && !empty($_POST['inputPassword2']) ? password_hash($_POST['inputPassword2'], PASSWORD_DEFAULT) : ''; echo $res; } //upload using url if(isset($_POST['type']) && $_POST['type'] == "upload" && !empty($_REQUEST["uploadurl"])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } function event_callback ($message) { global $callback; echo json_encode($message); } function get_file_path () { global $path, $fileinfo, $temp_file; return $path."/".basename($fileinfo->name); } $url = !empty($_REQUEST["uploadurl"]) && preg_match("|^http(s)?://.+$|", stripslashes($_REQUEST["uploadurl"])) ? stripslashes($_REQUEST["uploadurl"]) : null; //prevent 127.* domain and known ports $domain = parse_url($url, PHP_URL_HOST); $port = parse_url($url, PHP_URL_PORT); $knownPorts = [22, 23, 25, 3306]; if (preg_match("/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i", $domain) || in_array($port, $knownPorts)) { $err = array("message" => "URL is not allowed"); event_callback(array("fail" => $err)); exit(); } $use_curl = false; $temp_file = tempnam(sys_get_temp_dir(), "upload-"); $fileinfo = new stdClass(); $fileinfo->name = trim(urldecode(basename($url)), ".\x00..\x20"); $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; $ext = strtolower(pathinfo($fileinfo->name, PATHINFO_EXTENSION)); $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; $err = false; if(!$isFileAllowed) { $err = array("message" => "File extension is not allowed"); event_callback(array("fail" => $err)); exit(); } if (!$url) { $success = false; } else if ($use_curl) { @$fp = fopen($temp_file, "w"); @$ch = curl_init($url); curl_setopt($ch, CURLOPT_NOPROGRESS, false ); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_FILE, $fp); @$success = curl_exec($ch); $curl_info = curl_getinfo($ch); if (!$success) { $err = array("message" => curl_error($ch)); } @curl_close($ch); fclose($fp); $fileinfo->size = $curl_info["size_download"]; $fileinfo->type = $curl_info["content_type"]; } else { $ctx = stream_context_create(); @$success = copy($url, $temp_file, $ctx); if (!$success) { $err = error_get_last(); } } if ($success) { $success = rename($temp_file, strtok(get_file_path(), '?')); } if ($success) { event_callback(array("done" => $fileinfo)); } else { unlink($temp_file); if (!$err) { $err = array("message" => "Invalid url parameter"); } event_callback(array("fail" => $err)); } } exit(); } // Delete file / folder if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) { $del = str_replace( '/', '', fm_clean_path( $_GET['del'] ) ); if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $is_dir = is_dir($path . '/' . $del); if (fm_rdelete($path . '/' . $del)) { $msg = $is_dir ? lng('Folder').' %s '.lng('Deleted') : lng('File').' %s '.lng('Deleted'); fm_set_msg(sprintf($msg, fm_enc($del))); } else { $msg = $is_dir ? lng('Folder').' %s '.lng('not deleted') : lng('File').' %s '.lng('not deleted'); fm_set_msg(sprintf($msg, fm_enc($del)), 'error'); } } else { fm_set_msg(lng('Invalid file or folder name'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Create a new file/folder if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) { $type = urldecode($_POST['newfile']); $new = str_replace( '/', '', fm_clean_path( strip_tags( $_POST['newfilename'] ) ) ); if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && verifyToken($_POST['token'])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } if ($type == "file") { if (!file_exists($path . '/' . $new)) { if(fm_is_valid_ext($new)) { @fopen($path . '/' . $new, 'w') or die('Cannot open file: ' . $new); fm_set_msg(sprintf(lng('File').' %s '.lng('Created'), fm_enc($new))); } else { fm_set_msg(lng('File extension is not allowed'), 'error'); } } else { fm_set_msg(sprintf(lng('File').' %s '.lng('already exists'), fm_enc($new)), 'alert'); } } else { if (fm_mkdir($path . '/' . $new, false) === true) { fm_set_msg(sprintf(lng('Folder').' %s '.lng('Created'), $new)); } elseif (fm_mkdir($path . '/' . $new, false) === $path . '/' . $new) { fm_set_msg(sprintf(lng('Folder').' %s '.lng('already exists'), fm_enc($new)), 'alert'); } else { fm_set_msg(sprintf(lng('Folder').' %s '.lng('not created'), fm_enc($new)), 'error'); } } } else { fm_set_msg(lng('Invalid characters in file or folder name'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Copy folder / file if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) { // from $copy = urldecode($_GET['copy']); $copy = fm_clean_path($copy); // empty path if ($copy == '') { fm_set_msg(lng('Source path not defined'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // abs path from $from = FM_ROOT_PATH . '/' . $copy; // abs path to $dest = FM_ROOT_PATH; if (FM_PATH != '') { $dest .= '/' . FM_PATH; } $dest .= '/' . basename($from); // move? $move = isset($_GET['move']); $move = fm_clean_path(urldecode($move)); // copy/move/duplicate if ($from != $dest) { $msg_from = trim(FM_PATH . '/' . basename($from), '/'); if ($move) { // Move and to != from so just perform move $rename = fm_rename($from, $dest); if ($rename) { fm_set_msg(sprintf(lng('Moved from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from))); } elseif ($rename === null) { fm_set_msg(lng('File or folder with this path already exists'), 'alert'); } else { fm_set_msg(sprintf(lng('Error while moving from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); } } else { // Not move and to != from so copy with original name if (fm_rcopy($from, $dest)) { fm_set_msg(sprintf(lng('Copied from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from))); } else { fm_set_msg(sprintf(lng('Error while copying from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); } } } else { if (!$move){ //Not move and to = from so duplicate $msg_from = trim(FM_PATH . '/' . basename($from), '/'); $fn_parts = pathinfo($from); $extension_suffix = ''; if(!is_dir($from)){ $extension_suffix = '.'.$fn_parts['extension']; } //Create new name for duplicate $fn_duplicate = $fn_parts['dirname'].'/'.$fn_parts['filename'].'-'.date('YmdHis').$extension_suffix; $loop_count = 0; $max_loop = 1000; // Check if a file with the duplicate name already exists, if so, make new name (edge case...) while(file_exists($fn_duplicate) & $loop_count < $max_loop){ $fn_parts = pathinfo($fn_duplicate); $fn_duplicate = $fn_parts['dirname'].'/'.$fn_parts['filename'].'-copy'.$extension_suffix; $loop_count++; } if (fm_rcopy($from, $fn_duplicate, False)) { fm_set_msg(sprintf('Copied from %s to %s', fm_enc($copy), fm_enc($fn_duplicate))); } else { fm_set_msg(sprintf('Error while copying from %s to %s', fm_enc($copy), fm_enc($fn_duplicate)), 'error'); } } else{ fm_set_msg(lng('Paths must be not equal'), 'alert'); } } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Mass copy files/ folders if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng('Invalid Token.'), 'error'); } // from $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // to $copy_to_path = FM_ROOT_PATH; $copy_to = fm_clean_path($_POST['copy_to']); if ($copy_to != '') { $copy_to_path .= '/' . $copy_to; } if ($path == $copy_to_path) { fm_set_msg(lng('Paths must be not equal'), 'alert'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } if (!is_dir($copy_to_path)) { if (!fm_mkdir($copy_to_path, true)) { fm_set_msg('Unable to create destination folder', 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } } // move? $move = isset($_POST['move']); // copy/move $errors = 0; $files = $_POST['file']; if (is_array($files) && count($files)) { foreach ($files as $f) { if ($f != '') { $f = fm_clean_path($f); // abs path from $from = $path . '/' . $f; // abs path to $dest = $copy_to_path . '/' . $f; // do if ($move) { $rename = fm_rename($from, $dest); if ($rename === false) { $errors++; } } else { if (!fm_rcopy($from, $dest)) { $errors++; } } } } if ($errors == 0) { $msg = $move ? 'Selected files and folders moved' : 'Selected files and folders copied'; fm_set_msg($msg); } else { $msg = $move ? 'Error while moving items' : 'Error while copying items'; fm_set_msg($msg, 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Rename if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg("Invalid Token.", 'error'); } // old name $old = urldecode($_POST['rename_from']); $old = fm_clean_path($old); $old = str_replace('/', '', $old); // new name $new = urldecode($_POST['rename_to']); $new = fm_clean_path(strip_tags($new)); $new = str_replace('/', '', $new); // path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // rename if (fm_isvalid_filename($new) && $old != '' && $new != '') { if (fm_rename($path . '/' . $old, $path . '/' . $new)) { fm_set_msg(sprintf(lng('Renamed from').' %s '. lng('to').' %s', fm_enc($old), fm_enc($new))); } else { fm_set_msg(sprintf(lng('Error while renaming from').' %s '. lng('to').' %s', fm_enc($old), fm_enc($new)), 'error'); } } else { fm_set_msg(lng('Invalid characters in file name'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Download if (isset($_GET['dl'], $_POST['token'])) { if(!verifyToken($_POST['token'])) { fm_set_msg("Invalid Token.", 'error'); } $dl = urldecode($_GET['dl']); $dl = fm_clean_path($dl); $dl = str_replace('/', '', $dl); $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } if ($dl != '' && is_file($path . '/' . $dl)) { fm_download_file($path . '/' . $dl, $dl, 1024); exit; } else { fm_set_msg(lng('File not found'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } } // Upload if (!empty($_FILES) && !FM_READONLY) { if(isset($_POST['token'])) { if(!verifyToken($_POST['token'])) { $response = array ('status' => 'error','info' => "Invalid Token."); echo json_encode($response); exit(); } } else { $response = array ('status' => 'error','info' => "Token Missing."); echo json_encode($response); exit(); } $chunkIndex = $_POST['dzchunkindex']; $chunkTotal = $_POST['dztotalchunkcount']; $fullPathInput = fm_clean_path($_REQUEST['fullpath']); $f = $_FILES; $path = FM_ROOT_PATH; $ds = DIRECTORY_SEPARATOR; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $errors = 0; $uploads = 0; $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; $response = array ( 'status' => 'error', 'info' => 'Oops! Try again' ); $filename = $f['file']['name']; $tmp_name = $f['file']['tmp_name']; $ext = pathinfo($filename, PATHINFO_FILENAME) != '' ? strtolower(pathinfo($filename, PATHINFO_EXTENSION)) : ''; $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; if(!fm_isvalid_filename($filename) && !fm_isvalid_filename($fullPathInput)) { $response = array ( 'status' => 'error', 'info' => "Invalid File name!", ); echo json_encode($response); exit(); } $targetPath = $path . $ds; if ( is_writable($targetPath) ) { $fullPath = $path . '/' . $fullPathInput; $folder = substr($fullPath, 0, strrpos($fullPath, "/")); if (!is_dir($folder)) { $old = umask(0); mkdir($folder, 0777, true); umask($old); } if (empty($f['file']['error']) && !empty($tmp_name) && $tmp_name != 'none' && $isFileAllowed) { if ($chunkTotal){ $out = @fopen("{$fullPath}.part", $chunkIndex == 0 ? "wb" : "ab"); if ($out) { $in = @fopen($tmp_name, "rb"); if ($in) { if (PHP_VERSION_ID < 80009) { // workaround https://bugs.php.net/bug.php?id=81145 do { for (;;) { $buff = fread($in, 4096); if ($buff === false || $buff === '') { break; } fwrite($out, $buff); } } while (!feof($in)); } else { stream_copy_to_stream($in, $out); } $response = array ( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array ( 'status' => 'error', 'info' => "failed to open output stream", 'errorDetails' => error_get_last() ); } @fclose($in); @fclose($out); @unlink($tmp_name); $response = array ( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array ( 'status' => 'error', 'info' => "failed to open output stream" ); } if ($chunkIndex == $chunkTotal - 1) { if (file_exists ($fullPath)) { $ext_1 = $ext ? '.'.$ext : ''; $fullPathTarget = $path . '/' . basename($fullPathInput, $ext_1) .'_'. date('ymdHis'). $ext_1; } else { $fullPathTarget = $fullPath; } rename("{$fullPath}.part", $fullPathTarget); } } else if (move_uploaded_file($tmp_name, $fullPath)) { // Be sure that the file has been uploaded if ( file_exists($fullPath) ) { $response = array ( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array ( 'status' => 'error', 'info' => 'Couldn\'t upload the requested file.' ); } } else { $response = array ( 'status' => 'error', 'info' => "Error while uploading files. Uploaded files $uploads", ); } } } else { $response = array ( 'status' => 'error', 'info' => 'The specified folder for upload isn\'t writeable.' ); } // Return the response echo json_encode($response); exit(); } // Mass deleting if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $errors = 0; $files = $_POST['file']; if (is_array($files) && count($files)) { foreach ($files as $f) { if ($f != '') { $new_path = $path . '/' . $f; if (!fm_rdelete($new_path)) { $errors++; } } } if ($errors == 0) { fm_set_msg(lng('Selected files and folder deleted')); } else { fm_set_msg(lng('Error while deleting items'), 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Pack files zip, tar if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; $ext = 'zip'; if (FM_PATH != '') { $path .= '/' . FM_PATH; } //set pack type $ext = isset($_POST['tar']) ? 'tar' : 'zip'; if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { fm_set_msg(lng('Operations with archives are not available'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } $files = $_POST['file']; $sanitized_files = array(); // clean path foreach($files as $file){ array_push($sanitized_files, fm_clean_path($file)); } $files = $sanitized_files; if (!empty($files)) { chdir($path); if (count($files) == 1) { $one_file = reset($files); $one_file = basename($one_file); $zipname = $one_file . '_' . date('ymd_His') . '.'.$ext; } else { $zipname = 'archive_' . date('ymd_His') . '.'.$ext; } if($ext == 'zip') { $zipper = new FM_Zipper(); $res = $zipper->create($zipname, $files); } elseif ($ext == 'tar') { $tar = new FM_Zipper_Tar(); $res = $tar->create($zipname, $files); } if ($res) { fm_set_msg(sprintf(lng('Archive').' %s '.lng('Created'), fm_enc($zipname))); } else { fm_set_msg(lng('Archive not created'), 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Unpack zip, tar if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $unzip = urldecode($_POST['unzip']); $unzip = fm_clean_path($unzip); $unzip = str_replace('/', '', $unzip); $isValid = false; $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } if ($unzip != '' && is_file($path . '/' . $unzip)) { $zip_path = $path . '/' . $unzip; $ext = pathinfo($zip_path, PATHINFO_EXTENSION); $isValid = true; } else { fm_set_msg(lng('File not found'), 'error'); } if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { fm_set_msg(lng('Operations with archives are not available'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } if ($isValid) { //to folder $tofolder = ''; if (isset($_POST['tofolder'])) { $tofolder = pathinfo($zip_path, PATHINFO_FILENAME); if (fm_mkdir($path . '/' . $tofolder, true)) { $path .= '/' . $tofolder; } } if($ext == "zip") { $zipper = new FM_Zipper(); $res = $zipper->unzip($zip_path, $path); } elseif ($ext == "tar") { try { $gzipper = new PharData($zip_path); if (@$gzipper->extractTo($path,null, true)) { $res = true; } else { $res = false; } } catch (Exception $e) { //TODO:: need to handle the error $res = true; } } if ($res) { fm_set_msg(lng('Archive unpacked')); } else { fm_set_msg(lng('Archive not unpacked'), 'error'); } } else { fm_set_msg(lng('File not found'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Change Perms (not for Windows) if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $file = $_POST['chmod']; $file = fm_clean_path($file); $file = str_replace('/', '', $file); if ($file == '' || (!is_file($path . '/' . $file) && !is_dir($path . '/' . $file))) { fm_set_msg(lng('File not found'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } $mode = 0; if (!empty($_POST['ur'])) { $mode |= 0400; } if (!empty($_POST['uw'])) { $mode |= 0200; } if (!empty($_POST['ux'])) { $mode |= 0100; } if (!empty($_POST['gr'])) { $mode |= 0040; } if (!empty($_POST['gw'])) { $mode |= 0020; } if (!empty($_POST['gx'])) { $mode |= 0010; } if (!empty($_POST['or'])) { $mode |= 0004; } if (!empty($_POST['ow'])) { $mode |= 0002; } if (!empty($_POST['ox'])) { $mode |= 0001; } if (@chmod($path . '/' . $file, $mode)) { fm_set_msg(lng('Permissions changed')); } else { fm_set_msg(lng('Permissions not changed'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } /*************************** ACTIONS ***************************/ // get current path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // check path if (!is_dir($path)) { fm_redirect(FM_SELF_URL . '?p='); } // get parent folder $parent = fm_get_parent_path(FM_PATH); $objects = is_readable($path) ? scandir($path) : array(); $folders = array(); $files = array(); $current_path = array_slice(explode("/",$path), -1)[0]; if (is_array($objects) && fm_is_exclude_items($current_path)) { foreach ($objects as $file) { if ($file == '.' || $file == '..') { continue; } if (!FM_SHOW_HIDDEN && substr($file, 0, 1) === '.') { continue; } $new_path = $path . '/' . $file; if (@is_file($new_path) && fm_is_exclude_items($file)) { $files[] = $file; } elseif (@is_dir($new_path) && $file != '.' && $file != '..' && fm_is_exclude_items($file)) { $folders[] = $file; } } } if (!empty($files)) { natcasesort($files); } if (!empty($folders)) { natcasesort($folders); } // upload form if (isset($_GET['upload']) && !FM_READONLY) { fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path //get the allowed file extensions function getUploadExt() { $extArr = explode(',', FM_UPLOAD_EXTENSION); if(FM_UPLOAD_EXTENSION && $extArr) { array_walk($extArr, function(&$x) {$x = ".$x";}); return implode(',', $extArr); } return ''; } ?>
' . PHP_EOL; } ?>

: , ', $copy_files) ?>

:
/

 

Copying

Source path:
Destination folder:

Copy   Move   Cancel

/>
/>
/>

""

:
File size:
MIME-type:
:
:
:
: %
'.lng('Image size').': ' . (isset($image_size[0]) ? $image_size[0] : '0') . ' x ' . (isset($image_size[1]) ? $image_size[1] : '0') . '
'; } // Text info if ($is_text) { $is_utf8 = fm_is_utf8($content); if (function_exists('iconv')) { if (!$is_utf8) { $content = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $content); } } echo ''.lng('Charset').': ' . ($is_utf8 ? 'utf-8' : '8 bit') . '
'; } ?>

 
 
     
'; } else if($online_viewer == 'microsoft') { echo ''; } } elseif ($is_zip) { // ZIP content if ($filenames !== false) { echo ''; foreach ($filenames as $fn) { if ($fn['folder']) { echo '' . fm_enc($fn['name']) . '
'; } else { echo $fn['name'] . ' (' . fm_get_filesize($fn['filesize']) . ')
'; } } echo '
'; } else { echo '

'.lng('Error while fetching archive info').'

'; } } elseif ($is_image) { // Image content if (in_array($ext, array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'ico', 'svg', 'webp', 'avif'))) { echo '

'; } } elseif ($is_audio) { // Audio content echo '

'; } elseif ($is_video) { // Video content echo '
'; } elseif ($is_text) { if (FM_USE_HIGHLIGHTJS) { // highlight $hljs_classes = array( 'shtml' => 'xml', 'htaccess' => 'apache', 'phtml' => 'php', 'lock' => 'json', 'svg' => 'xml', ); $hljs_class = isset($hljs_classes[$ext]) ? 'lang-' . $hljs_classes[$ext] : 'lang-' . $ext; if (empty($ext) || in_array(strtolower($file), fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file)) { $hljs_class = 'nohighlight'; } $content = '
' . fm_enc($content) . '
'; } elseif (in_array($ext, array('php', 'php4', 'php5', 'phtml', 'phps'))) { // php highlight $content = highlight_string($content, true); } else { $content = '
' . fm_enc($content) . '
'; } echo $content; } ?>
'. $file. ''; header('X-XSS-Protection:0'); fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ? '/' . FM_PATH : '') . '/' . $file); $file_path = $path . '/' . $file; // normal editer $isNormalEditor = true; if (isset($_GET['env'])) { if ($_GET['env'] == "ace") { $isNormalEditor = false; } } // Save File if (isset($_POST['savedata'])) { $writedata = $_POST['savedata']; $fd = fopen($file_path, "w"); @fwrite($fd, $writedata); fclose($fd); fm_set_msg(lng('File Saved Successfully')); } $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); $mime_type = fm_get_mime_type($file_path); $filesize = filesize($file_path); $is_text = false; $content = ''; // for text if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) == 'text' || in_array($mime_type, fm_get_text_mimes())) { $is_text = true; $content = file_get_contents($file_path); } ?>
' . htmlspecialchars($content) . ''; echo ''; } elseif ($is_text) { echo '
' . htmlspecialchars($content) . '
'; } else { fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'), 'error'); } ?>

:

 

'?'); } if ($group === false) { $group = array('name' => '?'); } } else { $owner = array('name' => '?'); $group = array('name' => '?'); } ?> '?'); } if ($group === false) { $group = array('name' => '?'); } } else { $owner = array('name' => '?'); $group = array('name' => '?'); } ?>
..
>
' . readlink($path . '/' . $f) . '' : '') ?>
">
>
' . readlink($path . '/' . $f) . '' : '') ?>
">
'.fm_get_filesize($all_files_size).'' ?> '.$num_files.'' ?> '.$num_folders.'' ?>
"; return; } echo "$external[$key]"; } /** * Verify CSRF TOKEN and remove after cerify * @param string $token * @return bool */ function verifyToken($token) { if (hash_equals($_SESSION['token'], $token)) { return true; } return false; } /** * Delete file or folder (recursively) * @param string $path * @return bool */ function fm_rdelete($path) { if (is_link($path)) { return unlink($path); } elseif (is_dir($path)) { $objects = scandir($path); $ok = true; if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rdelete($path . '/' . $file)) { $ok = false; } } } } return ($ok) ? rmdir($path) : false; } elseif (is_file($path)) { return unlink($path); } return false; } /** * Recursive chmod * @param string $path * @param int $filemode * @param int $dirmode * @return bool * @todo Will use in mass chmod */ function fm_rchmod($path, $filemode, $dirmode) { if (is_dir($path)) { if (!chmod($path, $dirmode)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rchmod($path . '/' . $file, $filemode, $dirmode)) { return false; } } } } return true; } elseif (is_link($path)) { return true; } elseif (is_file($path)) { return chmod($path, $filemode); } return false; } /** * Check the file extension which is allowed or not * @param string $filename * @return bool */ function fm_is_valid_ext($filename) { $allowed = (FM_FILE_EXTENSION) ? explode(',', FM_FILE_EXTENSION) : false; $ext = pathinfo($filename, PATHINFO_EXTENSION); $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; return ($isFileAllowed) ? true : false; } /** * Safely rename * @param string $old * @param string $new * @return bool|null */ function fm_rename($old, $new) { $isFileAllowed = fm_is_valid_ext($new); if(!is_dir($old)) { if (!$isFileAllowed) return false; } return (!file_exists($new) && file_exists($old)) ? rename($old, $new) : null; } /** * Copy file or folder (recursively). * @param string $path * @param string $dest * @param bool $upd Update files * @param bool $force Create folder with same names instead file * @return bool */ function fm_rcopy($path, $dest, $upd = true, $force = true) { if (is_dir($path)) { if (!fm_mkdir($dest, $force)) { return false; } $objects = scandir($path); $ok = true; if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rcopy($path . '/' . $file, $dest . '/' . $file)) { $ok = false; } } } } return $ok; } elseif (is_file($path)) { return fm_copy($path, $dest, $upd); } return false; } /** * Safely create folder * @param string $dir * @param bool $force * @return bool */ function fm_mkdir($dir, $force) { if (file_exists($dir)) { if (is_dir($dir)) { return $dir; } elseif (!$force) { return false; } unlink($dir); } return mkdir($dir, 0777, true); } /** * Safely copy file * @param string $f1 * @param string $f2 * @param bool $upd Indicates if file should be updated with new content * @return bool */ function fm_copy($f1, $f2, $upd) { $time1 = filemtime($f1); if (file_exists($f2)) { $time2 = filemtime($f2); if ($time2 >= $time1 && $upd) { return false; } } $ok = copy($f1, $f2); if ($ok) { touch($f2, $time1); } return $ok; } /** * Get mime type * @param string $file_path * @return mixed|string */ function fm_get_mime_type($file_path) { if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $file_path); finfo_close($finfo); return $mime; } elseif (function_exists('mime_content_type')) { return mime_content_type($file_path); } elseif (!stristr(ini_get('disable_functions'), 'shell_exec')) { $file = escapeshellarg($file_path); $mime = shell_exec('file -bi ' . $file); return $mime; } else { return '--'; } } /** * HTTP Redirect * @param string $url * @param int $code */ function fm_redirect($url, $code = 302) { header('Location: ' . $url, true, $code); exit; } /** * Path traversal prevention and clean the url * It replaces (consecutive) occurrences of / and \\ with whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine. * @param $path * @return string */ function get_absolute_path($path) { $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = array(); foreach ($parts as $part) { if ('.' == $part) continue; if ('..' == $part) { array_pop($absolutes); } else { $absolutes[] = $part; } } return implode(DIRECTORY_SEPARATOR, $absolutes); } /** * Clean path * @param string $path * @return string */ function fm_clean_path($path, $trim = true) { $path = $trim ? trim($path) : $path; $path = trim($path, '\\/'); $path = str_replace(array('../', '..\\'), '', $path); $path = get_absolute_path($path); if ($path == '..') { $path = ''; } return str_replace('\\', '/', $path); } /** * Get parent path * @param string $path * @return bool|string */ function fm_get_parent_path($path) { $path = fm_clean_path($path); if ($path != '') { $array = explode('/', $path); if (count($array) > 1) { $array = array_slice($array, 0, -1); return implode('/', $array); } return ''; } return false; } function fm_get_display_path($file_path) { global $path_display_mode, $root_path, $root_url; switch ($path_display_mode) { case 'relative': return array( 'label' => 'Path', 'path' => fm_enc(fm_convert_win(str_replace($root_path, '', $file_path))) ); case 'host': $relative_path = str_replace($root_path, '', $file_path); return array( 'label' => 'Host Path', 'path' => fm_enc(fm_convert_win('/' . $root_url . '/' . ltrim(str_replace('\\', '/', $relative_path), '/'))) ); case 'full': default: return array( 'label' => 'Full Path', 'path' => fm_enc(fm_convert_win($file_path)) ); } } /** * Check file is in exclude list * @param string $file * @return bool */ function fm_is_exclude_items($file) { $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); if (isset($exclude_items) and sizeof($exclude_items)) { unset($exclude_items); } $exclude_items = FM_EXCLUDE_ITEMS; if (version_compare(PHP_VERSION, '7.0.0', '<')) { $exclude_items = unserialize($exclude_items); } if (!in_array($file, $exclude_items) && !in_array("*.$ext", $exclude_items)) { return true; } return false; } /** * get language translations from json file * @param int $tr * @return array */ function fm_get_translations($tr) { try { $content = @file_get_contents('translation.json'); if($content !== FALSE) { $lng = json_decode($content, TRUE); global $lang_list; foreach ($lng["language"] as $key => $value) { $code = $value["code"]; $lang_list[$code] = $value["name"]; if ($tr) $tr[$code] = $value["translation"]; } return $tr; } } catch (Exception $e) { echo $e; } } /** * @param string $file * Recover all file sizes larger than > 2GB. * Works on php 32bits and 64bits and supports linux * @return int|string */ function fm_get_size($file) { static $iswin; static $isdarwin; if (!isset($iswin)) { $iswin = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'); } if (!isset($isdarwin)) { $isdarwin = (strtoupper(substr(PHP_OS, 0)) == "DARWIN"); } static $exec_works; if (!isset($exec_works)) { $exec_works = (function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') == 'EXEC'); } // try a shell command if ($exec_works) { $arg = escapeshellarg($file); $cmd = ($iswin) ? "for %F in (\"$file\") do @echo %~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s $arg"); @exec($cmd, $output); if (is_array($output) && ctype_digit($size = trim(implode("\n", $output)))) { return $size; } } // try the Windows COM interface if ($iswin && class_exists("COM")) { try { $fsobj = new COM('Scripting.FileSystemObject'); $f = $fsobj->GetFile( realpath($file) ); $size = $f->Size; } catch (Exception $e) { $size = null; } if (ctype_digit($size)) { return $size; } } // if all else fails return filesize($file); } /** * Get nice filesize * @param int $size * @return string */ function fm_get_filesize($size) { $size = (float) $size; $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); $power = ($size > 0) ? floor(log($size, 1024)) : 0; $power = ($power > (count($units) - 1)) ? (count($units) - 1) : $power; return sprintf('%s %s', round($size / pow(1024, $power), 2), $units[$power]); } /** * Get total size of directory tree. * * @param string $directory Relative or absolute directory name. * @return int Total number of bytes. */ function fm_get_directorysize($directory) { $bytes = 0; $directory = realpath($directory); if ($directory !== false && $directory != '' && file_exists($directory)){ foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS)) as $file){ $bytes += $file->getSize(); } } return $bytes; } /** * Get info about zip archive * @param string $path * @return array|bool */ function fm_get_zif_info($path, $ext) { if ($ext == 'zip' && function_exists('zip_open')) { $arch = @zip_open($path); if ($arch) { $filenames = array(); while ($zip_entry = @zip_read($arch)) { $zip_name = @zip_entry_name($zip_entry); $zip_folder = substr($zip_name, -1) == '/'; $filenames[] = array( 'name' => $zip_name, 'filesize' => @zip_entry_filesize($zip_entry), 'compressed_size' => @zip_entry_compressedsize($zip_entry), 'folder' => $zip_folder //'compression_method' => zip_entry_compressionmethod($zip_entry), ); } @zip_close($arch); return $filenames; } } elseif($ext == 'tar' && class_exists('PharData')) { $archive = new PharData($path); $filenames = array(); foreach(new RecursiveIteratorIterator($archive) as $file) { $parent_info = $file->getPathInfo(); $zip_name = str_replace("phar://".$path, '', $file->getPathName()); $zip_name = substr($zip_name, ($pos = strpos($zip_name, '/')) !== false ? $pos + 1 : 0); $zip_folder = $parent_info->getFileName(); $zip_info = new SplFileInfo($file); $filenames[] = array( 'name' => $zip_name, 'filesize' => $zip_info->getSize(), 'compressed_size' => $file->getCompressedSize(), 'folder' => $zip_folder ); } return $filenames; } return false; } /** * Encode html entities * @param string $text * @return string */ function fm_enc($text) { return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); } /** * Prevent XSS attacks * @param string $text * @return string */ function fm_isvalid_filename($text) { return (strpbrk($text, '/?%*:|"<>') === FALSE) ? true : false; } /** * Save message in session * @param string $msg * @param string $status */ function fm_set_msg($msg, $status = 'ok') { $_SESSION[FM_SESSION_ID]['message'] = $msg; $_SESSION[FM_SESSION_ID]['status'] = $status; } /** * Check if string is in UTF-8 * @param string $string * @return int */ function fm_is_utf8($string) { return preg_match('//u', $string); } /** * Convert file name to UTF-8 in Windows * @param string $filename * @return string */ function fm_convert_win($filename) { if (FM_IS_WIN && function_exists('iconv')) { $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $filename); } return $filename; } /** * @param $obj * @return array */ function fm_object_to_array($obj) { if (!is_object($obj) && !is_array($obj)) { return $obj; } if (is_object($obj)) { $obj = get_object_vars($obj); } return array_map('fm_object_to_array', $obj); } /** * Get CSS classname for file * @param string $path * @return string */ function fm_get_file_icon_class($path) { // get extension $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); switch ($ext) { case 'ico': case 'gif': case 'jpg': case 'jpeg': case 'jpc': case 'jp2': case 'jpx': case 'xbm': case 'wbmp': case 'png': case 'bmp': case 'tif': case 'tiff': case 'webp': case 'avif': case 'svg': $img = 'fa fa-picture-o'; break; case 'passwd': case 'ftpquota': case 'sql': case 'js': case 'ts': case 'jsx': case 'tsx': case 'hbs': case 'json': case 'sh': case 'config': case 'twig': case 'tpl': case 'md': case 'gitignore': case 'c': case 'cpp': case 'cs': case 'py': case 'rs': case 'map': case 'lock': case 'dtd': $img = 'fa fa-file-code-o'; break; case 'txt': case 'ini': case 'conf': case 'log': case 'htaccess': case 'yaml': case 'yml': case 'toml': case 'tmp': case 'top': case 'bot': case 'dat': case 'bak': case 'htpasswd': case 'pl': $img = 'fa fa-file-text-o'; break; case 'css': case 'less': case 'sass': case 'scss': $img = 'fa fa-css3'; break; case 'bz2': case 'tbz2': case 'tbz': case 'zip': case 'rar': case 'gz': case 'tgz': case 'tar': case '7z': case 'xz': case 'txz': case 'zst': case 'tzst': $img = 'fa fa-file-archive-o'; break; case 'php': case 'php4': case 'php5': case 'phps': case 'phtml': $img = 'fa fa-code'; break; case 'htm': case 'html': case 'shtml': case 'xhtml': $img = 'fa fa-html5'; break; case 'xml': case 'xsl': $img = 'fa fa-file-excel-o'; break; case 'wav': case 'mp3': case 'mp2': case 'm4a': case 'aac': case 'ogg': case 'oga': case 'wma': case 'mka': case 'flac': case 'ac3': case 'tds': $img = 'fa fa-music'; break; case 'm3u': case 'm3u8': case 'pls': case 'cue': case 'xspf': $img = 'fa fa-headphones'; break; case 'avi': case 'mpg': case 'mpeg': case 'mp4': case 'm4v': case 'flv': case 'f4v': case 'ogm': case 'ogv': case 'mov': case 'mkv': case '3gp': case 'asf': case 'wmv': case 'webm': $img = 'fa fa-file-video-o'; break; case 'eml': case 'msg': $img = 'fa fa-envelope-o'; break; case 'xls': case 'xlsx': case 'ods': $img = 'fa fa-file-excel-o'; break; case 'csv': $img = 'fa fa-file-text-o'; break; case 'bak': case 'swp': $img = 'fa fa-clipboard'; break; case 'doc': case 'docx': case 'odt': $img = 'fa fa-file-word-o'; break; case 'ppt': case 'pptx': $img = 'fa fa-file-powerpoint-o'; break; case 'ttf': case 'ttc': case 'otf': case 'woff': case 'woff2': case 'eot': case 'fon': $img = 'fa fa-font'; break; case 'pdf': $img = 'fa fa-file-pdf-o'; break; case 'psd': case 'ai': case 'eps': case 'fla': case 'swf': $img = 'fa fa-file-image-o'; break; case 'exe': case 'msi': $img = 'fa fa-file-o'; break; case 'bat': $img = 'fa fa-terminal'; break; default: $img = 'fa fa-info-circle'; } return $img; } /** * Get image files extensions * @return array */ function fm_get_image_exts() { return array('ico', 'gif', 'jpg', 'jpeg', 'jpc', 'jp2', 'jpx', 'xbm', 'wbmp', 'png', 'bmp', 'tif', 'tiff', 'psd', 'svg', 'webp', 'avif'); } /** * Get video files extensions * @return array */ function fm_get_video_exts() { return array('avi', 'webm', 'wmv', 'mp4', 'm4v', 'ogm', 'ogv', 'mov', 'mkv'); } /** * Get audio files extensions * @return array */ function fm_get_audio_exts() { return array('wav', 'mp3', 'ogg', 'm4a'); } /** * Get text file extensions * @return array */ function fm_get_text_exts() { return array( 'txt', 'css', 'ini', 'conf', 'log', 'htaccess', 'passwd', 'ftpquota', 'sql', 'js', 'ts', 'jsx', 'tsx', 'mjs', 'json', 'sh', 'config', 'php', 'php4', 'php5', 'phps', 'phtml', 'htm', 'html', 'shtml', 'xhtml', 'xml', 'xsl', 'm3u', 'm3u8', 'pls', 'cue', 'bash', 'vue', 'eml', 'msg', 'csv', 'bat', 'twig', 'tpl', 'md', 'gitignore', 'less', 'sass', 'scss', 'c', 'cpp', 'cs', 'py', 'go', 'zsh', 'swift', 'map', 'lock', 'dtd', 'svg', 'asp', 'aspx', 'asx', 'asmx', 'ashx', 'jsp', 'jspx', 'cgi', 'dockerfile', 'ruby', 'yml', 'yaml', 'toml', 'vhost', 'scpt', 'applescript', 'csx', 'cshtml', 'c++', 'coffee', 'cfm', 'rb', 'graphql', 'mustache', 'jinja', 'http', 'handlebars', 'java', 'es', 'es6', 'markdown', 'wiki', 'tmp', 'top', 'bot', 'dat', 'bak', 'htpasswd', 'pl' ); } /** * Get mime types of text files * @return array */ function fm_get_text_mimes() { return array( 'application/xml', 'application/javascript', 'application/x-javascript', 'image/svg+xml', 'message/rfc822', 'application/json', ); } /** * Get file names of text files w/o extensions * @return array */ function fm_get_text_names() { return array( 'license', 'readme', 'authors', 'contributors', 'changelog', ); } /** * Get online docs viewer supported files extensions * @return array */ function fm_get_onlineViewer_exts() { return array('doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt', 'pptx', 'ai', 'psd', 'dxf', 'xps', 'rar', 'odt', 'ods'); } /** * It returns the mime type of a file based on its extension. * @param extension The file extension of the file you want to get the mime type for. * @return string|string[] The mime type of the file. */ function fm_get_file_mimes($extension) { $fileTypes['swf'] = 'application/x-shockwave-flash'; $fileTypes['pdf'] = 'application/pdf'; $fileTypes['exe'] = 'application/octet-stream'; $fileTypes['zip'] = 'application/zip'; $fileTypes['doc'] = 'application/msword'; $fileTypes['xls'] = 'application/vnd.ms-excel'; $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; $fileTypes['gif'] = 'image/gif'; $fileTypes['png'] = 'image/png'; $fileTypes['jpeg'] = 'image/jpg'; $fileTypes['jpg'] = 'image/jpg'; $fileTypes['webp'] = 'image/webp'; $fileTypes['avif'] = 'image/avif'; $fileTypes['rar'] = 'application/rar'; $fileTypes['ra'] = 'audio/x-pn-realaudio'; $fileTypes['ram'] = 'audio/x-pn-realaudio'; $fileTypes['ogg'] = 'audio/x-pn-realaudio'; $fileTypes['wav'] = 'video/x-msvideo'; $fileTypes['wmv'] = 'video/x-msvideo'; $fileTypes['avi'] = 'video/x-msvideo'; $fileTypes['asf'] = 'video/x-msvideo'; $fileTypes['divx'] = 'video/x-msvideo'; $fileTypes['mp3'] = 'audio/mpeg'; $fileTypes['mp4'] = 'audio/mpeg'; $fileTypes['mpeg'] = 'video/mpeg'; $fileTypes['mpg'] = 'video/mpeg'; $fileTypes['mpe'] = 'video/mpeg'; $fileTypes['mov'] = 'video/quicktime'; $fileTypes['swf'] = 'video/quicktime'; $fileTypes['3gp'] = 'video/quicktime'; $fileTypes['m4a'] = 'video/quicktime'; $fileTypes['aac'] = 'video/quicktime'; $fileTypes['m3u'] = 'video/quicktime'; $fileTypes['php'] = ['application/x-php']; $fileTypes['html'] = ['text/html']; $fileTypes['txt'] = ['text/plain']; //Unknown mime-types should be 'application/octet-stream' if(empty($fileTypes[$extension])) { $fileTypes[$extension] = ['application/octet-stream']; } return $fileTypes[$extension]; } /** * This function scans the files and folder recursively, and return matching files * @param string $dir * @param string $filter * @return array|null */ function scan($dir = '', $filter = '') { $path = FM_ROOT_PATH.'/'.$dir; if($path) { $ite = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); $rii = new RegexIterator($ite, "/(" . $filter . ")/i"); $files = array(); foreach ($rii as $file) { if (!$file->isDir()) { $fileName = $file->getFilename(); $location = str_replace(FM_ROOT_PATH, '', $file->getPath()); $files[] = array( "name" => $fileName, "type" => "file", "path" => $location, ); } } return $files; } } /** * Parameters: downloadFile(File Location, File Name, * max speed, is streaming * If streaming - videos will show as videos, images as images * instead of download prompt * https://stackoverflow.com/a/13821992/1164642 */ function fm_download_file($fileLocation, $fileName, $chunkSize = 1024) { if (connection_status() != 0) return (false); $extension = pathinfo($fileName, PATHINFO_EXTENSION); $contentType = fm_get_file_mimes($extension); if(is_array($contentType)) { $contentType = implode(' ', $contentType); } $size = filesize($fileLocation); if ($size == 0) { fm_set_msg(lng('Zero byte file! Aborting download'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); return (false); } @ini_set('magic_quotes_runtime', 0); $fp = fopen("$fileLocation", "rb"); if ($fp === false) { fm_set_msg(lng('Cannot open file! Aborting download'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); return (false); } // headers header('Content-Description: File Transfer'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header("Content-Transfer-Encoding: binary"); header("Content-Type: $contentType"); $contentDisposition = 'attachment'; if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } else { header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } header("Accept-Ranges: bytes"); $range = 0; if (isset($_SERVER['HTTP_RANGE'])) { list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); str_replace($range, "-", $range); $size2 = $size - 1; $new_length = $size - $range; header("HTTP/1.1 206 Partial Content"); header("Content-Length: $new_length"); header("Content-Range: bytes $range$size2/$size"); } else { $size2 = $size - 1; header("Content-Range: bytes 0-$size2/$size"); header("Content-Length: " . $size); } $fileLocation = realpath($fileLocation); while (ob_get_level()) ob_end_clean(); readfile($fileLocation); fclose($fp); return ((connection_status() == 0) and !connection_aborted()); } /** * If the theme is dark, return the text-white and bg-dark classes. * @return string the value of the variable. */ function fm_get_theme() { $result = ''; if(FM_THEME == "dark") { $result = "text-white bg-dark"; } return $result; } /** * Class to work with zip files (using ZipArchive) */ class FM_Zipper { private $zip; public function __construct() { $this->zip = new ZipArchive(); } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $res = $this->zip->open($filename, ZipArchive::CREATE); if ($res !== true) { return false; } if (is_array($files)) { foreach ($files as $f) { $f = fm_clean_path($f); if (!$this->addFileOrDir($f)) { $this->zip->close(); return false; } } $this->zip->close(); return true; } else { if ($this->addFileOrDir($files)) { $this->zip->close(); return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->zip->open($filename); if ($res !== true) { return false; } if ($this->zip->extractTo($path)) { $this->zip->close(); return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { return $this->zip->addFile($filename); } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { if (!$this->zip->addEmptyDir($path)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . '/' . $file)) { if (!$this->addDir($path . '/' . $file)) { return false; } } elseif (is_file($path . '/' . $file)) { if (!$this->zip->addFile($path . '/' . $file)) { return false; } } } } return true; } return false; } } /** * Class to work with Tar files (using PharData) */ class FM_Zipper_Tar { private $tar; public function __construct() { $this->tar = null; } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $this->tar = new PharData($filename); if (is_array($files)) { foreach ($files as $f) { $f = fm_clean_path($f); if (!$this->addFileOrDir($f)) { return false; } } return true; } else { if ($this->addFileOrDir($files)) { return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->tar->open($filename); if ($res !== true) { return false; } if ($this->tar->extractTo($path)) { return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { try { $this->tar->addFile($filename); return true; } catch (Exception $e) { return false; } } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . '/' . $file)) { if (!$this->addDir($path . '/' . $file)) { return false; } } elseif (is_file($path . '/' . $file)) { try { $this->tar->addFile($path . '/' . $file); } catch (Exception $e) { return false; } } } } return true; } return false; } } /** * Save Configuration */ class FM_Config { var $data; function __construct() { global $root_path, $root_url, $CONFIG; $fm_url = $root_url.$_SERVER["PHP_SELF"]; $this->data = array( 'lang' => 'en', 'error_reporting' => true, 'show_hidden' => true ); $data = false; if (strlen($CONFIG)) { $data = fm_object_to_array(json_decode($CONFIG)); } else { $msg = 'Tiny File Manager
Error: Cannot load configuration'; if (substr($fm_url, -1) == '/') { $fm_url = rtrim($fm_url, '/'); $msg .= '
'; $msg .= '
Seems like you have a trailing slash on the URL.'; $msg .= '
Try this link: ' . $fm_url . ''; } die($msg); } if (is_array($data) && count($data)) $this->data = $data; else $this->save(); } function save() { $fm_file = __FILE__; $var_name = '$CONFIG'; $var_value = var_export(json_encode($this->data), true); $config_string = " ' . $_SESSION[FM_SESSION_ID]['message'] . '

'; unset($_SESSION[FM_SESSION_ID]['message']); unset($_SESSION[FM_SESSION_ID]['status']); } } /** * Show page header in Login Form */ function fm_show_header_login() { $sprites_ver = '20160315'; header("Content-Type: text/html; charset=utf-8"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); global $lang, $root_url, $favicon_path; ?> '; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
'; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
Utility/InputValidator.php000064400000004720150211523530011665 0ustar00headers = new Headers(); $this->cookies = new Jar(); } /** * Is the response a redirect? * * @return boolean True if redirect (3xx status), false if not. */ public function is_redirect() { $code = $this->status_code; return in_array($code, [300, 301, 302, 303, 307], true) || $code > 307 && $code < 400; } /** * Throws an exception if the request was not successful * * @param boolean $allow_redirects Set to false to throw on a 3xx as well * * @throws \WpOrg\Requests\Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`) * @throws \WpOrg\Requests\Exception\Http On non-successful status code. Exception class corresponds to "Status" + code (e.g. {@see \WpOrg\Requests\Exception\Http\Status404}) */ public function throw_for_status($allow_redirects = true) { if ($this->is_redirect()) { if ($allow_redirects !== true) { throw new Exception('Redirection not allowed', 'response.no_redirects', $this); } } elseif (!$this->success) { $exception = Http::get_class($this->status_code); throw new $exception(null, $this); } } /** * JSON decode the response body. * * The method parameters are the same as those for the PHP native `json_decode()` function. * * @link https://php.net/json-decode * * @param bool|null $associative Optional. When `true`, JSON objects will be returned as associative arrays; * When `false`, JSON objects will be returned as objects. * When `null`, JSON objects will be returned as associative arrays * or objects depending on whether `JSON_OBJECT_AS_ARRAY` is set in the flags. * Defaults to `true` (in contrast to the PHP native default of `null`). * @param int $depth Optional. Maximum nesting depth of the structure being decoded. * Defaults to `512`. * @param int $options Optional. Bitmask of JSON_BIGINT_AS_STRING, JSON_INVALID_UTF8_IGNORE, * JSON_INVALID_UTF8_SUBSTITUTE, JSON_OBJECT_AS_ARRAY, JSON_THROW_ON_ERROR. * Defaults to `0` (no options set). * * @return array * * @throws \WpOrg\Requests\Exception If `$this->body` is not valid json. */ public function decode_body($associative = true, $depth = 512, $options = 0) { $data = json_decode($this->body, $associative, $depth, $options); if (json_last_error() !== JSON_ERROR_NONE) { $last_error = json_last_error_msg(); throw new Exception('Unable to parse JSON data: ' . $last_error, 'response.invalid', $this); } return $data; } } Transport.php000064400000003010150211523530007240 0ustar00 $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. * @return bool Whether the transport can be used. */ public static function test($capabilities = []); } Auth/Basic.php000064400000004755150211523530007207 0ustar00user, $this->pass) = $args; return; } if ($args !== null) { throw InvalidArgument::create(1, '$args', 'array|null', gettype($args)); } } /** * Register the necessary callbacks * * @see \WpOrg\Requests\Auth\Basic::curl_before_send() * @see \WpOrg\Requests\Auth\Basic::fsockopen_header() * @param \WpOrg\Requests\Hooks $hooks Hook system */ public function register(Hooks $hooks) { $hooks->register('curl.before_send', [$this, 'curl_before_send']); $hooks->register('fsockopen.after_headers', [$this, 'fsockopen_header']); } /** * Set cURL parameters before the data is sent * * @param resource|\CurlHandle $handle cURL handle */ public function curl_before_send(&$handle) { curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString()); } /** * Add extra headers to the request before sending * * @param string $out HTTP header string */ public function fsockopen_header(&$out) { $out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString())); } /** * Get the authentication string (user:pass) * * @return string */ public function getAuthString() { return $this->user . ':' . $this->pass; } } Requests.php000064400000102321150211523530007064 0ustar00 10, 'connect_timeout' => 10, 'useragent' => 'php-requests/' . self::VERSION, 'protocol_version' => 1.1, 'redirected' => 0, 'redirects' => 10, 'follow_redirects' => true, 'blocking' => true, 'type' => self::GET, 'filename' => false, 'auth' => false, 'proxy' => false, 'cookies' => false, 'max_bytes' => false, 'idn' => true, 'hooks' => null, 'transport' => null, 'verify' => null, 'verifyname' => true, ]; /** * Default supported Transport classes. * * @since 2.0.0 * * @var array */ const DEFAULT_TRANSPORTS = [ Curl::class => Curl::class, Fsockopen::class => Fsockopen::class, ]; /** * Current version of Requests * * @var string */ const VERSION = '2.0.11'; /** * Selected transport name * * Use {@see \WpOrg\Requests\Requests::get_transport()} instead * * @var array */ public static $transport = []; /** * Registered transport classes * * @var array */ protected static $transports = []; /** * Default certificate path. * * @see \WpOrg\Requests\Requests::get_certificate_path() * @see \WpOrg\Requests\Requests::set_certificate_path() * * @var string */ protected static $certificate_path = __DIR__ . '/../certificates/cacert.pem'; /** * All (known) valid deflate, gzip header magic markers. * * These markers relate to different compression levels. * * @link https://stackoverflow.com/a/43170354/482864 Marker source. * * @since 2.0.0 * * @var array */ private static $magic_compression_headers = [ "\x1f\x8b" => true, // Gzip marker. "\x78\x01" => true, // Zlib marker - level 1. "\x78\x5e" => true, // Zlib marker - level 2 to 5. "\x78\x9c" => true, // Zlib marker - level 6. "\x78\xda" => true, // Zlib marker - level 7 to 9. ]; /** * This is a static class, do not instantiate it * * @codeCoverageIgnore */ private function __construct() {} /** * Register a transport * * @param string $transport Transport class to add, must support the \WpOrg\Requests\Transport interface */ public static function add_transport($transport) { if (empty(self::$transports)) { self::$transports = self::DEFAULT_TRANSPORTS; } self::$transports[$transport] = $transport; } /** * Get the fully qualified class name (FQCN) for a working transport. * * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. * @return string FQCN of the transport to use, or an empty string if no transport was * found which provided the requested capabilities. */ protected static function get_transport_class(array $capabilities = []) { // Caching code, don't bother testing coverage. // @codeCoverageIgnoreStart // Array of capabilities as a string to be used as an array key. ksort($capabilities); $cap_string = serialize($capabilities); // Don't search for a transport if it's already been done for these $capabilities. if (isset(self::$transport[$cap_string])) { return self::$transport[$cap_string]; } // Ensure we will not run this same check again later on. self::$transport[$cap_string] = ''; // @codeCoverageIgnoreEnd if (empty(self::$transports)) { self::$transports = self::DEFAULT_TRANSPORTS; } // Find us a working transport. foreach (self::$transports as $class) { if (!class_exists($class)) { continue; } $result = $class::test($capabilities); if ($result === true) { self::$transport[$cap_string] = $class; break; } } return self::$transport[$cap_string]; } /** * Get a working transport. * * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. * @return \WpOrg\Requests\Transport * @throws \WpOrg\Requests\Exception If no valid transport is found (`notransport`). */ protected static function get_transport(array $capabilities = []) { $class = self::get_transport_class($capabilities); if ($class === '') { throw new Exception('No working transports found', 'notransport', self::$transports); } return new $class(); } /** * Checks to see if we have a transport for the capabilities requested. * * Supported capabilities can be found in the {@see \WpOrg\Requests\Capability} * interface as constants. * * Example usage: * `Requests::has_capabilities([Capability::SSL => true])`. * * @param array $capabilities Optional. Associative array of capabilities to test against, i.e. `['' => true]`. * @return bool Whether the transport has the requested capabilities. */ public static function has_capabilities(array $capabilities = []) { return self::get_transport_class($capabilities) !== ''; } /**#@+ * @see \WpOrg\Requests\Requests::request() * @param string $url * @param array $headers * @param array $options * @return \WpOrg\Requests\Response */ /** * Send a GET request */ public static function get($url, $headers = [], $options = []) { return self::request($url, $headers, null, self::GET, $options); } /** * Send a HEAD request */ public static function head($url, $headers = [], $options = []) { return self::request($url, $headers, null, self::HEAD, $options); } /** * Send a DELETE request */ public static function delete($url, $headers = [], $options = []) { return self::request($url, $headers, null, self::DELETE, $options); } /** * Send a TRACE request */ public static function trace($url, $headers = [], $options = []) { return self::request($url, $headers, null, self::TRACE, $options); } /**#@-*/ /**#@+ * @see \WpOrg\Requests\Requests::request() * @param string $url * @param array $headers * @param array $data * @param array $options * @return \WpOrg\Requests\Response */ /** * Send a POST request */ public static function post($url, $headers = [], $data = [], $options = []) { return self::request($url, $headers, $data, self::POST, $options); } /** * Send a PUT request */ public static function put($url, $headers = [], $data = [], $options = []) { return self::request($url, $headers, $data, self::PUT, $options); } /** * Send an OPTIONS request */ public static function options($url, $headers = [], $data = [], $options = []) { return self::request($url, $headers, $data, self::OPTIONS, $options); } /** * Send a PATCH request * * Note: Unlike {@see \WpOrg\Requests\Requests::post()} and {@see \WpOrg\Requests\Requests::put()}, * `$headers` is required, as the specification recommends that should send an ETag * * @link https://tools.ietf.org/html/rfc5789 */ public static function patch($url, $headers, $data = [], $options = []) { return self::request($url, $headers, $data, self::PATCH, $options); } /**#@-*/ /** * Main interface for HTTP requests * * This method initiates a request and sends it via a transport before * parsing. * * The `$options` parameter takes an associative array with the following * options: * * - `timeout`: How long should we wait for a response? * Note: for cURL, a minimum of 1 second applies, as DNS resolution * operates at second-resolution only. * (float, seconds with a millisecond precision, default: 10, example: 0.01) * - `connect_timeout`: How long should we wait while trying to connect? * (float, seconds with a millisecond precision, default: 10, example: 0.01) * - `useragent`: Useragent to send to the server * (string, default: php-requests/$version) * - `follow_redirects`: Should we follow 3xx redirects? * (boolean, default: true) * - `redirects`: How many times should we redirect before erroring? * (integer, default: 10) * - `blocking`: Should we block processing on this request? * (boolean, default: true) * - `filename`: File to stream the body to instead. * (string|boolean, default: false) * - `auth`: Authentication handler or array of user/password details to use * for Basic authentication * (\WpOrg\Requests\Auth|array|boolean, default: false) * - `proxy`: Proxy details to use for proxy by-passing and authentication * (\WpOrg\Requests\Proxy|array|string|boolean, default: false) * - `max_bytes`: Limit for the response body size. * (integer|boolean, default: false) * - `idn`: Enable IDN parsing * (boolean, default: true) * - `transport`: Custom transport. Either a class name, or a * transport object. Defaults to the first working transport from * {@see \WpOrg\Requests\Requests::getTransport()} * (string|\WpOrg\Requests\Transport, default: {@see \WpOrg\Requests\Requests::getTransport()}) * - `hooks`: Hooks handler. * (\WpOrg\Requests\HookManager, default: new WpOrg\Requests\Hooks()) * - `verify`: Should we verify SSL certificates? Allows passing in a custom * certificate file as a string. (Using true uses the system-wide root * certificate store instead, but this may have different behaviour * across transports.) * (string|boolean, default: certificates/cacert.pem) * - `verifyname`: Should we verify the common name in the SSL certificate? * (boolean, default: true) * - `data_format`: How should we send the `$data` parameter? * (string, one of 'query' or 'body', default: 'query' for * HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH) * * @param string|Stringable $url URL to request * @param array $headers Extra headers to send with the request * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests * @param string $type HTTP request type (use Requests constants) * @param array $options Options for the request (see description for more information) * @return \WpOrg\Requests\Response * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $type argument is not a string. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`) */ public static function request($url, $headers = [], $data = [], $type = self::GET, $options = []) { if (InputValidator::is_string_or_stringable($url) === false) { throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url)); } if (is_string($type) === false) { throw InvalidArgument::create(4, '$type', 'string', gettype($type)); } if (is_array($options) === false) { throw InvalidArgument::create(5, '$options', 'array', gettype($options)); } if (empty($options['type'])) { $options['type'] = $type; } $options = array_merge(self::get_default_options(), $options); self::set_defaults($url, $headers, $data, $type, $options); $options['hooks']->dispatch('requests.before_request', [&$url, &$headers, &$data, &$type, &$options]); if (!empty($options['transport'])) { $transport = $options['transport']; if (is_string($options['transport'])) { $transport = new $transport(); } } else { $need_ssl = (stripos($url, 'https://') === 0); $capabilities = [Capability::SSL => $need_ssl]; $transport = self::get_transport($capabilities); } $response = $transport->request($url, $headers, $data, $options); $options['hooks']->dispatch('requests.before_parse', [&$response, $url, $headers, $data, $type, $options]); return self::parse_response($response, $url, $headers, $data, $options); } /** * Send multiple HTTP requests simultaneously * * The `$requests` parameter takes an associative or indexed array of * request fields. The key of each request can be used to match up the * request with the returned data, or with the request passed into your * `multiple.request.complete` callback. * * The request fields value is an associative array with the following keys: * * - `url`: Request URL Same as the `$url` parameter to * {@see \WpOrg\Requests\Requests::request()} * (string, required) * - `headers`: Associative array of header fields. Same as the `$headers` * parameter to {@see \WpOrg\Requests\Requests::request()} * (array, default: `array()`) * - `data`: Associative array of data fields or a string. Same as the * `$data` parameter to {@see \WpOrg\Requests\Requests::request()} * (array|string, default: `array()`) * - `type`: HTTP request type (use \WpOrg\Requests\Requests constants). Same as the `$type` * parameter to {@see \WpOrg\Requests\Requests::request()} * (string, default: `\WpOrg\Requests\Requests::GET`) * - `cookies`: Associative array of cookie name to value, or cookie jar. * (array|\WpOrg\Requests\Cookie\Jar) * * If the `$options` parameter is specified, individual requests will * inherit options from it. This can be used to use a single hooking system, * or set all the types to `\WpOrg\Requests\Requests::POST`, for example. * * In addition, the `$options` parameter takes the following global options: * * - `complete`: A callback for when a request is complete. Takes two * parameters, a \WpOrg\Requests\Response/\WpOrg\Requests\Exception reference, and the * ID from the request array (Note: this can also be overridden on a * per-request basis, although that's a little silly) * (callback) * * @param array $requests Requests data (see description for more information) * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()}) * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object) * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ public static function request_multiple($requests, $options = []) { if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); } if (is_array($options) === false) { throw InvalidArgument::create(2, '$options', 'array', gettype($options)); } $options = array_merge(self::get_default_options(true), $options); if (!empty($options['hooks'])) { $options['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']); if (!empty($options['complete'])) { $options['hooks']->register('multiple.request.complete', $options['complete']); } } foreach ($requests as $id => &$request) { if (!isset($request['headers'])) { $request['headers'] = []; } if (!isset($request['data'])) { $request['data'] = []; } if (!isset($request['type'])) { $request['type'] = self::GET; } if (!isset($request['options'])) { $request['options'] = $options; $request['options']['type'] = $request['type']; } else { if (empty($request['options']['type'])) { $request['options']['type'] = $request['type']; } $request['options'] = array_merge($options, $request['options']); } self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']); // Ensure we only hook in once if ($request['options']['hooks'] !== $options['hooks']) { $request['options']['hooks']->register('transport.internal.parse_response', [static::class, 'parse_multiple']); if (!empty($request['options']['complete'])) { $request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']); } } } unset($request); if (!empty($options['transport'])) { $transport = $options['transport']; if (is_string($options['transport'])) { $transport = new $transport(); } } else { $transport = self::get_transport(); } $responses = $transport->request_multiple($requests, $options); foreach ($responses as $id => &$response) { // If our hook got messed with somehow, ensure we end up with the // correct response if (is_string($response)) { $request = $requests[$id]; self::parse_multiple($response, $request); $request['options']['hooks']->dispatch('multiple.request.complete', [&$response, $id]); } } return $responses; } /** * Get the default options * * @see \WpOrg\Requests\Requests::request() for values returned by this method * @param boolean $multirequest Is this a multirequest? * @return array Default option values */ protected static function get_default_options($multirequest = false) { $defaults = static::OPTION_DEFAULTS; $defaults['verify'] = self::$certificate_path; if ($multirequest !== false) { $defaults['complete'] = null; } return $defaults; } /** * Get default certificate path. * * @return string Default certificate path. */ public static function get_certificate_path() { return self::$certificate_path; } /** * Set default certificate path. * * @param string|Stringable|bool $path Certificate path, pointing to a PEM file. * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or boolean. */ public static function set_certificate_path($path) { if (InputValidator::is_string_or_stringable($path) === false && is_bool($path) === false) { throw InvalidArgument::create(1, '$path', 'string|Stringable|bool', gettype($path)); } self::$certificate_path = $path; } /** * Set the default values * * The $options parameter is updated with the results. * * @param string $url URL to request * @param array $headers Extra headers to send with the request * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests * @param string $type HTTP request type * @param array $options Options for the request * @return void * * @throws \WpOrg\Requests\Exception When the $url is not an http(s) URL. */ protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) { if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) { throw new Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url); } if (empty($options['hooks'])) { $options['hooks'] = new Hooks(); } if (is_array($options['auth'])) { $options['auth'] = new Basic($options['auth']); } if ($options['auth'] !== false) { $options['auth']->register($options['hooks']); } if (is_string($options['proxy']) || is_array($options['proxy'])) { $options['proxy'] = new Http($options['proxy']); } if ($options['proxy'] !== false) { $options['proxy']->register($options['hooks']); } if (is_array($options['cookies'])) { $options['cookies'] = new Jar($options['cookies']); } elseif (empty($options['cookies'])) { $options['cookies'] = new Jar(); } if ($options['cookies'] !== false) { $options['cookies']->register($options['hooks']); } if ($options['idn'] !== false) { $iri = new Iri($url); $iri->host = IdnaEncoder::encode($iri->ihost); $url = $iri->uri; } // Massage the type to ensure we support it. $type = strtoupper($type); if (!isset($options['data_format'])) { if (in_array($type, [self::HEAD, self::GET, self::DELETE], true)) { $options['data_format'] = 'query'; } else { $options['data_format'] = 'body'; } } } /** * HTTP response parser * * @param string $headers Full response text including headers and body * @param string $url Original request URL * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects * @return \WpOrg\Requests\Response * * @throws \WpOrg\Requests\Exception On missing head/body separator (`requests.no_crlf_separator`) * @throws \WpOrg\Requests\Exception On missing head/body separator (`noversion`) * @throws \WpOrg\Requests\Exception On missing head/body separator (`toomanyredirects`) */ protected static function parse_response($headers, $url, $req_headers, $req_data, $options) { $return = new Response(); if (!$options['blocking']) { return $return; } $return->raw = $headers; $return->url = (string) $url; $return->body = ''; if (!$options['filename']) { $pos = strpos($headers, "\r\n\r\n"); if ($pos === false) { // Crap! throw new Exception('Missing header/body separator', 'requests.no_crlf_separator'); } $headers = substr($return->raw, 0, $pos); // Headers will always be separated from the body by two new lines - `\n\r\n\r`. $body = substr($return->raw, $pos + 4); if (!empty($body)) { $return->body = $body; } } // Pretend CRLF = LF for compatibility (RFC 2616, section 19.3) $headers = str_replace("\r\n", "\n", $headers); // Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2) $headers = preg_replace('/\n[ \t]/', ' ', $headers); $headers = explode("\n", $headers); preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches); if (empty($matches)) { throw new Exception('Response could not be parsed', 'noversion', $headers); } $return->protocol_version = (float) $matches[1]; $return->status_code = (int) $matches[2]; if ($return->status_code >= 200 && $return->status_code < 300) { $return->success = true; } foreach ($headers as $header) { list($key, $value) = explode(':', $header, 2); $value = trim($value); preg_replace('#(\s+)#i', ' ', $value); $return->headers[$key] = $value; } if (isset($return->headers['transfer-encoding'])) { $return->body = self::decode_chunked($return->body); unset($return->headers['transfer-encoding']); } if (isset($return->headers['content-encoding'])) { $return->body = self::decompress($return->body); } //fsockopen and cURL compatibility if (isset($return->headers['connection'])) { unset($return->headers['connection']); } $options['hooks']->dispatch('requests.before_redirect_check', [&$return, $req_headers, $req_data, $options]); if ($return->is_redirect() && $options['follow_redirects'] === true) { if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) { if ($return->status_code === 303) { $options['type'] = self::GET; } $options['redirected']++; $location = $return->headers['location']; if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) { // relative redirect, for compatibility make it absolute $location = Iri::absolutize($url, $location); $location = $location->uri; } $hook_args = [ &$location, &$req_headers, &$req_data, &$options, $return, ]; $options['hooks']->dispatch('requests.before_redirect', $hook_args); $redirected = self::request($location, $req_headers, $req_data, $options['type'], $options); $redirected->history[] = $return; return $redirected; } elseif ($options['redirected'] >= $options['redirects']) { throw new Exception('Too many redirects', 'toomanyredirects', $return); } } $return->redirects = $options['redirected']; $options['hooks']->dispatch('requests.after_request', [&$return, $req_headers, $req_data, $options]); return $return; } /** * Callback for `transport.internal.parse_response` * * Internal use only. Converts a raw HTTP response to a \WpOrg\Requests\Response * while still executing a multiple request. * * `$response` is either set to a \WpOrg\Requests\Response instance, or a \WpOrg\Requests\Exception object * * @param string $response Full response text including headers and body (will be overwritten with Response instance) * @param array $request Request data as passed into {@see \WpOrg\Requests\Requests::request_multiple()} * @return void */ public static function parse_multiple(&$response, $request) { try { $url = $request['url']; $headers = $request['headers']; $data = $request['data']; $options = $request['options']; $response = self::parse_response($response, $url, $headers, $data, $options); } catch (Exception $e) { $response = $e; } } /** * Decoded a chunked body as per RFC 2616 * * @link https://tools.ietf.org/html/rfc2616#section-3.6.1 * @param string $data Chunked body * @return string Decoded body */ protected static function decode_chunked($data) { if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) { return $data; } $decoded = ''; $encoded = $data; while (true) { $is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches); if (!$is_chunked) { // Looks like it's not chunked after all return $data; } $length = hexdec(trim($matches[1])); if ($length === 0) { // Ignore trailer headers return $decoded; } $chunk_length = strlen($matches[0]); $decoded .= substr($encoded, $chunk_length, $length); $encoded = substr($encoded, $chunk_length + $length + 2); if (trim($encoded) === '0' || empty($encoded)) { return $decoded; } } // We'll never actually get down here // @codeCoverageIgnoreStart } // @codeCoverageIgnoreEnd /** * Convert a key => value array to a 'key: value' array for headers * * @param iterable $dictionary Dictionary of header values * @return array List of headers * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not iterable. */ public static function flatten($dictionary) { if (InputValidator::is_iterable($dictionary) === false) { throw InvalidArgument::create(1, '$dictionary', 'iterable', gettype($dictionary)); } $return = []; foreach ($dictionary as $key => $value) { $return[] = sprintf('%s: %s', $key, $value); } return $return; } /** * Decompress an encoded body * * Implements gzip, compress and deflate. Guesses which it is by attempting * to decode. * * @param string $data Compressed data in one of the above formats * @return string Decompressed string * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string. */ public static function decompress($data) { if (is_string($data) === false) { throw InvalidArgument::create(1, '$data', 'string', gettype($data)); } if (trim($data) === '') { // Empty body does not need further processing. return $data; } $marker = substr($data, 0, 2); if (!isset(self::$magic_compression_headers[$marker])) { // Not actually compressed. Probably cURL ruining this for us. return $data; } if (function_exists('gzdecode')) { $decoded = @gzdecode($data); if ($decoded !== false) { return $decoded; } } if (function_exists('gzinflate')) { $decoded = @gzinflate($data); if ($decoded !== false) { return $decoded; } } $decoded = self::compatible_gzinflate($data); if ($decoded !== false) { return $decoded; } if (function_exists('gzuncompress')) { $decoded = @gzuncompress($data); if ($decoded !== false) { return $decoded; } } return $data; } /** * Decompression of deflated string while staying compatible with the majority of servers. * * Certain Servers will return deflated data with headers which PHP's gzinflate() * function cannot handle out of the box. The following function has been created from * various snippets on the gzinflate() PHP documentation. * * Warning: Magic numbers within. Due to the potential different formats that the compressed * data may be returned in, some "magic offsets" are needed to ensure proper decompression * takes place. For a simple progmatic way to determine the magic offset in use, see: * https://core.trac.wordpress.org/ticket/18273 * * @since 1.6.0 * @link https://core.trac.wordpress.org/ticket/18273 * @link https://www.php.net/gzinflate#70875 * @link https://www.php.net/gzinflate#77336 * * @param string $gz_data String to decompress. * @return string|bool False on failure. * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string. */ public static function compatible_gzinflate($gz_data) { if (is_string($gz_data) === false) { throw InvalidArgument::create(1, '$gz_data', 'string', gettype($gz_data)); } if (trim($gz_data) === '') { return false; } // Compressed data might contain a full zlib header, if so strip it for // gzinflate() if (substr($gz_data, 0, 3) === "\x1f\x8b\x08") { $i = 10; $flg = ord(substr($gz_data, 3, 1)); if ($flg > 0) { if ($flg & 4) { list($xlen) = unpack('v', substr($gz_data, $i, 2)); $i += 2 + $xlen; } if ($flg & 8) { $i = strpos($gz_data, "\0", $i) + 1; } if ($flg & 16) { $i = strpos($gz_data, "\0", $i) + 1; } if ($flg & 2) { $i += 2; } } $decompressed = self::compatible_gzinflate(substr($gz_data, $i)); if ($decompressed !== false) { return $decompressed; } } // If the data is Huffman Encoded, we must first strip the leading 2 // byte Huffman marker for gzinflate() // The response is Huffman coded by many compressors such as // java.util.zip.Deflater, Ruby's Zlib::Deflate, and .NET's // System.IO.Compression.DeflateStream. // // See https://decompres.blogspot.com/ for a quick explanation of this // data type $huffman_encoded = false; // low nibble of first byte should be 0x08 list(, $first_nibble) = unpack('h', $gz_data); // First 2 bytes should be divisible by 0x1F list(, $first_two_bytes) = unpack('n', $gz_data); if ($first_nibble === 0x08 && ($first_two_bytes % 0x1F) === 0) { $huffman_encoded = true; } if ($huffman_encoded) { $decompressed = @gzinflate(substr($gz_data, 2)); if ($decompressed !== false) { return $decompressed; } } if (substr($gz_data, 0, 4) === "\x50\x4b\x03\x04") { // ZIP file format header // Offset 6: 2 bytes, General-purpose field // Offset 26: 2 bytes, filename length // Offset 28: 2 bytes, optional field length // Offset 30: Filename field, followed by optional field, followed // immediately by data list(, $general_purpose_flag) = unpack('v', substr($gz_data, 6, 2)); // If the file has been compressed on the fly, 0x08 bit is set of // the general purpose field. We can use this to differentiate // between a compressed document, and a ZIP file $zip_compressed_on_the_fly = ((0x08 & $general_purpose_flag) === 0x08); if (!$zip_compressed_on_the_fly) { // Don't attempt to decode a compressed zip file return $gz_data; } // Determine the first byte of data, based on the above ZIP header // offsets: $first_file_start = array_sum(unpack('v2', substr($gz_data, 26, 4))); $decompressed = @gzinflate(substr($gz_data, 30 + $first_file_start)); if ($decompressed !== false) { return $decompressed; } return false; } // Finally fall back to straight gzinflate $decompressed = @gzinflate($gz_data); if ($decompressed !== false) { return $decompressed; } // Fallback for all above failing, not expected, but included for // debugging and preventing regressions and to track stats $decompressed = @gzinflate(substr($gz_data, 2)); if ($decompressed !== false) { return $decompressed; } return false; } } Cookie/Jar.php000064400000010413150211523530007176 0ustar00cookies = $cookies; } /** * Normalise cookie data into a \WpOrg\Requests\Cookie * * @param string|\WpOrg\Requests\Cookie $cookie Cookie header value, possibly pre-parsed (object). * @param string $key Optional. The name for this cookie. * @return \WpOrg\Requests\Cookie */ public function normalize_cookie($cookie, $key = '') { if ($cookie instanceof Cookie) { return $cookie; } return Cookie::parse($cookie, $key); } /** * Check if the given item exists * * @param string $offset Item key * @return boolean Does the item exist? */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->cookies[$offset]); } /** * Get the value for the item * * @param string $offset Item key * @return string|null Item value (null if offsetExists is false) */ #[ReturnTypeWillChange] public function offsetGet($offset) { if (!isset($this->cookies[$offset])) { return null; } return $this->cookies[$offset]; } /** * Set the given item * * @param string $offset Item name * @param string $value Item value * * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`) */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if ($offset === null) { throw new Exception('Object is a dictionary, not a list', 'invalidset'); } $this->cookies[$offset] = $value; } /** * Unset the given header * * @param string $offset The key for the item to unset. */ #[ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->cookies[$offset]); } /** * Get an iterator for the data * * @return \ArrayIterator */ #[ReturnTypeWillChange] public function getIterator() { return new ArrayIterator($this->cookies); } /** * Register the cookie handler with the request's hooking system * * @param \WpOrg\Requests\HookManager $hooks Hooking system */ public function register(HookManager $hooks) { $hooks->register('requests.before_request', [$this, 'before_request']); $hooks->register('requests.before_redirect_check', [$this, 'before_redirect_check']); } /** * Add Cookie header to a request if we have any * * As per RFC 6265, cookies are separated by '; ' * * @param string $url * @param array $headers * @param array $data * @param string $type * @param array $options */ public function before_request($url, &$headers, &$data, &$type, &$options) { if (!$url instanceof Iri) { $url = new Iri($url); } if (!empty($this->cookies)) { $cookies = []; foreach ($this->cookies as $key => $cookie) { $cookie = $this->normalize_cookie($cookie, $key); // Skip expired cookies if ($cookie->is_expired()) { continue; } if ($cookie->domain_matches($url->host)) { $cookies[] = $cookie->format_for_header(); } } $headers['Cookie'] = implode('; ', $cookies); } } /** * Parse all cookies from a response and attach them to the response * * @param \WpOrg\Requests\Response $response Response as received. */ public function before_redirect_check(Response $response) { $url = $response->url; if (!$url instanceof Iri) { $url = new Iri($url); } $cookies = Cookie::parse_from_headers($response->headers, $url); $this->cookies = array_merge($this->cookies, $cookies); $response->cookies = $this; } } Session.php000064400000021623150211523530006701 0ustar00useragent = 'X';` * * @var array */ public $options = []; /** * Create a new session * * @param string|Stringable|null $url Base URL for requests * @param array $headers Default headers for requests * @param array $data Default data for requests * @param array $options Default options for requests * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string, Stringable or null. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data argument is not an array. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ public function __construct($url = null, $headers = [], $data = [], $options = []) { if ($url !== null && InputValidator::is_string_or_stringable($url) === false) { throw InvalidArgument::create(1, '$url', 'string|Stringable|null', gettype($url)); } if (is_array($headers) === false) { throw InvalidArgument::create(2, '$headers', 'array', gettype($headers)); } if (is_array($data) === false) { throw InvalidArgument::create(3, '$data', 'array', gettype($data)); } if (is_array($options) === false) { throw InvalidArgument::create(4, '$options', 'array', gettype($options)); } $this->url = $url; $this->headers = $headers; $this->data = $data; $this->options = $options; if (empty($this->options['cookies'])) { $this->options['cookies'] = new Jar(); } } /** * Get a property's value * * @param string $name Property name. * @return mixed|null Property value, null if none found */ public function __get($name) { if (isset($this->options[$name])) { return $this->options[$name]; } return null; } /** * Set a property's value * * @param string $name Property name. * @param mixed $value Property value */ public function __set($name, $value) { $this->options[$name] = $value; } /** * Remove a property's value * * @param string $name Property name. */ public function __isset($name) { return isset($this->options[$name]); } /** * Remove a property's value * * @param string $name Property name. */ public function __unset($name) { unset($this->options[$name]); } /**#@+ * @see \WpOrg\Requests\Session::request() * @param string $url * @param array $headers * @param array $options * @return \WpOrg\Requests\Response */ /** * Send a GET request */ public function get($url, $headers = [], $options = []) { return $this->request($url, $headers, null, Requests::GET, $options); } /** * Send a HEAD request */ public function head($url, $headers = [], $options = []) { return $this->request($url, $headers, null, Requests::HEAD, $options); } /** * Send a DELETE request */ public function delete($url, $headers = [], $options = []) { return $this->request($url, $headers, null, Requests::DELETE, $options); } /**#@-*/ /**#@+ * @see \WpOrg\Requests\Session::request() * @param string $url * @param array $headers * @param array $data * @param array $options * @return \WpOrg\Requests\Response */ /** * Send a POST request */ public function post($url, $headers = [], $data = [], $options = []) { return $this->request($url, $headers, $data, Requests::POST, $options); } /** * Send a PUT request */ public function put($url, $headers = [], $data = [], $options = []) { return $this->request($url, $headers, $data, Requests::PUT, $options); } /** * Send a PATCH request * * Note: Unlike {@see \WpOrg\Requests\Session::post()} and {@see \WpOrg\Requests\Session::put()}, * `$headers` is required, as the specification recommends that should send an ETag * * @link https://tools.ietf.org/html/rfc5789 */ public function patch($url, $headers, $data = [], $options = []) { return $this->request($url, $headers, $data, Requests::PATCH, $options); } /**#@-*/ /** * Main interface for HTTP requests * * This method initiates a request and sends it via a transport before * parsing. * * @see \WpOrg\Requests\Requests::request() * * @param string $url URL to request * @param array $headers Extra headers to send with the request * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests * @param string $type HTTP request type (use \WpOrg\Requests\Requests constants) * @param array $options Options for the request (see {@see \WpOrg\Requests\Requests::request()}) * @return \WpOrg\Requests\Response * * @throws \WpOrg\Requests\Exception On invalid URLs (`nonhttp`) */ public function request($url, $headers = [], $data = [], $type = Requests::GET, $options = []) { $request = $this->merge_request(compact('url', 'headers', 'data', 'options')); return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']); } /** * Send multiple HTTP requests simultaneously * * @see \WpOrg\Requests\Requests::request_multiple() * * @param array $requests Requests data (see {@see \WpOrg\Requests\Requests::request_multiple()}) * @param array $options Global and default options (see {@see \WpOrg\Requests\Requests::request()}) * @return array Responses (either \WpOrg\Requests\Response or a \WpOrg\Requests\Exception object) * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array. */ public function request_multiple($requests, $options = []) { if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) { throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests)); } if (is_array($options) === false) { throw InvalidArgument::create(2, '$options', 'array', gettype($options)); } foreach ($requests as $key => $request) { $requests[$key] = $this->merge_request($request, false); } $options = array_merge($this->options, $options); // Disallow forcing the type, as that's a per request setting unset($options['type']); return Requests::request_multiple($requests, $options); } public function __wakeup() { throw new \LogicException( __CLASS__ . ' should never be unserialized' ); } /** * Merge a request's data with the default data * * @param array $request Request data (same form as {@see \WpOrg\Requests\Session::request_multiple()}) * @param boolean $merge_options Should we merge options as well? * @return array Request data */ protected function merge_request($request, $merge_options = true) { if ($this->url !== null) { $request['url'] = Iri::absolutize($this->url, $request['url']); $request['url'] = $request['url']->uri; } if (empty($request['headers'])) { $request['headers'] = []; } $request['headers'] = array_merge($this->headers, $request['headers']); if (empty($request['data'])) { if (is_array($this->data)) { $request['data'] = $this->data; } } elseif (is_array($request['data']) && is_array($this->data)) { $request['data'] = array_merge($this->data, $request['data']); } if ($merge_options === true) { $request['options'] = array_merge($this->options, $request['options']); // Disallow forcing the type, as that's a per request setting unset($request['options']['type']); } return $request; } } IdnaEncoder.php000064400000030223150211523530007425 0ustar00 0) { if ($position + $length > $strlen) { throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); } for ($position++; $remaining > 0; $position++) { $value = ord($input[$position]); // If it is invalid, count the sequence as invalid and reprocess the current byte: if (($value & 0xC0) !== 0x80) { throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); } --$remaining; $character |= ($value & 0x3F) << ($remaining * 6); } $position--; } if (// Non-shortest form sequences are invalid $length > 1 && $character <= 0x7F || $length > 2 && $character <= 0x7FF || $length > 3 && $character <= 0xFFFF // Outside of range of ucschar codepoints // Noncharacters || ($character & 0xFFFE) === 0xFFFE || $character >= 0xFDD0 && $character <= 0xFDEF || ( // Everything else not in ucschar $character > 0xD7FF && $character < 0xF900 || $character < 0x20 || $character > 0x7E && $character < 0xA0 || $character > 0xEFFFD ) ) { throw new Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character); } $codepoints[] = $character; } return $codepoints; } /** * RFC3492-compliant encoder * * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code * * @param string $input UTF-8 encoded string to encode * @return string Punycode-encoded string * * @throws \WpOrg\Requests\Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`) */ public static function punycode_encode($input) { $output = ''; // let n = initial_n $n = self::BOOTSTRAP_INITIAL_N; // let delta = 0 $delta = 0; // let bias = initial_bias $bias = self::BOOTSTRAP_INITIAL_BIAS; // let h = b = the number of basic code points in the input $h = 0; $b = 0; // see loop // copy them to the output in order $codepoints = self::utf8_to_codepoints($input); $extended = []; foreach ($codepoints as $char) { if ($char < 128) { // Character is valid ASCII // TODO: this should also check if it's valid for a URL $output .= chr($char); $h++; // Check if the character is non-ASCII, but below initial n // This never occurs for Punycode, so ignore in coverage // @codeCoverageIgnoreStart } elseif ($char < $n) { throw new Exception('Invalid character', 'idna.character_outside_domain', $char); // @codeCoverageIgnoreEnd } else { $extended[$char] = true; } } $extended = array_keys($extended); sort($extended); $b = $h; // [copy them] followed by a delimiter if b > 0 if (strlen($output) > 0) { $output .= '-'; } // {if the input contains a non-basic code point < n then fail} // while h < length(input) do begin $codepointcount = count($codepoints); while ($h < $codepointcount) { // let m = the minimum code point >= n in the input $m = array_shift($extended); //printf('next code point to insert is %s' . PHP_EOL, dechex($m)); // let delta = delta + (m - n) * (h + 1), fail on overflow $delta += ($m - $n) * ($h + 1); // let n = m $n = $m; // for each code point c in the input (in order) do begin for ($num = 0; $num < $codepointcount; $num++) { $c = $codepoints[$num]; // if c < n then increment delta, fail on overflow if ($c < $n) { $delta++; } elseif ($c === $n) { // if c == n then begin // let q = delta $q = $delta; // for k = base to infinity in steps of base do begin for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) { // let t = tmin if k <= bias {+ tmin}, or // tmax if k >= bias + tmax, or k - bias otherwise if ($k <= ($bias + self::BOOTSTRAP_TMIN)) { $t = self::BOOTSTRAP_TMIN; } elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) { $t = self::BOOTSTRAP_TMAX; } else { $t = $k - $bias; } // if q < t then break if ($q < $t) { break; } // output the code point for digit t + ((q - t) mod (base - t)) $digit = (int) ($t + (($q - $t) % (self::BOOTSTRAP_BASE - $t))); $output .= self::digit_to_char($digit); // let q = (q - t) div (base - t) $q = (int) floor(($q - $t) / (self::BOOTSTRAP_BASE - $t)); } // end // output the code point for digit q $output .= self::digit_to_char($q); // let bias = adapt(delta, h + 1, test h equals b?) $bias = self::adapt($delta, $h + 1, $h === $b); // let delta = 0 $delta = 0; // increment h $h++; } // end } // end // increment delta and n $delta++; $n++; } // end return $output; } /** * Convert a digit to its respective character * * @link https://tools.ietf.org/html/rfc3492#section-5 * * @param int $digit Digit in the range 0-35 * @return string Single character corresponding to digit * * @throws \WpOrg\Requests\Exception On invalid digit (`idna.invalid_digit`) */ protected static function digit_to_char($digit) { // @codeCoverageIgnoreStart // As far as I know, this never happens, but still good to be sure. if ($digit < 0 || $digit > 35) { throw new Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit); } // @codeCoverageIgnoreEnd $digits = 'abcdefghijklmnopqrstuvwxyz0123456789'; return substr($digits, $digit, 1); } /** * Adapt the bias * * @link https://tools.ietf.org/html/rfc3492#section-6.1 * @param int $delta * @param int $numpoints * @param bool $firsttime * @return int|float New bias * * function adapt(delta,numpoints,firsttime): */ protected static function adapt($delta, $numpoints, $firsttime) { // if firsttime then let delta = delta div damp if ($firsttime) { $delta = floor($delta / self::BOOTSTRAP_DAMP); } else { // else let delta = delta div 2 $delta = floor($delta / 2); } // let delta = delta + (delta div numpoints) $delta += floor($delta / $numpoints); // let k = 0 $k = 0; // while delta > ((base - tmin) * tmax) div 2 do begin $max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2); while ($delta > $max) { // let delta = delta div (base - tmin) $delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN)); // let k = k + base $k += self::BOOTSTRAP_BASE; } // end // return k + (((base - tmin + 1) * delta) div (delta + skew)) return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW)); } } Response/Headers.php000064400000006035150211523530010427 0ustar00data[$offset])) { return null; } return $this->flatten($this->data[$offset]); } /** * Set the given item * * @param string $offset Item name * @param string $value Item value * * @throws \WpOrg\Requests\Exception On attempting to use dictionary as list (`invalidset`) */ public function offsetSet($offset, $value) { if ($offset === null) { throw new Exception('Object is a dictionary, not a list', 'invalidset'); } if (is_string($offset)) { $offset = strtolower($offset); } if (!isset($this->data[$offset])) { $this->data[$offset] = []; } $this->data[$offset][] = $value; } /** * Get all values for a given header * * @param string $offset Name of the header to retrieve. * @return array|null Header values * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not valid as an array key. */ public function getValues($offset) { if (!is_string($offset) && !is_int($offset)) { throw InvalidArgument::create(1, '$offset', 'string|int', gettype($offset)); } if (is_string($offset)) { $offset = strtolower($offset); } if (!isset($this->data[$offset])) { return null; } return $this->data[$offset]; } /** * Flattens a value into a string * * Converts an array into a string by imploding values with a comma, as per * RFC2616's rules for folding headers. * * @param string|array $value Value to flatten * @return string Flattened value * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or an array. */ public function flatten($value) { if (is_string($value)) { return $value; } if (is_array($value)) { return implode(',', $value); } throw InvalidArgument::create(1, '$value', 'string|array', gettype($value)); } /** * Get an iterator for the data * * Converts the internally stored values to a comma-separated string if there is more * than one value for a key. * * @return \ArrayIterator */ public function getIterator() { return new FilteredIterator($this->data, [$this, 'flatten']); } } Cookie.php000064400000036035150211523530006472 0ustar00name = $name; $this->value = $value; $this->attributes = $attributes; $default_flags = [ 'creation' => time(), 'last-access' => time(), 'persistent' => false, 'host-only' => true, ]; $this->flags = array_merge($default_flags, $flags); $this->reference_time = time(); if ($reference_time !== null) { $this->reference_time = $reference_time; } $this->normalize(); } /** * Get the cookie value * * Attributes and other data can be accessed via methods. */ public function __toString() { return $this->value; } /** * Check if a cookie is expired. * * Checks the age against $this->reference_time to determine if the cookie * is expired. * * @return boolean True if expired, false if time is valid. */ public function is_expired() { // RFC6265, s. 4.1.2.2: // If a cookie has both the Max-Age and the Expires attribute, the Max- // Age attribute has precedence and controls the expiration date of the // cookie. if (isset($this->attributes['max-age'])) { $max_age = $this->attributes['max-age']; return $max_age < $this->reference_time; } if (isset($this->attributes['expires'])) { $expires = $this->attributes['expires']; return $expires < $this->reference_time; } return false; } /** * Check if a cookie is valid for a given URI * * @param \WpOrg\Requests\Iri $uri URI to check * @return boolean Whether the cookie is valid for the given URI */ public function uri_matches(Iri $uri) { if (!$this->domain_matches($uri->host)) { return false; } if (!$this->path_matches($uri->path)) { return false; } return empty($this->attributes['secure']) || $uri->scheme === 'https'; } /** * Check if a cookie is valid for a given domain * * @param string $domain Domain to check * @return boolean Whether the cookie is valid for the given domain */ public function domain_matches($domain) { if (is_string($domain) === false) { return false; } if (!isset($this->attributes['domain'])) { // Cookies created manually; cookies created by Requests will set // the domain to the requested domain return true; } $cookie_domain = $this->attributes['domain']; if ($cookie_domain === $domain) { // The cookie domain and the passed domain are identical. return true; } // If the cookie is marked as host-only and we don't have an exact // match, reject the cookie if ($this->flags['host-only'] === true) { return false; } if (strlen($domain) <= strlen($cookie_domain)) { // For obvious reasons, the cookie domain cannot be a suffix if the passed domain // is shorter than the cookie domain return false; } if (substr($domain, -1 * strlen($cookie_domain)) !== $cookie_domain) { // The cookie domain should be a suffix of the passed domain. return false; } $prefix = substr($domain, 0, strlen($domain) - strlen($cookie_domain)); if (substr($prefix, -1) !== '.') { // The last character of the passed domain that is not included in the // domain string should be a %x2E (".") character. return false; } // The passed domain should be a host name (i.e., not an IP address). return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $domain); } /** * Check if a cookie is valid for a given path * * From the path-match check in RFC 6265 section 5.1.4 * * @param string $request_path Path to check * @return boolean Whether the cookie is valid for the given path */ public function path_matches($request_path) { if (empty($request_path)) { // Normalize empty path to root $request_path = '/'; } if (!isset($this->attributes['path'])) { // Cookies created manually; cookies created by Requests will set // the path to the requested path return true; } if (is_scalar($request_path) === false) { return false; } $cookie_path = $this->attributes['path']; if ($cookie_path === $request_path) { // The cookie-path and the request-path are identical. return true; } if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) { if (substr($cookie_path, -1) === '/') { // The cookie-path is a prefix of the request-path, and the last // character of the cookie-path is %x2F ("/"). return true; } if (substr($request_path, strlen($cookie_path), 1) === '/') { // The cookie-path is a prefix of the request-path, and the // first character of the request-path that is not included in // the cookie-path is a %x2F ("/") character. return true; } } return false; } /** * Normalize cookie and attributes * * @return boolean Whether the cookie was successfully normalized */ public function normalize() { foreach ($this->attributes as $key => $value) { $orig_value = $value; if (is_string($key)) { $value = $this->normalize_attribute($key, $value); } if ($value === null) { unset($this->attributes[$key]); continue; } if ($value !== $orig_value) { $this->attributes[$key] = $value; } } return true; } /** * Parse an individual cookie attribute * * Handles parsing individual attributes from the cookie values. * * @param string $name Attribute name * @param string|int|bool $value Attribute value (string/integer value, or true if empty/flag) * @return mixed Value if available, or null if the attribute value is invalid (and should be skipped) */ protected function normalize_attribute($name, $value) { switch (strtolower($name)) { case 'expires': // Expiration parsing, as per RFC 6265 section 5.2.1 if (is_int($value)) { return $value; } $expiry_time = strtotime($value); if ($expiry_time === false) { return null; } return $expiry_time; case 'max-age': // Expiration parsing, as per RFC 6265 section 5.2.2 if (is_int($value)) { return $value; } // Check that we have a valid age if (!preg_match('/^-?\d+$/', $value)) { return null; } $delta_seconds = (int) $value; if ($delta_seconds <= 0) { $expiry_time = 0; } else { $expiry_time = $this->reference_time + $delta_seconds; } return $expiry_time; case 'domain': // Domains are not required as per RFC 6265 section 5.2.3 if (empty($value)) { return null; } // Domain normalization, as per RFC 6265 section 5.2.3 if ($value[0] === '.') { $value = substr($value, 1); } return $value; default: return $value; } } /** * Format a cookie for a Cookie header * * This is used when sending cookies to a server. * * @return string Cookie formatted for Cookie header */ public function format_for_header() { return sprintf('%s=%s', $this->name, $this->value); } /** * Format a cookie for a Set-Cookie header * * This is used when sending cookies to clients. This isn't really * applicable to client-side usage, but might be handy for debugging. * * @return string Cookie formatted for Set-Cookie header */ public function format_for_set_cookie() { $header_value = $this->format_for_header(); if (!empty($this->attributes)) { $parts = []; foreach ($this->attributes as $key => $value) { // Ignore non-associative attributes if (is_numeric($key)) { $parts[] = $value; } else { $parts[] = sprintf('%s=%s', $key, $value); } } $header_value .= '; ' . implode('; ', $parts); } return $header_value; } /** * Parse a cookie string into a cookie object * * Based on Mozilla's parsing code in Firefox and related projects, which * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265 * specifies some of this handling, but not in a thorough manner. * * @param string $cookie_header Cookie header value (from a Set-Cookie header) * @param string $name * @param int|null $reference_time * @return \WpOrg\Requests\Cookie Parsed cookie object * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $cookie_header argument is not a string. * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $name argument is not a string. */ public static function parse($cookie_header, $name = '', $reference_time = null) { if (is_string($cookie_header) === false) { throw InvalidArgument::create(1, '$cookie_header', 'string', gettype($cookie_header)); } if (is_string($name) === false) { throw InvalidArgument::create(2, '$name', 'string', gettype($name)); } $parts = explode(';', $cookie_header); $kvparts = array_shift($parts); if (!empty($name)) { $value = $cookie_header; } elseif (strpos($kvparts, '=') === false) { // Some sites might only have a value without the equals separator. // Deviate from RFC 6265 and pretend it was actually a blank name // (`=foo`) // // https://bugzilla.mozilla.org/show_bug.cgi?id=169091 $name = ''; $value = $kvparts; } else { list($name, $value) = explode('=', $kvparts, 2); } $name = trim($name); $value = trim($value); // Attribute keys are handled case-insensitively $attributes = new CaseInsensitiveDictionary(); if (!empty($parts)) { foreach ($parts as $part) { if (strpos($part, '=') === false) { $part_key = $part; $part_value = true; } else { list($part_key, $part_value) = explode('=', $part, 2); $part_value = trim($part_value); } $part_key = trim($part_key); $attributes[$part_key] = $part_value; } } return new static($name, $value, $attributes, [], $reference_time); } /** * Parse all Set-Cookie headers from request headers * * @param \WpOrg\Requests\Response\Headers $headers Headers to parse from * @param \WpOrg\Requests\Iri|null $origin URI for comparing cookie origins * @param int|null $time Reference time for expiration calculation * @return array * * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $origin argument is not null or an instance of the Iri class. */ public static function parse_from_headers(Headers $headers, $origin = null, $time = null) { $cookie_headers = $headers->getValues('Set-Cookie'); if (empty($cookie_headers)) { return []; } if ($origin !== null && !($origin instanceof Iri)) { throw InvalidArgument::create(2, '$origin', Iri::class . ' or null', gettype($origin)); } $cookies = []; foreach ($cookie_headers as $header) { $parsed = self::parse($header, '', $time); // Default domain/path attributes if (empty($parsed->attributes['domain']) && !empty($origin)) { $parsed->attributes['domain'] = $origin->host; $parsed->flags['host-only'] = true; } else { $parsed->flags['host-only'] = false; } $path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/'); if (!$path_is_valid && !empty($origin)) { $path = $origin->path; // Default path normalization as per RFC 6265 section 5.1.4 if (substr($path, 0, 1) !== '/') { // If the uri-path is empty or if the first character of // the uri-path is not a %x2F ("/") character, output // %x2F ("/") and skip the remaining steps. $path = '/'; } elseif (substr_count($path, '/') === 1) { // If the uri-path contains no more than one %x2F ("/") // character, output %x2F ("/") and skip the remaining // step. $path = '/'; } else { // Output the characters of the uri-path from the first // character up to, but not including, the right-most // %x2F ("/"). $path = substr($path, 0, strrpos($path, '/')); } $parsed->attributes['path'] = $path; } // Reject invalid cookie domains if (!empty($origin) && !$parsed->domain_matches($origin->host)) { continue; } $cookies[$parsed->name] = $parsed; } return $cookies; } } HookManager.php000064400000001305150211523530007444 0ustar000 is executed later */ public function register($hook, $callback, $priority = 0); /** * Dispatch a message * * @param string $hook Hook name * @param array $parameters Parameters to pass to callbacks * @return boolean Successfulness */ public function dispatch($hook, $parameters = []); } Core.php000064400000004273150211552310006146 0ustar00` or `` tags as defined in Media RSS and iTunes RSS respectively * * Used by {@see \SimplePie\Enclosure::get_rating()} and {@see \SimplePie\Enclosure::get_ratings()} * * This class can be overloaded with {@see \SimplePie\SimplePie::set_rating_class()} * * @package SimplePie * @subpackage API */ class Rating { /** * Rating scheme * * @var string * @see get_scheme() */ public $scheme; /** * Rating value * * @var string * @see get_value() */ public $value; /** * Constructor, used to input the data * * For documentation on all the parameters, see the corresponding * properties and their accessors */ public function __construct($scheme = null, $value = null) { $this->scheme = $scheme; $this->value = $value; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the organizational scheme for the rating * * @return string|null */ public function get_scheme() { if ($this->scheme !== null) { return $this->scheme; } return null; } /** * Get the value of the rating * * @return string|null */ public function get_value() { if ($this->value !== null) { return $this->value; } return null; } } class_alias('SimplePie\Rating', 'SimplePie_Rating'); Restriction.php000064400000010020150211552310007546 0ustar00` as defined in Media RSS * * Used by {@see \SimplePie\Enclosure::get_restriction()} and {@see \SimplePie\Enclosure::get_restrictions()} * * This class can be overloaded with {@see \SimplePie\SimplePie::set_restriction_class()} * * @package SimplePie * @subpackage API */ class Restriction { /** * Relationship ('allow'/'deny') * * @var string * @see get_relationship() */ public $relationship; /** * Type of restriction * * @var string * @see get_type() */ public $type; /** * Restricted values * * @var string * @see get_value() */ public $value; /** * Constructor, used to input the data * * For documentation on all the parameters, see the corresponding * properties and their accessors */ public function __construct($relationship = null, $type = null, $value = null) { $this->relationship = $relationship; $this->type = $type; $this->value = $value; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the relationship * * @return string|null Either 'allow' or 'deny' */ public function get_relationship() { if ($this->relationship !== null) { return $this->relationship; } return null; } /** * Get the type * * @return string|null */ public function get_type() { if ($this->type !== null) { return $this->type; } return null; } /** * Get the list of restricted things * * @return string|null */ public function get_value() { if ($this->value !== null) { return $this->value; } return null; } } class_alias('SimplePie\Restriction', 'SimplePie_Restriction'); Registry.php000064400000020766150211552310007073 0ustar00 */ protected $default = [ Cache::class => Cache::class, Locator::class => Locator::class, Parser::class => Parser::class, File::class => File::class, Sanitize::class => Sanitize::class, Item::class => Item::class, Author::class => Author::class, Category::class => Category::class, Enclosure::class => Enclosure::class, Caption::class => Caption::class, Copyright::class => Copyright::class, Credit::class => Credit::class, Rating::class => Rating::class, Restriction::class => Restriction::class, Sniffer::class => Sniffer::class, Source::class => Source::class, Misc::class => Misc::class, DeclarationParser::class => DeclarationParser::class, Date::class => Date::class, ]; /** * Class mapping * * @see register() * @var array */ protected $classes = []; /** * Legacy classes * * @see register() * @var array */ protected $legacy = []; /** * Legacy types * * @see register() * @var array */ private $legacyTypes = [ 'Cache' => Cache::class, 'Locator' => Locator::class, 'Parser' => Parser::class, 'File' => File::class, 'Sanitize' => Sanitize::class, 'Item' => Item::class, 'Author' => Author::class, 'Category' => Category::class, 'Enclosure' => Enclosure::class, 'Caption' => Caption::class, 'Copyright' => Copyright::class, 'Credit' => Credit::class, 'Rating' => Rating::class, 'Restriction' => Restriction::class, 'Content_Type_Sniffer' => Sniffer::class, 'Source' => Source::class, 'Misc' => Misc::class, 'XML_Declaration_Parser' => DeclarationParser::class, 'Parse_Date' => Date::class, ]; /** * Constructor * * No-op */ public function __construct() { } /** * Register a class * * @param string $type See {@see $default} for names * @param class-string $class Class name, must subclass the corresponding default * @param bool $legacy Whether to enable legacy support for this class * @return bool Successfulness */ public function register($type, $class, $legacy = false) { if (array_key_exists($type, $this->legacyTypes)) { // trigger_error(sprintf('"%s"(): Using argument #1 ($type) with value "%s" is deprecated since SimplePie 1.8.0, use class-string "%s" instead.', __METHOD__, $type, $this->legacyTypes[$type]), \E_USER_DEPRECATED); $type = $this->legacyTypes[$type]; } if (!array_key_exists($type, $this->default)) { return false; } if (!class_exists($class)) { return false; } /** @var string */ $base_class = $this->default[$type]; if (!is_subclass_of($class, $base_class)) { return false; } $this->classes[$type] = $class; if ($legacy) { $this->legacy[] = $class; } return true; } /** * Get the class registered for a type * * Where possible, use {@see create()} or {@see call()} instead * * @template T * @param class-string $type * @return class-string|null */ public function get_class($type) { if (array_key_exists($type, $this->legacyTypes)) { // trigger_error(sprintf('"%s"(): Using argument #1 ($type) with value "%s" is deprecated since SimplePie 1.8.0, use class-string "%s" instead.', __METHOD__, $type, $this->legacyTypes[$type]), \E_USER_DEPRECATED); $type = $this->legacyTypes[$type]; } if (!array_key_exists($type, $this->default)) { return null; } $class = $this->default[$type]; if (array_key_exists($type, $this->classes)) { $class = $this->classes[$type]; } return $class; } /** * Create a new instance of a given type * * @template T class-string $type * @param class-string $type * @param array $parameters Parameters to pass to the constructor * @return T Instance of class */ public function &create($type, $parameters = []) { $class = $this->get_class($type); if (!method_exists($class, '__construct')) { $instance = new $class(); } else { $reflector = new \ReflectionClass($class); $instance = $reflector->newInstanceArgs($parameters); } if ($instance instanceof RegistryAware) { $instance->set_registry($this); } elseif (method_exists($instance, 'set_registry')) { trigger_error(sprintf('Using the method "set_registry()" without implementing "%s" is deprecated since SimplePie 1.8.0, implement "%s" in "%s".', RegistryAware::class, RegistryAware::class, $class), \E_USER_DEPRECATED); $instance->set_registry($this); } return $instance; } /** * Call a static method for a type * * @param class-string $type * @param string $method * @param array $parameters * @return mixed */ public function &call($type, $method, $parameters = []) { $class = $this->get_class($type); if (in_array($class, $this->legacy)) { switch ($type) { case Cache::class: // For backwards compatibility with old non-static // Cache::create() methods in PHP < 8.0. // No longer supported as of PHP 8.0. if ($method === 'get_handler') { $result = @call_user_func_array([$class, 'create'], $parameters); return $result; } break; } } $result = call_user_func_array([$class, $method], $parameters); return $result; } } class_alias('SimplePie\Registry', 'SimplePie_Registry'); Source.php000064400000057305150211552310006522 0ustar00` * * Used by {@see \SimplePie\Item::get_source()} * * This class can be overloaded with {@see \SimplePie::set_source_class()} * * @package SimplePie * @subpackage API */ class Source implements RegistryAware { public $item; public $data = []; protected $registry; public function __construct($item, $data) { $this->item = $item; $this->data = $data; } public function set_registry(\SimplePie\Registry $registry)/* : void */ { $this->registry = $registry; } public function __toString() { return md5(serialize($this->data)); } public function get_source_tags($namespace, $tag) { if (isset($this->data['child'][$namespace][$tag])) { return $this->data['child'][$namespace][$tag]; } return null; } public function get_base($element = []) { return $this->item->get_base($element); } public function sanitize($data, $type, $base = '') { return $this->item->sanitize($data, $type, $base); } public function get_item() { return $this->item; } public function get_title() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'title')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'title')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'title')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'title')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'title')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'title')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'title')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } return null; } public function get_category($key = 0) { $categories = $this->get_categories(); if (isset($categories[$key])) { return $categories[$key]; } return null; } public function get_categories() { $categories = []; foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'category') as $category) { $term = null; $scheme = null; $label = null; if (isset($category['attribs']['']['term'])) { $term = $this->sanitize($category['attribs']['']['term'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'category') as $category) { // This is really the label, but keep this as the term also for BC. // Label will also work on retrieving because that falls back to term. $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); if (isset($category['attribs']['']['domain'])) { $scheme = $this->sanitize($category['attribs']['']['domain'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = null; } $categories[] = $this->registry->create(Category::class, [$term, $scheme, null]); } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'subject') as $category) { $categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'subject') as $category) { $categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } if (!empty($categories)) { return array_unique($categories); } return null; } public function get_author($key = 0) { $authors = $this->get_authors(); if (isset($authors[$key])) { return $authors[$key]; } return null; } public function get_authors() { $authors = []; foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'author') as $author) { $name = null; $uri = null; $email = null; if (isset($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'])) { $name = $this->sanitize($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'])) { $uri = $this->sanitize($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0])); } if (isset($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'])) { $email = $this->sanitize($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $uri !== null) { $authors[] = $this->registry->create(Author::class, [$name, $uri, $email]); } } if ($author = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'author')) { $name = null; $url = null; $email = null; if (isset($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'])) { $name = $this->sanitize($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'])) { $url = $this->sanitize($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0])); } if (isset($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $url !== null) { $authors[] = $this->registry->create(Author::class, [$name, $url, $email]); } } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'creator') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'creator') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'author') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } if (!empty($authors)) { return array_unique($authors); } return null; } public function get_contributor($key = 0) { $contributors = $this->get_contributors(); if (isset($contributors[$key])) { return $contributors[$key]; } return null; } public function get_contributors() { $contributors = []; foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'contributor') as $contributor) { $name = null; $uri = null; $email = null; if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'])) { $name = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'])) { $uri = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0])); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'])) { $email = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $uri !== null) { $contributors[] = $this->registry->create(Author::class, [$name, $uri, $email]); } } foreach ((array) $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'contributor') as $contributor) { $name = null; $url = null; $email = null; if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'])) { $name = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'])) { $url = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0])); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $url !== null) { $contributors[] = $this->registry->create(Author::class, [$name, $url, $email]); } } if (!empty($contributors)) { return array_unique($contributors); } return null; } public function get_link($key = 0, $rel = 'alternate') { $links = $this->get_links($rel); if (isset($links[$key])) { return $links[$key]; } return null; } /** * Added for parity between the parent-level and the item/entry-level. */ public function get_permalink() { return $this->get_link(0); } public function get_links($rel = 'alternate') { if (!isset($this->data['links'])) { $this->data['links'] = []; if ($links = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'link')) { foreach ($links as $link) { if (isset($link['attribs']['']['href'])) { $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); } } } if ($links = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'link')) { foreach ($links as $link) { if (isset($link['attribs']['']['href'])) { $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); } } } if ($links = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } $keys = array_keys($this->data['links']); foreach ($keys as $key) { if ($this->registry->call(Misc::class, 'is_isegment_nz_nc', [$key])) { if (isset($this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key])) { $this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key]); $this->data['links'][$key] = &$this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key]; } else { $this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key] = &$this->data['links'][$key]; } } elseif (substr($key, 0, 41) === \SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY) { $this->data['links'][substr($key, 41)] = &$this->data['links'][$key]; } $this->data['links'][$key] = array_unique($this->data['links'][$key]); } } if (isset($this->data['links'][$rel])) { return $this->data['links'][$rel]; } return null; } public function get_description() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'subtitle')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'tagline')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'description')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'description')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'description')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'description')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'description')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'summary')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'subtitle')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($return[0])); } return null; } public function get_copyright() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'rights')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'copyright')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'copyright')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'rights')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'rights')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } return null; } public function get_language() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'language')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'language')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'language')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif (isset($this->data['xml_lang'])) { return $this->sanitize($this->data['xml_lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } return null; } public function get_latitude() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_W3C_BASIC_GEO, 'lat')) { return (float) $return[0]['data']; } elseif (($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) { return (float) $match[1]; } return null; } public function get_longitude() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_W3C_BASIC_GEO, 'long')) { return (float) $return[0]['data']; } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_W3C_BASIC_GEO, 'lon')) { return (float) $return[0]['data']; } elseif (($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) { return (float) $match[2]; } return null; } public function get_image_url() { if ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'image')) { return $this->sanitize($return[0]['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'logo')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_source_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'icon')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($return[0])); } return null; } } class_alias('SimplePie\Source', 'SimplePie_Source'); Parse/Date.php000064400000064345150211552310007213 0ustar00 ordinal day number in the week * * @access protected * @var array */ public $day = [ // English 'mon' => 1, 'monday' => 1, 'tue' => 2, 'tuesday' => 2, 'wed' => 3, 'wednesday' => 3, 'thu' => 4, 'thursday' => 4, 'fri' => 5, 'friday' => 5, 'sat' => 6, 'saturday' => 6, 'sun' => 7, 'sunday' => 7, // Dutch 'maandag' => 1, 'dinsdag' => 2, 'woensdag' => 3, 'donderdag' => 4, 'vrijdag' => 5, 'zaterdag' => 6, 'zondag' => 7, // French 'lundi' => 1, 'mardi' => 2, 'mercredi' => 3, 'jeudi' => 4, 'vendredi' => 5, 'samedi' => 6, 'dimanche' => 7, // German 'montag' => 1, 'mo' => 1, 'dienstag' => 2, 'di' => 2, 'mittwoch' => 3, 'mi' => 3, 'donnerstag' => 4, 'do' => 4, 'freitag' => 5, 'fr' => 5, 'samstag' => 6, 'sa' => 6, 'sonnabend' => 6, // AFAIK no short form for sonnabend 'so' => 7, 'sonntag' => 7, // Italian 'lunedì' => 1, 'martedì' => 2, 'mercoledì' => 3, 'giovedì' => 4, 'venerdì' => 5, 'sabato' => 6, 'domenica' => 7, // Spanish 'lunes' => 1, 'martes' => 2, 'miércoles' => 3, 'jueves' => 4, 'viernes' => 5, 'sábado' => 6, 'domingo' => 7, // Finnish 'maanantai' => 1, 'tiistai' => 2, 'keskiviikko' => 3, 'torstai' => 4, 'perjantai' => 5, 'lauantai' => 6, 'sunnuntai' => 7, // Hungarian 'hétfő' => 1, 'kedd' => 2, 'szerda' => 3, 'csütörtok' => 4, 'péntek' => 5, 'szombat' => 6, 'vasárnap' => 7, // Greek 'Δευ' => 1, 'Τρι' => 2, 'Τετ' => 3, 'Πεμ' => 4, 'Παρ' => 5, 'Σαβ' => 6, 'Κυρ' => 7, // Russian 'Пн.' => 1, 'Вт.' => 2, 'Ср.' => 3, 'Чт.' => 4, 'Пт.' => 5, 'Сб.' => 6, 'Вс.' => 7, ]; /** * List of months, calendar month name => calendar month number * * @access protected * @var array */ public $month = [ // English 'jan' => 1, 'january' => 1, 'feb' => 2, 'february' => 2, 'mar' => 3, 'march' => 3, 'apr' => 4, 'april' => 4, 'may' => 5, // No long form of May 'jun' => 6, 'june' => 6, 'jul' => 7, 'july' => 7, 'aug' => 8, 'august' => 8, 'sep' => 9, 'september' => 9, 'oct' => 10, 'october' => 10, 'nov' => 11, 'november' => 11, 'dec' => 12, 'december' => 12, // Dutch 'januari' => 1, 'februari' => 2, 'maart' => 3, 'april' => 4, 'mei' => 5, 'juni' => 6, 'juli' => 7, 'augustus' => 8, 'september' => 9, 'oktober' => 10, 'november' => 11, 'december' => 12, // French 'janvier' => 1, 'février' => 2, 'mars' => 3, 'avril' => 4, 'mai' => 5, 'juin' => 6, 'juillet' => 7, 'août' => 8, 'septembre' => 9, 'octobre' => 10, 'novembre' => 11, 'décembre' => 12, // German 'januar' => 1, 'jan' => 1, 'februar' => 2, 'feb' => 2, 'märz' => 3, 'mär' => 3, 'april' => 4, 'apr' => 4, 'mai' => 5, // no short form for may 'juni' => 6, 'jun' => 6, 'juli' => 7, 'jul' => 7, 'august' => 8, 'aug' => 8, 'september' => 9, 'sep' => 9, 'oktober' => 10, 'okt' => 10, 'november' => 11, 'nov' => 11, 'dezember' => 12, 'dez' => 12, // Italian 'gennaio' => 1, 'febbraio' => 2, 'marzo' => 3, 'aprile' => 4, 'maggio' => 5, 'giugno' => 6, 'luglio' => 7, 'agosto' => 8, 'settembre' => 9, 'ottobre' => 10, 'novembre' => 11, 'dicembre' => 12, // Spanish 'enero' => 1, 'febrero' => 2, 'marzo' => 3, 'abril' => 4, 'mayo' => 5, 'junio' => 6, 'julio' => 7, 'agosto' => 8, 'septiembre' => 9, 'setiembre' => 9, 'octubre' => 10, 'noviembre' => 11, 'diciembre' => 12, // Finnish 'tammikuu' => 1, 'helmikuu' => 2, 'maaliskuu' => 3, 'huhtikuu' => 4, 'toukokuu' => 5, 'kesäkuu' => 6, 'heinäkuu' => 7, 'elokuu' => 8, 'suuskuu' => 9, 'lokakuu' => 10, 'marras' => 11, 'joulukuu' => 12, // Hungarian 'január' => 1, 'február' => 2, 'március' => 3, 'április' => 4, 'május' => 5, 'június' => 6, 'július' => 7, 'augusztus' => 8, 'szeptember' => 9, 'október' => 10, 'november' => 11, 'december' => 12, // Greek 'Ιαν' => 1, 'Φεβ' => 2, 'Μάώ' => 3, 'Μαώ' => 3, 'Απρ' => 4, 'Μάι' => 5, 'Μαϊ' => 5, 'Μαι' => 5, 'Ιούν' => 6, 'Ιον' => 6, 'Ιούλ' => 7, 'Ιολ' => 7, 'Αύγ' => 8, 'Αυγ' => 8, 'Σεπ' => 9, 'Οκτ' => 10, 'Νοέ' => 11, 'Δεκ' => 12, // Russian 'Янв' => 1, 'января' => 1, 'Фев' => 2, 'февраля' => 2, 'Мар' => 3, 'марта' => 3, 'Апр' => 4, 'апреля' => 4, 'Май' => 5, 'мая' => 5, 'Июн' => 6, 'июня' => 6, 'Июл' => 7, 'июля' => 7, 'Авг' => 8, 'августа' => 8, 'Сен' => 9, 'сентября' => 9, 'Окт' => 10, 'октября' => 10, 'Ноя' => 11, 'ноября' => 11, 'Дек' => 12, 'декабря' => 12, ]; /** * List of timezones, abbreviation => offset from UTC * * @access protected * @var array */ public $timezone = [ 'ACDT' => 37800, 'ACIT' => 28800, 'ACST' => 34200, 'ACT' => -18000, 'ACWDT' => 35100, 'ACWST' => 31500, 'AEDT' => 39600, 'AEST' => 36000, 'AFT' => 16200, 'AKDT' => -28800, 'AKST' => -32400, 'AMDT' => 18000, 'AMT' => -14400, 'ANAST' => 46800, 'ANAT' => 43200, 'ART' => -10800, 'AZOST' => -3600, 'AZST' => 18000, 'AZT' => 14400, 'BIOT' => 21600, 'BIT' => -43200, 'BOT' => -14400, 'BRST' => -7200, 'BRT' => -10800, 'BST' => 3600, 'BTT' => 21600, 'CAST' => 18000, 'CAT' => 7200, 'CCT' => 23400, 'CDT' => -18000, 'CEDT' => 7200, 'CEST' => 7200, 'CET' => 3600, 'CGST' => -7200, 'CGT' => -10800, 'CHADT' => 49500, 'CHAST' => 45900, 'CIST' => -28800, 'CKT' => -36000, 'CLDT' => -10800, 'CLST' => -14400, 'COT' => -18000, 'CST' => -21600, 'CVT' => -3600, 'CXT' => 25200, 'DAVT' => 25200, 'DTAT' => 36000, 'EADT' => -18000, 'EAST' => -21600, 'EAT' => 10800, 'ECT' => -18000, 'EDT' => -14400, 'EEST' => 10800, 'EET' => 7200, 'EGT' => -3600, 'EKST' => 21600, 'EST' => -18000, 'FJT' => 43200, 'FKDT' => -10800, 'FKST' => -14400, 'FNT' => -7200, 'GALT' => -21600, 'GEDT' => 14400, 'GEST' => 10800, 'GFT' => -10800, 'GILT' => 43200, 'GIT' => -32400, 'GST' => 14400, 'GST' => -7200, 'GYT' => -14400, 'HAA' => -10800, 'HAC' => -18000, 'HADT' => -32400, 'HAE' => -14400, 'HAP' => -25200, 'HAR' => -21600, 'HAST' => -36000, 'HAT' => -9000, 'HAY' => -28800, 'HKST' => 28800, 'HMT' => 18000, 'HNA' => -14400, 'HNC' => -21600, 'HNE' => -18000, 'HNP' => -28800, 'HNR' => -25200, 'HNT' => -12600, 'HNY' => -32400, 'IRDT' => 16200, 'IRKST' => 32400, 'IRKT' => 28800, 'IRST' => 12600, 'JFDT' => -10800, 'JFST' => -14400, 'JST' => 32400, 'KGST' => 21600, 'KGT' => 18000, 'KOST' => 39600, 'KOVST' => 28800, 'KOVT' => 25200, 'KRAST' => 28800, 'KRAT' => 25200, 'KST' => 32400, 'LHDT' => 39600, 'LHST' => 37800, 'LINT' => 50400, 'LKT' => 21600, 'MAGST' => 43200, 'MAGT' => 39600, 'MAWT' => 21600, 'MDT' => -21600, 'MESZ' => 7200, 'MEZ' => 3600, 'MHT' => 43200, 'MIT' => -34200, 'MNST' => 32400, 'MSDT' => 14400, 'MSST' => 10800, 'MST' => -25200, 'MUT' => 14400, 'MVT' => 18000, 'MYT' => 28800, 'NCT' => 39600, 'NDT' => -9000, 'NFT' => 41400, 'NMIT' => 36000, 'NOVST' => 25200, 'NOVT' => 21600, 'NPT' => 20700, 'NRT' => 43200, 'NST' => -12600, 'NUT' => -39600, 'NZDT' => 46800, 'NZST' => 43200, 'OMSST' => 25200, 'OMST' => 21600, 'PDT' => -25200, 'PET' => -18000, 'PETST' => 46800, 'PETT' => 43200, 'PGT' => 36000, 'PHOT' => 46800, 'PHT' => 28800, 'PKT' => 18000, 'PMDT' => -7200, 'PMST' => -10800, 'PONT' => 39600, 'PST' => -28800, 'PWT' => 32400, 'PYST' => -10800, 'PYT' => -14400, 'RET' => 14400, 'ROTT' => -10800, 'SAMST' => 18000, 'SAMT' => 14400, 'SAST' => 7200, 'SBT' => 39600, 'SCDT' => 46800, 'SCST' => 43200, 'SCT' => 14400, 'SEST' => 3600, 'SGT' => 28800, 'SIT' => 28800, 'SRT' => -10800, 'SST' => -39600, 'SYST' => 10800, 'SYT' => 7200, 'TFT' => 18000, 'THAT' => -36000, 'TJT' => 18000, 'TKT' => -36000, 'TMT' => 18000, 'TOT' => 46800, 'TPT' => 32400, 'TRUT' => 36000, 'TVT' => 43200, 'TWT' => 28800, 'UYST' => -7200, 'UYT' => -10800, 'UZT' => 18000, 'VET' => -14400, 'VLAST' => 39600, 'VLAT' => 36000, 'VOST' => 21600, 'VUT' => 39600, 'WAST' => 7200, 'WAT' => 3600, 'WDT' => 32400, 'WEST' => 3600, 'WFT' => 43200, 'WIB' => 25200, 'WIT' => 32400, 'WITA' => 28800, 'WKST' => 18000, 'WST' => 28800, 'YAKST' => 36000, 'YAKT' => 32400, 'YAPT' => 36000, 'YEKST' => 21600, 'YEKT' => 18000, ]; /** * Cached PCRE for Date::$day * * @access protected * @var string */ public $day_pcre; /** * Cached PCRE for Date::$month * * @access protected * @var string */ public $month_pcre; /** * Array of user-added callback methods * * @access private * @var array */ public $built_in = []; /** * Array of user-added callback methods * * @access private * @var array */ public $user = []; /** * Create new Date object, and set self::day_pcre, * self::month_pcre, and self::built_in * * @access private */ public function __construct() { $this->day_pcre = '(' . implode('|', array_keys($this->day)) . ')'; $this->month_pcre = '(' . implode('|', array_keys($this->month)) . ')'; static $cache; if (!isset($cache[get_class($this)])) { $all_methods = get_class_methods($this); foreach ($all_methods as $method) { if (strtolower(substr($method, 0, 5)) === 'date_') { $cache[get_class($this)][] = $method; } } } foreach ($cache[get_class($this)] as $method) { $this->built_in[] = $method; } } /** * Get the object * * @access public */ public static function get() { static $object; if (!$object) { $object = new Date(); } return $object; } /** * Parse a date * * @final * @access public * @param string $date Date to parse * @return int Timestamp corresponding to date string, or false on failure */ public function parse($date) { foreach ($this->user as $method) { if (($returned = call_user_func($method, $date)) !== false) { return $returned; } } foreach ($this->built_in as $method) { if (($returned = call_user_func([$this, $method], $date)) !== false) { return $returned; } } return false; } /** * Add a callback method to parse a date * * @final * @access public * @param callable $callback */ public function add_callback($callback) { if (is_callable($callback)) { $this->user[] = $callback; } else { trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); } } /** * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as * well as allowing any of upper or lower case "T", horizontal tabs, or * spaces to be used as the time separator (including more than one)) * * @access protected * @return int Timestamp */ public function date_w3cdtf($date) { $pcre = <<<'PCRE' / ^ (?P[0-9]{4}) (?: -? (?P[0-9]{2}) (?: -? (?P[0-9]{2}) (?: [Tt\x09\x20]+ (?P[0-9]{2}) (?: :? (?P[0-9]{2}) (?: :? (?P[0-9]{2}) (?: . (?P[0-9]*) )? )? )? (?: (?PZ) | (?P[+\-]) (?P[0-9]{1,2}) :? (?P[0-9]{1,2}) ) )? )? )? $ /x PCRE; if (preg_match($pcre, $date, $match)) { // Fill in empty matches and convert to proper types. $year = (int) $match['year']; $month = isset($match['month']) ? (int) $match['month'] : 1; $day = isset($match['day']) ? (int) $match['day'] : 1; $hour = isset($match['hour']) ? (int) $match['hour'] : 0; $minute = isset($match['minute']) ? (int) $match['minute'] : 0; $second = isset($match['second']) ? (int) $match['second'] : 0; $second_fraction = isset($match['second_fraction']) ? ((int) $match['second_fraction']) / (10 ** strlen($match['second_fraction'])) : 0; $tz_sign = ($match['tz_sign'] ?? '') === '-' ? -1 : 1; $tz_hour = isset($match['tz_hour']) ? (int) $match['tz_hour'] : 0; $tz_minute = isset($match['tz_minute']) ? (int) $match['tz_minute'] : 0; // Numeric timezone $timezone = $tz_hour * 3600; $timezone += $tz_minute * 60; $timezone *= $tz_sign; // Convert the number of seconds to an integer, taking decimals into account $second = (int) round($second + $second_fraction); return gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone; } return false; } /** * Remove RFC822 comments * * @access protected * @param string $data Data to strip comments from * @return string Comment stripped string */ public function remove_rfc2822_comments($string) { $string = (string) $string; $position = 0; $length = strlen($string); $depth = 0; $output = ''; while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) { $output .= substr($string, $position, $pos - $position); $position = $pos + 1; if ($pos === 0 || $string[$pos - 1] !== '\\') { $depth++; while ($depth && $position < $length) { $position += strcspn($string, '()', $position); if ($string[$position - 1] === '\\') { $position++; continue; } elseif (isset($string[$position])) { switch ($string[$position]) { case '(': $depth++; break; case ')': $depth--; break; } $position++; } else { break; } } } else { $output .= '('; } } $output .= substr($string, $position); return $output; } /** * Parse RFC2822's date format * * @access protected * @return int Timestamp */ public function date_rfc2822($date) { static $pcre; if (!$pcre) { $wsp = '[\x09\x20]'; $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; $optional_fws = $fws . '?'; $day_name = $this->day_pcre; $month = $this->month_pcre; $day = '([0-9]{1,2})'; $hour = $minute = $second = '([0-9]{2})'; $year = '([0-9]{2,4})'; $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; $character_zone = '([A-Z]{1,5})'; $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i'; } if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) { /* Capturing subpatterns: 1: Day name 2: Day 3: Month 4: Year 5: Hour 6: Minute 7: Second 8: Timezone ± 9: Timezone hours 10: Timezone minutes 11: Alphabetic timezone */ // Find the month number $month = $this->month[strtolower($match[3])]; // Numeric timezone if ($match[8] !== '') { $timezone = $match[9] * 3600; $timezone += $match[10] * 60; if ($match[8] === '-') { $timezone = 0 - $timezone; } } // Character timezone elseif (isset($this->timezone[strtoupper($match[11])])) { $timezone = $this->timezone[strtoupper($match[11])]; } // Assume everything else to be -0000 else { $timezone = 0; } // Deal with 2/3 digit years if ($match[4] < 50) { $match[4] += 2000; } elseif ($match[4] < 1000) { $match[4] += 1900; } // Second is optional, if it is empty set it to zero if ($match[7] !== '') { $second = $match[7]; } else { $second = 0; } return gmmktime(intval($match[5]), intval($match[6]), intval($second), intval($month), intval($match[2]), intval($match[4])) - $timezone; } return false; } /** * Parse RFC850's date format * * @access protected * @return int Timestamp */ public function date_rfc850($date) { static $pcre; if (!$pcre) { $space = '[\x09\x20]+'; $day_name = $this->day_pcre; $month = $this->month_pcre; $day = '([0-9]{1,2})'; $year = $hour = $minute = $second = '([0-9]{2})'; $zone = '([A-Z]{1,5})'; $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; } if (preg_match($pcre, $date, $match)) { /* Capturing subpatterns: 1: Day name 2: Day 3: Month 4: Year 5: Hour 6: Minute 7: Second 8: Timezone */ // Month $month = $this->month[strtolower($match[3])]; // Character timezone if (isset($this->timezone[strtoupper($match[8])])) { $timezone = $this->timezone[strtoupper($match[8])]; } // Assume everything else to be -0000 else { $timezone = 0; } // Deal with 2 digit year if ($match[4] < 50) { $match[4] += 2000; } else { $match[4] += 1900; } return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; } return false; } /** * Parse C99's asctime()'s date format * * @access protected * @return int Timestamp */ public function date_asctime($date) { static $pcre; if (!$pcre) { $space = '[\x09\x20]+'; $wday_name = $this->day_pcre; $mon_name = $this->month_pcre; $day = '([0-9]{1,2})'; $hour = $sec = $min = '([0-9]{2})'; $year = '([0-9]{4})'; $terminator = '\x0A?\x00?'; $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; } if (preg_match($pcre, $date, $match)) { /* Capturing subpatterns: 1: Day name 2: Month 3: Day 4: Hour 5: Minute 6: Second 7: Year */ $month = $this->month[strtolower($match[2])]; return gmmktime((int) $match[4], (int) $match[5], (int) $match[6], $month, (int) $match[3], (int) $match[7]); } return false; } /** * Parse dates using strtotime() * * @access protected * @return int Timestamp */ public function date_strtotime($date) { $strtotime = strtotime($date); if ($strtotime === -1 || $strtotime === false) { return false; } return $strtotime; } } class_alias('SimplePie\Parse\Date', 'SimplePie_Parse_Date'); Credit.php000064400000007666150211552310006501 0ustar00` as defined in Media RSS * * Used by {@see \SimplePie\Enclosure::get_credit()} and {@see \SimplePie\Enclosure::get_credits()} * * This class can be overloaded with {@see \SimplePie\SimplePie::set_credit_class()} * * @package SimplePie * @subpackage API */ class Credit { /** * Credited role * * @var string * @see get_role() */ public $role; /** * Organizational scheme * * @var string * @see get_scheme() */ public $scheme; /** * Credited name * * @var string * @see get_name() */ public $name; /** * Constructor, used to input the data * * For documentation on all the parameters, see the corresponding * properties and their accessors */ public function __construct($role = null, $scheme = null, $name = null) { $this->role = $role; $this->scheme = $scheme; $this->name = $name; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the role of the person receiving credit * * @return string|null */ public function get_role() { if ($this->role !== null) { return $this->role; } return null; } /** * Get the organizational scheme * * @return string|null */ public function get_scheme() { if ($this->scheme !== null) { return $this->scheme; } return null; } /** * Get the credited person/entity's name * * @return string|null */ public function get_name() { if ($this->name !== null) { return $this->name; } return null; } } class_alias('SimplePie\Credit', 'SimplePie_Credit'); Caption.php000064400000011517150211552310006652 0ustar00` captions as defined in Media RSS. * * Used by {@see \SimplePie\Enclosure::get_caption()} and {@see \SimplePie\Enclosure::get_captions()} * * This class can be overloaded with {@see \SimplePie\SimplePie::set_caption_class()} * * @package SimplePie * @subpackage API */ class Caption { /** * Content type * * @var string * @see get_type() */ public $type; /** * Language * * @var string * @see get_language() */ public $lang; /** * Start time * * @var string * @see get_starttime() */ public $startTime; /** * End time * * @var string * @see get_endtime() */ public $endTime; /** * Caption text * * @var string * @see get_text() */ public $text; /** * Constructor, used to input the data * * For documentation on all the parameters, see the corresponding * properties and their accessors */ public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null) { $this->type = $type; $this->lang = $lang; $this->startTime = $startTime; $this->endTime = $endTime; $this->text = $text; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the end time * * @return string|null Time in the format 'hh:mm:ss.SSS' */ public function get_endtime() { if ($this->endTime !== null) { return $this->endTime; } return null; } /** * Get the language * * @link http://tools.ietf.org/html/rfc3066 * @return string|null Language code as per RFC 3066 */ public function get_language() { if ($this->lang !== null) { return $this->lang; } return null; } /** * Get the start time * * @return string|null Time in the format 'hh:mm:ss.SSS' */ public function get_starttime() { if ($this->startTime !== null) { return $this->startTime; } return null; } /** * Get the text of the caption * * @return string|null */ public function get_text() { if ($this->text !== null) { return $this->text; } return null; } /** * Get the content type (not MIME type) * * @return string|null Either 'text' or 'html' */ public function get_type() { if ($this->type !== null) { return $this->type; } return null; } } class_alias('SimplePie\Caption', 'SimplePie_Caption'); Gzdecode.php000064400000023754150211552310007007 0ustar00compressed_data = $data; $this->compressed_size = strlen($data); } /** * Decode the GZIP stream * * @return bool Successfulness */ public function parse() { if ($this->compressed_size >= $this->min_compressed_size) { $len = 0; // Check ID1, ID2, and CM if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") { return false; } // Get the FLG (FLaGs) $this->flags = ord($this->compressed_data[3]); // FLG bits above (1 << 4) are reserved if ($this->flags > 0x1F) { return false; } // Advance the pointer after the above $this->position += 4; // MTIME $mtime = substr($this->compressed_data, $this->position, 4); // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness if (current(unpack('S', "\x00\x01")) === 1) { $mtime = strrev($mtime); } $this->MTIME = current(unpack('l', $mtime)); $this->position += 4; // Get the XFL (eXtra FLags) $this->XFL = ord($this->compressed_data[$this->position++]); // Get the OS (Operating System) $this->OS = ord($this->compressed_data[$this->position++]); // Parse the FEXTRA if ($this->flags & 4) { // Read subfield IDs $this->SI1 = $this->compressed_data[$this->position++]; $this->SI2 = $this->compressed_data[$this->position++]; // SI2 set to zero is reserved for future use if ($this->SI2 === "\x00") { return false; } // Get the length of the extra field $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); $this->position += 2; // Check the length of the string is still valid $this->min_compressed_size += $len + 4; if ($this->compressed_size >= $this->min_compressed_size) { // Set the extra field to the given data $this->extra_field = substr($this->compressed_data, $this->position, $len); $this->position += $len; } else { return false; } } // Parse the FNAME if ($this->flags & 8) { // Get the length of the filename $len = strcspn($this->compressed_data, "\x00", $this->position); // Check the length of the string is still valid $this->min_compressed_size += $len + 1; if ($this->compressed_size >= $this->min_compressed_size) { // Set the original filename to the given string $this->filename = substr($this->compressed_data, $this->position, $len); $this->position += $len + 1; } else { return false; } } // Parse the FCOMMENT if ($this->flags & 16) { // Get the length of the comment $len = strcspn($this->compressed_data, "\x00", $this->position); // Check the length of the string is still valid $this->min_compressed_size += $len + 1; if ($this->compressed_size >= $this->min_compressed_size) { // Set the original comment to the given string $this->comment = substr($this->compressed_data, $this->position, $len); $this->position += $len + 1; } else { return false; } } // Parse the FHCRC if ($this->flags & 2) { // Check the length of the string is still valid $this->min_compressed_size += $len + 2; if ($this->compressed_size >= $this->min_compressed_size) { // Read the CRC $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); // Check the CRC matches if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) { $this->position += 2; } else { return false; } } else { return false; } } // Decompress the actual data if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) { return false; } $this->position = $this->compressed_size - 8; // Check CRC of data $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); $this->position += 4; /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) { return false; }*/ // Check ISIZE of data $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); $this->position += 4; if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) { return false; } // Wow, against all odds, we've actually got a valid gzip string return true; } return false; } } class_alias('SimplePie\Gzdecode', 'SimplePie_gzdecode'); Content/Type/Sniffer.php000064400000022112150211552310011175 0ustar00file = $file; } /** * Get the Content-Type of the specified file * * @return string Actual Content-Type */ public function get_type() { if (isset($this->file->headers['content-type'])) { if (!isset($this->file->headers['content-encoding']) && ($this->file->headers['content-type'] === 'text/plain' || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1' || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8')) { return $this->text_or_binary(); } if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) { $official = substr($this->file->headers['content-type'], 0, $pos); } else { $official = $this->file->headers['content-type']; } $official = trim(strtolower($official)); if ($official === 'unknown/unknown' || $official === 'application/unknown') { return $this->unknown(); } elseif (substr($official, -4) === '+xml' || $official === 'text/xml' || $official === 'application/xml') { return $official; } elseif (substr($official, 0, 6) === 'image/') { if ($return = $this->image()) { return $return; } return $official; } elseif ($official === 'text/html') { return $this->feed_or_html(); } return $official; } return $this->unknown(); } /** * Sniff text or binary * * @return string Actual Content-Type */ public function text_or_binary() { if (substr($this->file->body, 0, 2) === "\xFE\xFF" || substr($this->file->body, 0, 2) === "\xFF\xFE" || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") { return 'text/plain'; } elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) { return 'application/octet-stream'; } return 'text/plain'; } /** * Sniff unknown * * @return string Actual Content-Type */ public function unknown() { $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); if (strtolower(substr($this->file->body, $ws, 14)) === 'file->body, $ws, 5)) === 'file->body, $ws, 7)) === 'file->body, 0, 5) === '%PDF-') { return 'application/pdf'; } elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') { return 'application/postscript'; } elseif (substr($this->file->body, 0, 6) === 'GIF87a' || substr($this->file->body, 0, 6) === 'GIF89a') { return 'image/gif'; } elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") { return 'image/png'; } elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") { return 'image/jpeg'; } elseif (substr($this->file->body, 0, 2) === "\x42\x4D") { return 'image/bmp'; } elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") { return 'image/vnd.microsoft.icon'; } return $this->text_or_binary(); } /** * Sniff images * * @return string Actual Content-Type */ public function image() { if (substr($this->file->body, 0, 6) === 'GIF87a' || substr($this->file->body, 0, 6) === 'GIF89a') { return 'image/gif'; } elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") { return 'image/png'; } elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") { return 'image/jpeg'; } elseif (substr($this->file->body, 0, 2) === "\x42\x4D") { return 'image/bmp'; } elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") { return 'image/vnd.microsoft.icon'; } return false; } /** * Sniff HTML * * @return string Actual Content-Type */ public function feed_or_html() { $len = strlen($this->file->body); $pos = strspn($this->file->body, "\x09\x0A\x0D\x20\xEF\xBB\xBF"); while ($pos < $len) { switch ($this->file->body[$pos]) { case "\x09": case "\x0A": case "\x0D": case "\x20": $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); continue 2; case '<': $pos++; break; default: return 'text/html'; } if (substr($this->file->body, $pos, 3) === '!--') { $pos += 3; if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) { $pos += 3; } else { return 'text/html'; } } elseif (substr($this->file->body, $pos, 1) === '!') { if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) { $pos++; } else { return 'text/html'; } } elseif (substr($this->file->body, $pos, 1) === '?') { if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) { $pos += 2; } else { return 'text/html'; } } elseif (substr($this->file->body, $pos, 3) === 'rss' || substr($this->file->body, $pos, 7) === 'rdf:RDF') { return 'application/rss+xml'; } elseif (substr($this->file->body, $pos, 4) === 'feed') { return 'application/atom+xml'; } else { return 'text/html'; } } return 'text/html'; } } class_alias('SimplePie\Content\Type\Sniffer', 'SimplePie_Content_Type_Sniffer'); Sanitize.php000064400000061065150211552310007046 0ustar00 ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']]; public $strip_comments = false; public $output_encoding = 'UTF-8'; public $enable_cache = true; public $cache_location = './cache'; public $cache_name_function = 'md5'; /** * @var NameFilter */ private $cache_namefilter; public $timeout = 10; public $useragent = ''; public $force_fsockopen = false; public $replace_url_attributes = null; public $registry; /** * @var DataCache|null */ private $cache = null; /** * @var int Cache duration (in seconds) */ private $cache_duration = 3600; /** * List of domains for which to force HTTPS. * @see \SimplePie\Sanitize::set_https_domains() * Array is a tree split at DNS levels. Example: * array('biz' => true, 'com' => array('example' => true), 'net' => array('example' => array('www' => true))) */ public $https_domains = []; public function __construct() { // Set defaults $this->set_url_replacements(null); } public function remove_div($enable = true) { $this->remove_div = (bool) $enable; } public function set_image_handler($page = false) { if ($page) { $this->image_handler = (string) $page; } else { $this->image_handler = false; } } public function set_registry(\SimplePie\Registry $registry)/* : void */ { $this->registry = $registry; } public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie\Cache', ?DataCache $cache = null) { if (isset($enable_cache)) { $this->enable_cache = (bool) $enable_cache; } if ($cache_location) { $this->cache_location = (string) $cache_location; } if (!is_string($cache_name_function) && !is_object($cache_name_function) && !$cache_name_function instanceof NameFilter) { throw new InvalidArgumentException(sprintf( '%s(): Argument #3 ($cache_name_function) must be of type %s', __METHOD__, NameFilter::class ), 1); } // BC: $cache_name_function could be a callable as string if (is_string($cache_name_function)) { // trigger_error(sprintf('Providing $cache_name_function as string in "%s()" is deprecated since SimplePie 1.8.0, provide as "%s" instead.', __METHOD__, NameFilter::class), \E_USER_DEPRECATED); $this->cache_name_function = (string) $cache_name_function; $cache_name_function = new CallableNameFilter($cache_name_function); } $this->cache_namefilter = $cache_name_function; if ($cache !== null) { $this->cache = $cache; } } public function pass_file_data($file_class = 'SimplePie\File', $timeout = 10, $useragent = '', $force_fsockopen = false) { if ($timeout) { $this->timeout = (string) $timeout; } if ($useragent) { $this->useragent = (string) $useragent; } if ($force_fsockopen) { $this->force_fsockopen = (string) $force_fsockopen; } } public function strip_htmltags($tags = ['base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style']) { if ($tags) { if (is_array($tags)) { $this->strip_htmltags = $tags; } else { $this->strip_htmltags = explode(',', $tags); } } else { $this->strip_htmltags = false; } } public function encode_instead_of_strip($encode = false) { $this->encode_instead_of_strip = (bool) $encode; } public function rename_attributes($attribs = []) { if ($attribs) { if (is_array($attribs)) { $this->rename_attributes = $attribs; } else { $this->rename_attributes = explode(',', $attribs); } } else { $this->rename_attributes = false; } } public function strip_attributes($attribs = ['bgsound', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc']) { if ($attribs) { if (is_array($attribs)) { $this->strip_attributes = $attribs; } else { $this->strip_attributes = explode(',', $attribs); } } else { $this->strip_attributes = false; } } public function add_attributes($attribs = ['audio' => ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']]) { if ($attribs) { if (is_array($attribs)) { $this->add_attributes = $attribs; } else { $this->add_attributes = explode(',', $attribs); } } else { $this->add_attributes = false; } } public function strip_comments($strip = false) { $this->strip_comments = (bool) $strip; } public function set_output_encoding($encoding = 'UTF-8') { $this->output_encoding = (string) $encoding; } /** * Set element/attribute key/value pairs of HTML attributes * containing URLs that need to be resolved relative to the feed * * Defaults to |a|@href, |area|@href, |audio|@src, |blockquote|@cite, * |del|@cite, |form|@action, |img|@longdesc, |img|@src, |input|@src, * |ins|@cite, |q|@cite, |source|@src, |video|@src * * @since 1.0 * @param array|null $element_attribute Element/attribute key/value pairs, null for default */ public function set_url_replacements($element_attribute = null) { if ($element_attribute === null) { $element_attribute = [ 'a' => 'href', 'area' => 'href', 'audio' => 'src', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => [ 'longdesc', 'src' ], 'input' => 'src', 'ins' => 'cite', 'q' => 'cite', 'source' => 'src', 'video' => [ 'poster', 'src' ] ]; } $this->replace_url_attributes = (array) $element_attribute; } /** * Set the list of domains for which to force HTTPS. * @see \SimplePie\Misc::https_url() * Example array('biz', 'example.com', 'example.org', 'www.example.net'); */ public function set_https_domains($domains) { $this->https_domains = []; foreach ($domains as $domain) { $domain = trim($domain, ". \t\n\r\0\x0B"); $segments = array_reverse(explode('.', $domain)); $node = &$this->https_domains; foreach ($segments as $segment) {//Build a tree if ($node === true) { break; } if (!isset($node[$segment])) { $node[$segment] = []; } $node = &$node[$segment]; } $node = true; } } /** * Check if the domain is in the list of forced HTTPS. */ protected function is_https_domain($domain) { $domain = trim($domain, '. '); $segments = array_reverse(explode('.', $domain)); $node = &$this->https_domains; foreach ($segments as $segment) {//Explore the tree if (isset($node[$segment])) { $node = &$node[$segment]; } else { break; } } return $node === true; } /** * Force HTTPS for selected Web sites. */ public function https_url($url) { return (strtolower(substr($url, 0, 7)) === 'http://') && $this->is_https_domain(parse_url($url, PHP_URL_HOST)) ? substr_replace($url, 's', 4, 0) : //Add the 's' to HTTPS $url; } public function sanitize($data, $type, $base = '') { $data = trim($data); if ($data !== '' || $type & \SimplePie\SimplePie::CONSTRUCT_IRI) { if ($type & \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML) { if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . \SimplePie\SimplePie::PCRE_HTML_ATTRIBUTE . '>)/', $data)) { $type |= \SimplePie\SimplePie::CONSTRUCT_HTML; } else { $type |= \SimplePie\SimplePie::CONSTRUCT_TEXT; } } if ($type & \SimplePie\SimplePie::CONSTRUCT_BASE64) { $data = base64_decode($data); } if ($type & (\SimplePie\SimplePie::CONSTRUCT_HTML | \SimplePie\SimplePie::CONSTRUCT_XHTML)) { if (!class_exists('DOMDocument')) { throw new \SimplePie\Exception('DOMDocument not found, unable to use sanitizer'); } $document = new \DOMDocument(); $document->encoding = 'UTF-8'; $data = $this->preprocess($data, $type); set_error_handler(['SimplePie\Misc', 'silence_errors']); $document->loadHTML($data); restore_error_handler(); $xpath = new \DOMXPath($document); // Strip comments if ($this->strip_comments) { $comments = $xpath->query('//comment()'); foreach ($comments as $comment) { $comment->parentNode->removeChild($comment); } } // Strip out HTML tags and attributes that might cause various security problems. // Based on recommendations by Mark Pilgrim at: // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely if ($this->strip_htmltags) { foreach ($this->strip_htmltags as $tag) { $this->strip_tag($tag, $document, $xpath, $type); } } if ($this->rename_attributes) { foreach ($this->rename_attributes as $attrib) { $this->rename_attr($attrib, $xpath); } } if ($this->strip_attributes) { foreach ($this->strip_attributes as $attrib) { $this->strip_attr($attrib, $xpath); } } if ($this->add_attributes) { foreach ($this->add_attributes as $tag => $valuePairs) { $this->add_attr($tag, $valuePairs, $document); } } // Replace relative URLs $this->base = $base; foreach ($this->replace_url_attributes as $element => $attributes) { $this->replace_urls($document, $element, $attributes); } // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags. if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) { $images = $document->getElementsByTagName('img'); foreach ($images as $img) { if ($img->hasAttribute('src')) { $image_url = $this->cache_namefilter->filter($img->getAttribute('src')); $cache = $this->get_cache($image_url); if ($cache->get_data($image_url, false)) { $img->setAttribute('src', $this->image_handler . $image_url); } else { $file = $this->registry->create(File::class, [$img->getAttribute('src'), $this->timeout, 5, ['X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']], $this->useragent, $this->force_fsockopen]); $headers = $file->headers; if ($file->success && ($file->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) { if ($cache->set_data($image_url, ['headers' => $file->headers, 'body' => $file->body], $this->cache_duration)) { $img->setAttribute('src', $this->image_handler . $image_url); } else { trigger_error("$this->cache_location is not writable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); } } } } } } // Get content node $div = $document->getElementsByTagName('body')->item(0)->firstChild; // Finally, convert to a HTML string $data = trim($document->saveHTML($div)); if ($this->remove_div) { $data = preg_replace('/^/', '', $data); $data = preg_replace('/<\/div>$/', '', $data); } else { $data = preg_replace('/^/', '
', $data); } $data = str_replace('', '', $data); } if ($type & \SimplePie\SimplePie::CONSTRUCT_IRI) { $absolute = $this->registry->call(Misc::class, 'absolutize_url', [$data, $base]); if ($absolute !== false) { $data = $absolute; } } if ($type & (\SimplePie\SimplePie::CONSTRUCT_TEXT | \SimplePie\SimplePie::CONSTRUCT_IRI)) { $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); } if ($this->output_encoding !== 'UTF-8') { $data = $this->registry->call(Misc::class, 'change_encoding', [$data, 'UTF-8', $this->output_encoding]); } } return $data; } protected function preprocess($html, $type) { $ret = ''; $html = preg_replace('%]*?'.'>%is', '', $html); if ($type & ~\SimplePie\SimplePie::CONSTRUCT_XHTML) { // Atom XHTML constructs are wrapped with a div by default // Note: No protection if $html contains a stray
! $html = '
' . $html . '
'; $ret .= ''; $content_type = 'text/html'; } else { $ret .= ''; $content_type = 'application/xhtml+xml'; } $ret .= ''; $ret .= ''; $ret .= '' . $html . ''; return $ret; } public function replace_urls($document, $tag, $attributes) { if (!is_array($attributes)) { $attributes = [$attributes]; } if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) { $elements = $document->getElementsByTagName($tag); foreach ($elements as $element) { foreach ($attributes as $attribute) { if ($element->hasAttribute($attribute)) { $value = $this->registry->call(Misc::class, 'absolutize_url', [$element->getAttribute($attribute), $this->base]); if ($value !== false) { $value = $this->https_url($value); $element->setAttribute($attribute, $value); } } } } } } public function do_strip_htmltags($match) { if ($this->encode_instead_of_strip) { if (isset($match[4]) && !in_array(strtolower($match[1]), ['script', 'style'])) { $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8'); $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8'); return "<$match[1]$match[2]>$match[3]</$match[1]>"; } else { return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8'); } } elseif (isset($match[4]) && !in_array(strtolower($match[1]), ['script', 'style'])) { return $match[4]; } else { return ''; } } protected function strip_tag($tag, $document, $xpath, $type) { $elements = $xpath->query('body//' . $tag); if ($this->encode_instead_of_strip) { foreach ($elements as $element) { $fragment = $document->createDocumentFragment(); // For elements which aren't script or style, include the tag itself if (!in_array($tag, ['script', 'style'])) { $text = '<' . $tag; if ($element->hasAttributes()) { $attrs = []; foreach ($element->attributes as $name => $attr) { $value = $attr->value; // In XHTML, empty values should never exist, so we repeat the value if (empty($value) && ($type & \SimplePie\SimplePie::CONSTRUCT_XHTML)) { $value = $name; } // For HTML, empty is fine elseif (empty($value) && ($type & \SimplePie\SimplePie::CONSTRUCT_HTML)) { $attrs[] = $name; continue; } // Standard attribute text $attrs[] = $name . '="' . $attr->value . '"'; } $text .= ' ' . implode(' ', $attrs); } $text .= '>'; $fragment->appendChild(new \DOMText($text)); } $number = $element->childNodes->length; for ($i = $number; $i > 0; $i--) { $child = $element->childNodes->item(0); $fragment->appendChild($child); } if (!in_array($tag, ['script', 'style'])) { $fragment->appendChild(new \DOMText('')); } $element->parentNode->replaceChild($fragment, $element); } return; } elseif (in_array($tag, ['script', 'style'])) { foreach ($elements as $element) { $element->parentNode->removeChild($element); } return; } else { foreach ($elements as $element) { $fragment = $document->createDocumentFragment(); $number = $element->childNodes->length; for ($i = $number; $i > 0; $i--) { $child = $element->childNodes->item(0); $fragment->appendChild($child); } $element->parentNode->replaceChild($fragment, $element); } } } protected function strip_attr($attrib, $xpath) { $elements = $xpath->query('//*[@' . $attrib . ']'); foreach ($elements as $element) { $element->removeAttribute($attrib); } } protected function rename_attr($attrib, $xpath) { $elements = $xpath->query('//*[@' . $attrib . ']'); foreach ($elements as $element) { $element->setAttribute('data-sanitized-' . $attrib, $element->getAttribute($attrib)); $element->removeAttribute($attrib); } } protected function add_attr($tag, $valuePairs, $document) { $elements = $document->getElementsByTagName($tag); foreach ($elements as $element) { foreach ($valuePairs as $attrib => $value) { $element->setAttribute($attrib, $value); } } } /** * Get a DataCache * * @param string $image_url Only needed for BC, can be removed in SimplePie 2.0.0 * * @return DataCache */ private function get_cache($image_url = '') { if ($this->cache === null) { // @trigger_error(sprintf('Not providing as PSR-16 cache implementation is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache()".'), \E_USER_DEPRECATED); $cache = $this->registry->call(Cache::class, 'get_handler', [ $this->cache_location, $image_url, Base::TYPE_IMAGE ]); return new BaseDataCache($cache); } return $this->cache; } } class_alias('SimplePie\Sanitize', 'SimplePie_Sanitize'); Category.php000064400000010416150211552310007027 0ustar00 * subject for * * @var string|null * @see get_type() */ public $type; /** * Constructor, used to input the data * * @param string|null $term * @param string|null $scheme * @param string|null $label * @param string|null $type */ public function __construct($term = null, $scheme = null, $label = null, $type = null) { $this->term = $term; $this->scheme = $scheme; $this->label = $label; $this->type = $type; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the category identifier * * @return string|null */ public function get_term() { return $this->term; } /** * Get the categorization scheme identifier * * @return string|null */ public function get_scheme() { return $this->scheme; } /** * Get the human readable label * * @param bool $strict * @return string|null */ public function get_label($strict = false) { if ($this->label === null && $strict !== true) { return $this->get_term(); } return $this->label; } /** * Get the category type * * @return string|null */ public function get_type() { return $this->type; } } class_alias('SimplePie\Category', 'SimplePie_Category'); Copyright.php000064400000007031150211552310007221 0ustar00` copyright tags as defined in Media RSS * * Used by {@see \SimplePie\Enclosure::get_copyright()} * * This class can be overloaded with {@see \SimplePie\SimplePie::set_copyright_class()} * * @package SimplePie * @subpackage API */ class Copyright { /** * Copyright URL * * @var string * @see get_url() */ public $url; /** * Attribution * * @var string * @see get_attribution() */ public $label; /** * Constructor, used to input the data * * For documentation on all the parameters, see the corresponding * properties and their accessors */ public function __construct($url = null, $label = null) { $this->url = $url; $this->label = $label; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the copyright URL * * @return string|null URL to copyright information */ public function get_url() { if ($this->url !== null) { return $this->url; } return null; } /** * Get the attribution text * * @return string|null */ public function get_attribution() { if ($this->label !== null) { return $this->label; } return null; } } class_alias('SimplePie\Copyright', 'SimplePie_Copyright'); Enclosure.php000064400000100400150211552310007202 0ustar00bitrate = $bitrate; $this->captions = $captions; $this->categories = $categories; $this->channels = $channels; $this->copyright = $copyright; $this->credits = $credits; $this->description = $description; $this->duration = $duration; $this->expression = $expression; $this->framerate = $framerate; $this->hashes = $hashes; $this->height = $height; $this->keywords = $keywords; $this->lang = $lang; $this->length = $length; $this->link = $link; $this->medium = $medium; $this->player = $player; $this->ratings = $ratings; $this->restrictions = $restrictions; $this->samplingrate = $samplingrate; $this->thumbnails = $thumbnails; $this->title = $title; $this->type = $type; $this->width = $width; if (class_exists('idna_convert')) { $idn = new \idna_convert(); $parsed = \SimplePie\Misc::parse_url($link); $this->link = \SimplePie\Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); } $this->handler = $this->get_handler(); // Needs to load last } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Get the bitrate * * @return string|null */ public function get_bitrate() { if ($this->bitrate !== null) { return $this->bitrate; } return null; } /** * Get a single caption * * @param int $key * @return \SimplePie\Caption|null */ public function get_caption($key = 0) { $captions = $this->get_captions(); if (isset($captions[$key])) { return $captions[$key]; } return null; } /** * Get all captions * * @return array|null Array of {@see \SimplePie\Caption} objects */ public function get_captions() { if ($this->captions !== null) { return $this->captions; } return null; } /** * Get a single category * * @param int $key * @return \SimplePie\Category|null */ public function get_category($key = 0) { $categories = $this->get_categories(); if (isset($categories[$key])) { return $categories[$key]; } return null; } /** * Get all categories * * @return array|null Array of {@see \SimplePie\Category} objects */ public function get_categories() { if ($this->categories !== null) { return $this->categories; } return null; } /** * Get the number of audio channels * * @return int|null */ public function get_channels() { if ($this->channels !== null) { return $this->channels; } return null; } /** * Get the copyright information * * @return \SimplePie\Copyright|null */ public function get_copyright() { if ($this->copyright !== null) { return $this->copyright; } return null; } /** * Get a single credit * * @param int $key * @return \SimplePie\Credit|null */ public function get_credit($key = 0) { $credits = $this->get_credits(); if (isset($credits[$key])) { return $credits[$key]; } return null; } /** * Get all credits * * @return array|null Array of {@see \SimplePie\Credit} objects */ public function get_credits() { if ($this->credits !== null) { return $this->credits; } return null; } /** * Get the description of the enclosure * * @return string|null */ public function get_description() { if ($this->description !== null) { return $this->description; } return null; } /** * Get the duration of the enclosure * * @param bool $convert Convert seconds into hh:mm:ss * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found) */ public function get_duration($convert = false) { if ($this->duration !== null) { if ($convert) { $time = \SimplePie\Misc::time_hms($this->duration); return $time; } return $this->duration; } return null; } /** * Get the expression * * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full' */ public function get_expression() { if ($this->expression !== null) { return $this->expression; } return 'full'; } /** * Get the file extension * * @return string|null */ public function get_extension() { if ($this->link !== null) { $url = \SimplePie\Misc::parse_url($this->link); if ($url['path'] !== '') { return pathinfo($url['path'], PATHINFO_EXTENSION); } } return null; } /** * Get the framerate (in frames-per-second) * * @return string|null */ public function get_framerate() { if ($this->framerate !== null) { return $this->framerate; } return null; } /** * Get the preferred handler * * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3' */ public function get_handler() { return $this->get_real_type(true); } /** * Get a single hash * * @link http://www.rssboard.org/media-rss#media-hash * @param int $key * @return string|null Hash as per `media:hash`, prefixed with "$algo:" */ public function get_hash($key = 0) { $hashes = $this->get_hashes(); if (isset($hashes[$key])) { return $hashes[$key]; } return null; } /** * Get all credits * * @return array|null Array of strings, see {@see get_hash()} */ public function get_hashes() { if ($this->hashes !== null) { return $this->hashes; } return null; } /** * Get the height * * @return string|null */ public function get_height() { if ($this->height !== null) { return $this->height; } return null; } /** * Get the language * * @link http://tools.ietf.org/html/rfc3066 * @return string|null Language code as per RFC 3066 */ public function get_language() { if ($this->lang !== null) { return $this->lang; } return null; } /** * Get a single keyword * * @param int $key * @return string|null */ public function get_keyword($key = 0) { $keywords = $this->get_keywords(); if (isset($keywords[$key])) { return $keywords[$key]; } return null; } /** * Get all keywords * * @return array|null Array of strings */ public function get_keywords() { if ($this->keywords !== null) { return $this->keywords; } return null; } /** * Get length * * @return float Length in bytes */ public function get_length() { if ($this->length !== null) { return $this->length; } return null; } /** * Get the URL * * @return string|null */ public function get_link() { if ($this->link !== null) { return $this->link; } return null; } /** * Get the medium * * @link http://www.rssboard.org/media-rss#media-content * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable' */ public function get_medium() { if ($this->medium !== null) { return $this->medium; } return null; } /** * Get the player URL * * Typically the same as {@see get_permalink()} * @return string|null Player URL */ public function get_player() { if ($this->player !== null) { return $this->player; } return null; } /** * Get a single rating * * @param int $key * @return \SimplePie\Rating|null */ public function get_rating($key = 0) { $ratings = $this->get_ratings(); if (isset($ratings[$key])) { return $ratings[$key]; } return null; } /** * Get all ratings * * @return array|null Array of {@see \SimplePie\Rating} objects */ public function get_ratings() { if ($this->ratings !== null) { return $this->ratings; } return null; } /** * Get a single restriction * * @param int $key * @return \SimplePie\Restriction|null */ public function get_restriction($key = 0) { $restrictions = $this->get_restrictions(); if (isset($restrictions[$key])) { return $restrictions[$key]; } return null; } /** * Get all restrictions * * @return array|null Array of {@see \SimplePie\Restriction} objects */ public function get_restrictions() { if ($this->restrictions !== null) { return $this->restrictions; } return null; } /** * Get the sampling rate (in kHz) * * @return string|null */ public function get_sampling_rate() { if ($this->samplingrate !== null) { return $this->samplingrate; } return null; } /** * Get the file size (in MiB) * * @return float|null File size in mebibytes (1048 bytes) */ public function get_size() { $length = $this->get_length(); if ($length !== null) { return round($length / 1048576, 2); } return null; } /** * Get a single thumbnail * * @param int $key * @return string|null Thumbnail URL */ public function get_thumbnail($key = 0) { $thumbnails = $this->get_thumbnails(); if (isset($thumbnails[$key])) { return $thumbnails[$key]; } return null; } /** * Get all thumbnails * * @return array|null Array of thumbnail URLs */ public function get_thumbnails() { if ($this->thumbnails !== null) { return $this->thumbnails; } return null; } /** * Get the title * * @return string|null */ public function get_title() { if ($this->title !== null) { return $this->title; } return null; } /** * Get mimetype of the enclosure * * @see get_real_type() * @return string|null MIME type */ public function get_type() { if ($this->type !== null) { return $this->type; } return null; } /** * Get the width * * @return string|null */ public function get_width() { if ($this->width !== null) { return $this->width; } return null; } /** * Embed the enclosure using `` * * @deprecated Use the second parameter to {@see embed} instead * * @param array|string $options See first parameter to {@see embed} * @return string HTML string to output */ public function native_embed($options = '') { return $this->embed($options, true); } /** * Embed the enclosure using Javascript * * `$options` is an array or comma-separated key:value string, with the * following properties: * * - `alt` (string): Alternate content for when an end-user does not have * the appropriate handler installed or when a file type is * unsupported. Can be any text or HTML. Defaults to blank. * - `altclass` (string): If a file type is unsupported, the end-user will * see the alt text (above) linked directly to the content. That link * will have this value as its class name. Defaults to blank. * - `audio` (string): This is an image that should be used as a * placeholder for audio files before they're loaded (QuickTime-only). * Can be any relative or absolute URL. Defaults to blank. * - `bgcolor` (string): The background color for the media, if not * already transparent. Defaults to `#ffffff`. * - `height` (integer): The height of the embedded media. Accepts any * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`, * and it is recommended that you use this default. * - `loop` (boolean): Do you want the media to loop when it's done? * Defaults to `false`. * - `mediaplayer` (string): The location of the included * `mediaplayer.swf` file. This allows for the playback of Flash Video * (`.flv`) files, and is the default handler for non-Odeo MP3's. * Defaults to blank. * - `video` (string): This is an image that should be used as a * placeholder for video files before they're loaded (QuickTime-only). * Can be any relative or absolute URL. Defaults to blank. * - `width` (integer): The width of the embedded media. Accepts any * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`, * and it is recommended that you use this default. * - `widescreen` (boolean): Is the enclosure widescreen or standard? * This applies only to video enclosures, and will automatically resize * the content appropriately. Defaults to `false`, implying 4:3 mode. * * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto` * will default to 480x360 video resolution. Widescreen (16:9) mode with * `width` and `height` set to `auto` will default to 480x270 video resolution. * * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'. * @param array|string $options Comma-separated key:value list, or array * @param bool $native Use `` * @return string HTML string to output */ public function embed($options = '', $native = false) { // Set up defaults $audio = ''; $video = ''; $alt = ''; $altclass = ''; $loop = 'false'; $width = 'auto'; $height = 'auto'; $bgcolor = '#ffffff'; $mediaplayer = ''; $widescreen = false; $handler = $this->get_handler(); $type = $this->get_real_type(); $placeholder = ''; // Process options and reassign values as necessary if (is_array($options)) { extract($options); } else { $options = explode(',', $options); foreach ($options as $option) { $opt = explode(':', $option, 2); if (isset($opt[0], $opt[1])) { $opt[0] = trim($opt[0]); $opt[1] = trim($opt[1]); switch ($opt[0]) { case 'audio': $audio = $opt[1]; break; case 'video': $video = $opt[1]; break; case 'alt': $alt = $opt[1]; break; case 'altclass': $altclass = $opt[1]; break; case 'loop': $loop = $opt[1]; break; case 'width': $width = $opt[1]; break; case 'height': $height = $opt[1]; break; case 'bgcolor': $bgcolor = $opt[1]; break; case 'mediaplayer': $mediaplayer = $opt[1]; break; case 'widescreen': $widescreen = $opt[1]; break; } } } } $mime = explode('/', $type, 2); $mime = $mime[0]; // Process values for 'auto' if ($width === 'auto') { if ($mime === 'video') { if ($height === 'auto') { $width = 480; } elseif ($widescreen) { $width = round((intval($height) / 9) * 16); } else { $width = round((intval($height) / 3) * 4); } } else { $width = '100%'; } } if ($height === 'auto') { if ($mime === 'audio') { $height = 0; } elseif ($mime === 'video') { if ($width === 'auto') { if ($widescreen) { $height = 270; } else { $height = 360; } } elseif ($widescreen) { $height = round((intval($width) / 16) * 9); } else { $height = round((intval($width) / 4) * 3); } } else { $height = 376; } } elseif ($mime === 'audio') { $height = 0; } // Set proper placeholder value if ($mime === 'audio') { $placeholder = $audio; } elseif ($mime === 'video') { $placeholder = $video; } $embed = ''; // Flash if ($handler === 'flash') { if ($native) { $embed .= "get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\">"; } else { $embed .= ""; } } // Flash Media Player file types. // Preferred handler for MP3 file types. elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== '')) { $height += 20; if ($native) { $embed .= "get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\">"; } else { $embed .= ""; } } // QuickTime 7 file types. Need to test with QuickTime 6. // Only handle MP3's if the Flash Media Player is not present. elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === '')) { $height += 16; if ($native) { if ($placeholder !== '') { $embed .= "get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; } else { $embed .= "get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\">"; } } else { $embed .= ""; } } // Windows Media elseif ($handler === 'wmedia') { $height += 45; if ($native) { $embed .= "get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\">"; } else { $embed .= ""; } } // Everything else else { $embed .= '' . $alt . ''; } return $embed; } /** * Get the real media type * * Often, feeds lie to us, necessitating a bit of deeper inspection. This * converts types to their canonical representations based on the file * extension * * @see get_type() * @param bool $find_handler Internal use only, use {@see get_handler()} instead * @return string MIME type */ public function get_real_type($find_handler = false) { // Mime-types by handler. $types_flash = ['application/x-shockwave-flash', 'application/futuresplash']; // Flash $types_fmedia = ['video/flv', 'video/x-flv','flv-application/octet-stream']; // Flash Media Player $types_quicktime = ['audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video']; // QuickTime $types_wmedia = ['application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx']; // Windows Media $types_mp3 = ['audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg']; // MP3 if ($this->get_type() !== null) { $type = strtolower($this->type); } else { $type = null; } // If we encounter an unsupported mime-type, check the file extension and guess intelligently. if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) { $extension = $this->get_extension(); if ($extension === null) { return null; } switch (strtolower($extension)) { // Audio mime-types case 'aac': case 'adts': $type = 'audio/acc'; break; case 'aif': case 'aifc': case 'aiff': case 'cdda': $type = 'audio/aiff'; break; case 'bwf': $type = 'audio/wav'; break; case 'kar': case 'mid': case 'midi': case 'smf': $type = 'audio/midi'; break; case 'm4a': $type = 'audio/x-m4a'; break; case 'mp3': case 'swa': $type = 'audio/mp3'; break; case 'wav': $type = 'audio/wav'; break; case 'wax': $type = 'audio/x-ms-wax'; break; case 'wma': $type = 'audio/x-ms-wma'; break; // Video mime-types case '3gp': case '3gpp': $type = 'video/3gpp'; break; case '3g2': case '3gp2': $type = 'video/3gpp2'; break; case 'asf': $type = 'video/x-ms-asf'; break; case 'flv': $type = 'video/x-flv'; break; case 'm1a': case 'm1s': case 'm1v': case 'm15': case 'm75': case 'mp2': case 'mpa': case 'mpeg': case 'mpg': case 'mpm': case 'mpv': $type = 'video/mpeg'; break; case 'm4v': $type = 'video/x-m4v'; break; case 'mov': case 'qt': $type = 'video/quicktime'; break; case 'mp4': case 'mpg4': $type = 'video/mp4'; break; case 'sdv': $type = 'video/sd-video'; break; case 'wm': $type = 'video/x-ms-wm'; break; case 'wmv': $type = 'video/x-ms-wmv'; break; case 'wvx': $type = 'video/x-ms-wvx'; break; // Flash mime-types case 'spl': $type = 'application/futuresplash'; break; case 'swf': $type = 'application/x-shockwave-flash'; break; } } if ($find_handler) { if (in_array($type, $types_flash)) { return 'flash'; } elseif (in_array($type, $types_fmedia)) { return 'fmedia'; } elseif (in_array($type, $types_quicktime)) { return 'quicktime'; } elseif (in_array($type, $types_wmedia)) { return 'wmedia'; } elseif (in_array($type, $types_mp3)) { return 'mp3'; } return null; } return $type; } } class_alias('SimplePie\Enclosure', 'SimplePie_Enclosure'); Cache/MySQL.php000064400000036306150211552310007230 0ustar00options = [ 'user' => null, 'pass' => null, 'host' => '127.0.0.1', 'port' => '3306', 'path' => '', 'extras' => [ 'prefix' => '', 'cache_purge_time' => 2592000 ], ]; $this->options = array_replace_recursive($this->options, \SimplePie\Cache::parse_URL($location)); // Path is prefixed with a "/" $this->options['dbname'] = substr($this->options['path'], 1); try { $this->mysql = new \PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8']); } catch (\PDOException $e) { $this->mysql = null; return; } $this->id = $name . $type; if (!$query = $this->mysql->query('SHOW TABLES')) { $this->mysql = null; return; } $db = []; while ($row = $query->fetchColumn()) { $db[] = $row; } if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db)) { $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))'); if ($query === false) { trigger_error("Can't create " . $this->options['extras']['prefix'] . "cache_data table, check permissions", \E_USER_WARNING); $this->mysql = null; return; } } if (!in_array($this->options['extras']['prefix'] . 'items', $db)) { $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))'); if ($query === false) { trigger_error("Can't create " . $this->options['extras']['prefix'] . "items table, check permissions", \E_USER_WARNING); $this->mysql = null; return; } } } /** * Save data to the cache * * @param array|\SimplePie\SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property * @return bool Successfulness */ public function save($data) { if ($this->mysql === null) { return false; } $query = $this->mysql->prepare('DELETE i, cd FROM `' . $this->options['extras']['prefix'] . 'cache_data` cd, ' . '`' . $this->options['extras']['prefix'] . 'items` i ' . 'WHERE cd.id = i.feed_id ' . 'AND cd.mtime < (unix_timestamp() - :purge_time)'); $query->bindValue(':purge_time', $this->options['extras']['cache_purge_time']); if (!$query->execute()) { return false; } if ($data instanceof \SimplePie\SimplePie) { $data = clone $data; $prepared = self::prepare_simplepie_object_for_cache($data); $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed'); $query->bindValue(':feed', $this->id); if ($query->execute()) { if ($query->fetchColumn() > 0) { $items = count($prepared[1]); if ($items) { $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed'; $query = $this->mysql->prepare($sql); $query->bindValue(':items', $items); } else { $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed'; $query = $this->mysql->prepare($sql); } $query->bindValue(':data', $prepared[0]); $query->bindValue(':time', time()); $query->bindValue(':feed', $this->id); if (!$query->execute()) { return false; } } else { $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)'); $query->bindValue(':feed', $this->id); $query->bindValue(':count', count($prepared[1])); $query->bindValue(':data', $prepared[0]); $query->bindValue(':time', time()); if (!$query->execute()) { return false; } } $ids = array_keys($prepared[1]); if (!empty($ids)) { foreach ($ids as $id) { $database_ids[] = $this->mysql->quote($id); } $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed'); $query->bindValue(':feed', $this->id); if ($query->execute()) { $existing_ids = []; while ($row = $query->fetchColumn()) { $existing_ids[] = $row; } $new_ids = array_diff($ids, $existing_ids); foreach ($new_ids as $new_id) { if (!($date = $prepared[1][$new_id]->get_date('U'))) { $date = time(); } $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)'); $query->bindValue(':feed', $this->id); $query->bindValue(':id', $new_id); $query->bindValue(':data', serialize($prepared[1][$new_id]->data)); $query->bindValue(':date', $date); if (!$query->execute()) { return false; } } return true; } } else { return true; } } } else { $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed'); $query->bindValue(':feed', $this->id); if ($query->execute()) { if ($query->rowCount() > 0) { $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed'); $query->bindValue(':data', serialize($data)); $query->bindValue(':time', time()); $query->bindValue(':feed', $this->id); if ($query->execute()) { return true; } } else { $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)'); $query->bindValue(':id', $this->id); $query->bindValue(':data', serialize($data)); $query->bindValue(':time', time()); if ($query->execute()) { return true; } } } } return false; } /** * Retrieve the data saved to the cache * * @return array Data for SimplePie::$data */ public function load() { if ($this->mysql === null) { return false; } $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); $query->bindValue(':id', $this->id); if ($query->execute() && ($row = $query->fetch())) { $data = unserialize($row[1]); if (isset($this->options['items'][0])) { $items = (int) $this->options['items'][0]; } else { $items = (int) $row[0]; } if ($items !== 0) { if (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['feed'][0])) { $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['feed'][0]; } elseif (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['feed'][0])) { $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['feed'][0]; } elseif (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_RDF]['RDF'][0])) { $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_RDF]['RDF'][0]; } elseif (isset($data['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['rss'][0])) { $feed = &$data['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['rss'][0]; } else { $feed = null; } if ($feed !== null) { $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC'; if ($items > 0) { $sql .= ' LIMIT ' . $items; } $query = $this->mysql->prepare($sql); $query->bindValue(':feed', $this->id); if ($query->execute()) { while ($row = $query->fetchColumn()) { $feed['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['entry'][] = unserialize($row); } } else { return false; } } } return $data; } return false; } /** * Retrieve the last modified time for the cache * * @return int Timestamp */ public function mtime() { if ($this->mysql === null) { return false; } $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); $query->bindValue(':id', $this->id); if ($query->execute() && ($time = $query->fetchColumn())) { return $time; } return false; } /** * Set the last modified time to the current time * * @return bool Success status */ public function touch() { if ($this->mysql === null) { return false; } $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id'); $query->bindValue(':time', time()); $query->bindValue(':id', $this->id); return $query->execute() && $query->rowCount() > 0; } /** * Remove the cache * * @return bool Success status */ public function unlink() { if ($this->mysql === null) { return false; } $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); $query->bindValue(':id', $this->id); $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id'); $query2->bindValue(':id', $this->id); return $query->execute() && $query2->execute(); } } class_alias('SimplePie\Cache\MySQL', 'SimplePie_Cache_MySQL'); Cache/Memcache.php000064400000012717150211552310007765 0ustar00options = [ 'host' => '127.0.0.1', 'port' => 11211, 'extras' => [ 'timeout' => 3600, // one hour 'prefix' => 'simplepie_', ], ]; $this->options = array_replace_recursive($this->options, \SimplePie\Cache::parse_URL($location)); $this->name = $this->options['extras']['prefix'] . md5("$name:$type"); $this->cache = new NativeMemcache(); $this->cache->addServer($this->options['host'], (int) $this->options['port']); } /** * Save data to the cache * * @param array|\SimplePie\SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property * @return bool Successfulness */ public function save($data) { if ($data instanceof \SimplePie\SimplePie) { $data = $data->data; } return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']); } /** * Retrieve the data saved to the cache * * @return array Data for SimplePie::$data */ public function load() { $data = $this->cache->get($this->name); if ($data !== false) { return unserialize($data); } return false; } /** * Retrieve the last modified time for the cache * * @return int Timestamp */ public function mtime() { $data = $this->cache->get($this->name); if ($data !== false) { // essentially ignore the mtime because Memcache expires on its own return time(); } return false; } /** * Set the last modified time to the current time * * @return bool Success status */ public function touch() { $data = $this->cache->get($this->name); if ($data !== false) { return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']); } return false; } /** * Remove the cache * * @return bool Success status */ public function unlink() { return $this->cache->delete($this->name, 0); } } class_alias('SimplePie\Cache\Memcache', 'SimplePie_Cache_Memcache'); Cache/BaseDataCache.php000064400000012613150211552310010646 0ustar00cache = $cache; } /** * Fetches a value from the cache. * * Equivalent to \Psr\SimpleCache\CacheInterface::get() * * public function get(string $key, mixed $default = null): mixed; * * * @param string $key The unique key of this item in the cache. * @param mixed $default Default value to return if the key does not exist. * * @return array|mixed The value of the item from the cache, or $default in case of cache miss. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function get_data(string $key, $default = null) { $data = $this->cache->load(); if (!is_array($data)) { return $default; } // ignore data if internal cache expiration time is not set if (!array_key_exists('__cache_expiration_time', $data)) { return $default; } // ignore data if internal cache expiration time is expired if ($data['__cache_expiration_time'] < time()) { return $default; } // remove internal cache expiration time unset($data['__cache_expiration_time']); return $data; } /** * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. * * Equivalent to \Psr\SimpleCache\CacheInterface::set() * * public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool; * * * @param string $key The key of the item to store. * @param array $value The value of the item to store, must be serializable. * @param null|int $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * * @return bool True on success and false on failure. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function set_data(string $key, array $value, ?int $ttl = null): bool { if ($ttl === null) { $ttl = 3600; } // place internal cache expiration time $value['__cache_expiration_time'] = time() + $ttl; return $this->cache->save($value); } /** * Delete an item from the cache by its unique key. * * Equivalent to \Psr\SimpleCache\CacheInterface::delete() * * public function delete(string $key): bool; * * * @param string $key The unique cache key of the item to delete. * * @return bool True if the item was successfully removed. False if there was an error. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function delete_data(string $key): bool { return $this->cache->unlink(); } } Cache/DB.php000064400000012676150211552310006554 0ustar00get_items(); $items_by_id = []; if (!empty($items)) { foreach ($items as $item) { $items_by_id[$item->get_id()] = $item; } if (count($items_by_id) !== count($items)) { $items_by_id = []; foreach ($items as $item) { $items_by_id[$item->get_id(true)] = $item; } } if (isset($data->data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['feed'][0])) { $channel = &$data->data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['feed'][0]; } elseif (isset($data->data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['feed'][0])) { $channel = &$data->data['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['feed'][0]; } elseif (isset($data->data['child'][\SimplePie\SimplePie::NAMESPACE_RDF]['RDF'][0])) { $channel = &$data->data['child'][\SimplePie\SimplePie::NAMESPACE_RDF]['RDF'][0]; } elseif (isset($data->data['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['rss'][0]['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['channel'][0])) { $channel = &$data->data['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['rss'][0]['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['channel'][0]; } else { $channel = null; } if ($channel !== null) { if (isset($channel['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['entry'])) { unset($channel['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['entry']); } if (isset($channel['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['entry'])) { unset($channel['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['entry']); } if (isset($channel['child'][\SimplePie\SimplePie::NAMESPACE_RSS_10]['item'])) { unset($channel['child'][\SimplePie\SimplePie::NAMESPACE_RSS_10]['item']); } if (isset($channel['child'][\SimplePie\SimplePie::NAMESPACE_RSS_090]['item'])) { unset($channel['child'][\SimplePie\SimplePie::NAMESPACE_RSS_090]['item']); } if (isset($channel['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['item'])) { unset($channel['child'][\SimplePie\SimplePie::NAMESPACE_RSS_20]['item']); } } if (isset($data->data['items'])) { unset($data->data['items']); } if (isset($data->data['ordered_items'])) { unset($data->data['ordered_items']); } } return [serialize($data->data), $items_by_id]; } } class_alias('SimplePie\Cache\DB', 'SimplePie_Cache_DB'); Cache/File.php000064400000011374150211552310007140 0ustar00location = $location; $this->filename = $name; $this->extension = $type; $this->name = "$this->location/$this->filename.$this->extension"; } /** * Save data to the cache * * @param array|\SimplePie\SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property * @return bool Successfulness */ public function save($data) { if (file_exists($this->name) && is_writable($this->name) || file_exists($this->location) && is_writable($this->location)) { if ($data instanceof \SimplePie\SimplePie) { $data = $data->data; } $data = serialize($data); return (bool) file_put_contents($this->name, $data); } return false; } /** * Retrieve the data saved to the cache * * @return array Data for SimplePie::$data */ public function load() { if (file_exists($this->name) && is_readable($this->name)) { return unserialize(file_get_contents($this->name)); } return false; } /** * Retrieve the last modified time for the cache * * @return int Timestamp */ public function mtime() { return @filemtime($this->name); } /** * Set the last modified time to the current time * * @return bool Success status */ public function touch() { return @touch($this->name); } /** * Remove the cache * * @return bool Success status */ public function unlink() { if (file_exists($this->name)) { return unlink($this->name); } return false; } } class_alias('SimplePie\Cache\File', 'SimplePie_Cache_File'); Cache/NameFilter.php000064400000006044150211552310010305 0ustar00callable = $callable; } /** * Method to create cache filename with. * * The returning name MUST follow the rules for keys in PSR-16. * * @link https://www.php-fig.org/psr/psr-16/ * * The returning name MUST be a string of at least one character * that uniquely identifies a cached item, MUST only contain the * characters A-Z, a-z, 0-9, _, and . in any order in UTF-8 encoding * and MUST not longer then 64 characters. The following characters * are reserved for future extensions and MUST NOT be used: {}()/\@: * * A provided implementing library MAY support additional characters * and encodings or longer lengths, but MUST support at least that * minimum. * * @param string $name The name for the cache will be most likly an url with query string * * @return string the new cache name */ public function filter(string $name): string { return call_user_func($this->callable, $name); } } Cache/Memcached.php000064400000013033150211552310010121 0ustar00options = [ 'host' => '127.0.0.1', 'port' => 11211, 'extras' => [ 'timeout' => 3600, // one hour 'prefix' => 'simplepie_', ], ]; $this->options = array_replace_recursive($this->options, \SimplePie\Cache::parse_URL($location)); $this->name = $this->options['extras']['prefix'] . md5("$name:$type"); $this->cache = new NativeMemcached(); $this->cache->addServer($this->options['host'], (int)$this->options['port']); } /** * Save data to the cache * @param array|\SimplePie\SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property * @return bool Successfulness */ public function save($data) { if ($data instanceof \SimplePie\SimplePie) { $data = $data->data; } return $this->setData(serialize($data)); } /** * Retrieve the data saved to the cache * @return array Data for SimplePie::$data */ public function load() { $data = $this->cache->get($this->name); if ($data !== false) { return unserialize($data); } return false; } /** * Retrieve the last modified time for the cache * @return int Timestamp */ public function mtime() { $data = $this->cache->get($this->name . '_mtime'); return (int) $data; } /** * Set the last modified time to the current time * @return bool Success status */ public function touch() { $data = $this->cache->get($this->name); return $this->setData($data); } /** * Remove the cache * @return bool Success status */ public function unlink() { return $this->cache->delete($this->name, 0); } /** * Set the last modified time and data to NativeMemcached * @return bool Success status */ private function setData($data) { if ($data !== false) { $this->cache->set($this->name . '_mtime', time(), (int)$this->options['extras']['timeout']); return $this->cache->set($this->name, $data, (int)$this->options['extras']['timeout']); } return false; } } class_alias('SimplePie\Cache\Memcached', 'SimplePie_Cache_Memcached'); Cache/Psr16.php000064400000012023150211552310007164 0ustar00cache = $cache; } /** * Fetches a value from the cache. * * Equivalent to \Psr\SimpleCache\CacheInterface::get() * * public function get(string $key, mixed $default = null): mixed; * * * @param string $key The unique key of this item in the cache. * @param mixed $default Default value to return if the key does not exist. * * @return array|mixed The value of the item from the cache, or $default in case of cache miss. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function get_data(string $key, $default = null) { $data = $this->cache->get($key, $default); if (!is_array($data) || $data === $default) { return $default; } return $data; } /** * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. * * Equivalent to \Psr\SimpleCache\CacheInterface::set() * * public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool; * * * @param string $key The key of the item to store. * @param array $value The value of the item to store, must be serializable. * @param null|int $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * * @return bool True on success and false on failure. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function set_data(string $key, array $value, ?int $ttl = null): bool { return $this->cache->set($key, $value, $ttl); } /** * Delete an item from the cache by its unique key. * * Equivalent to \Psr\SimpleCache\CacheInterface::delete() * * public function delete(string $key): bool; * * * @param string $key The unique cache key of the item to delete. * * @return bool True if the item was successfully removed. False if there was an error. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function delete_data(string $key): bool { return $this->cache->delete($key); } } Cache/Base.php000064400000007306150211552310007133 0ustar00 * public function get(string $key, mixed $default = null): mixed; * * * @param string $key The unique key of this item in the cache. * @param mixed $default Default value to return if the key does not exist. * * @return array|mixed The value of the item from the cache, or $default in case of cache miss. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function get_data(string $key, $default = null); /** * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. * * Equivalent to \Psr\SimpleCache\CacheInterface::set() * * public function set(string $key, mixed $value, null|int|\DateInterval $ttl = null): bool; * * * @param string $key The key of the item to store. * @param array $value The value of the item to store, must be serializable. * @param null|int $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. * * @return bool True on success and false on failure. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function set_data(string $key, array $value, ?int $ttl = null): bool; /** * Delete an item from the cache by its unique key. * * Equivalent to \Psr\SimpleCache\CacheInterface::delete() * * public function delete(string $key): bool; * * * @param string $key The unique cache key of the item to delete. * * @return bool True if the item was successfully removed. False if there was an error. * * @throws InvalidArgumentException * MUST be thrown if the $key string is not a legal value. */ public function delete_data(string $key): bool; } Cache/Redis.php000064400000013665150211552310007334 0ustar00cache = \flow\simple\cache\Redis::getRedisClientInstance(); $parsed = \SimplePie\Cache::parse_URL($location); $redis = new NativeRedis(); $redis->connect($parsed['host'], $parsed['port']); if (isset($parsed['pass'])) { $redis->auth($parsed['pass']); } if (isset($parsed['path'])) { $redis->select((int)substr($parsed['path'], 1)); } $this->cache = $redis; if (!is_null($options) && is_array($options)) { $this->options = $options; } else { $this->options = [ 'prefix' => 'rss:simple_primary:', 'expire' => 0, ]; } $this->name = $this->options['prefix'] . $name; } /** * @param NativeRedis $cache */ public function setRedisClient(NativeRedis $cache) { $this->cache = $cache; } /** * Save data to the cache * * @param array|\SimplePie\SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property * @return bool Successfulness */ public function save($data) { if ($data instanceof \SimplePie\SimplePie) { $data = $data->data; } $response = $this->cache->set($this->name, serialize($data)); if ($this->options['expire']) { $this->cache->expire($this->name, $this->options['expire']); } return $response; } /** * Retrieve the data saved to the cache * * @return array Data for SimplePie::$data */ public function load() { $data = $this->cache->get($this->name); if ($data !== false) { return unserialize($data); } return false; } /** * Retrieve the last modified time for the cache * * @return int Timestamp */ public function mtime() { $data = $this->cache->get($this->name); if ($data !== false) { return time(); } return false; } /** * Set the last modified time to the current time * * @return bool Success status */ public function touch() { $data = $this->cache->get($this->name); if ($data !== false) { $return = $this->cache->set($this->name, $data); if ($this->options['expire']) { return $this->cache->expire($this->name, $this->options['expire']); } return $return; } return false; } /** * Remove the cache * * @return bool Success status */ public function unlink() { return $this->cache->set($this->name, null); } } class_alias('SimplePie\Cache\Redis', 'SimplePie_Cache_Redis'); File.php000064400000031363150211552310006135 0ustar00encode($parsed['authority']), $parsed['path'], $parsed['query'], null); } $this->url = $url; $this->permanent_url = $url; $this->useragent = $useragent; if (preg_match('/^http(s)?:\/\//i', $url)) { if ($useragent === null) { $useragent = ini_get('user_agent'); $this->useragent = $useragent; } if (!is_array($headers)) { $headers = []; } if (!$force_fsockopen && function_exists('curl_exec')) { $this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_CURL; $fp = curl_init(); $headers2 = []; foreach ($headers as $key => $value) { $headers2[] = "$key: $value"; } if (version_compare(\SimplePie\Misc::get_curl_version(), '7.10.5', '>=')) { curl_setopt($fp, CURLOPT_ENCODING, ''); } curl_setopt($fp, CURLOPT_URL, $url); curl_setopt($fp, CURLOPT_HEADER, 1); curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); curl_setopt($fp, CURLOPT_FAILONERROR, 1); curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($fp, CURLOPT_REFERER, \SimplePie\Misc::url_remove_credentials($url)); curl_setopt($fp, CURLOPT_USERAGENT, $useragent); curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); foreach ($curl_options as $curl_param => $curl_value) { curl_setopt($fp, $curl_param, $curl_value); } $this->headers = curl_exec($fp); if (curl_errno($fp) === 23 || curl_errno($fp) === 61) { curl_setopt($fp, CURLOPT_ENCODING, 'none'); $this->headers = curl_exec($fp); } $this->status_code = curl_getinfo($fp, CURLINFO_HTTP_CODE); if (curl_errno($fp)) { $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); $this->success = false; } else { // Use the updated url provided by curl_getinfo after any redirects. if ($info = curl_getinfo($fp)) { $this->url = $info['url']; } curl_close($fp); $this->headers = \SimplePie\HTTP\Parser::prepareHeaders($this->headers, $info['redirect_count'] + 1); $parser = new \SimplePie\HTTP\Parser($this->headers); if ($parser->parse()) { $this->headers = $parser->headers; $this->body = trim($parser->body); $this->status_code = $parser->status_code; if ((in_array($this->status_code, [300, 301, 302, 303, 307]) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) { $this->redirects++; $location = \SimplePie\Misc::absolutize_url($this->headers['location'], $url); $previousStatusCode = $this->status_code; $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen, $curl_options); $this->permanent_url = ($previousStatusCode == 301) ? $location : $url; return; } } } } else { $this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_FSOCKOPEN; $url_parts = parse_url($url); $socket_host = $url_parts['host']; if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') { $socket_host = "ssl://$url_parts[host]"; $url_parts['port'] = 443; } if (!isset($url_parts['port'])) { $url_parts['port'] = 80; } $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout); if (!$fp) { $this->error = 'fsockopen error: ' . $errstr; $this->success = false; } else { stream_set_timeout($fp, $timeout); if (isset($url_parts['path'])) { if (isset($url_parts['query'])) { $get = "$url_parts[path]?$url_parts[query]"; } else { $get = $url_parts['path']; } } else { $get = '/'; } $out = "GET $get HTTP/1.1\r\n"; $out .= "Host: $url_parts[host]\r\n"; $out .= "User-Agent: $useragent\r\n"; if (extension_loaded('zlib')) { $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; } if (isset($url_parts['user']) && isset($url_parts['pass'])) { $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; } foreach ($headers as $key => $value) { $out .= "$key: $value\r\n"; } $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); $info = stream_get_meta_data($fp); $this->headers = ''; while (!$info['eof'] && !$info['timed_out']) { $this->headers .= fread($fp, 1160); $info = stream_get_meta_data($fp); } if (!$info['timed_out']) { $parser = new \SimplePie\HTTP\Parser($this->headers); if ($parser->parse()) { $this->headers = $parser->headers; $this->body = $parser->body; $this->status_code = $parser->status_code; if ((in_array($this->status_code, [300, 301, 302, 303, 307]) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) { $this->redirects++; $location = \SimplePie\Misc::absolutize_url($this->headers['location'], $url); $previousStatusCode = $this->status_code; $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen, $curl_options); $this->permanent_url = ($previousStatusCode == 301) ? $location : $url; return; } if (isset($this->headers['content-encoding'])) { // Hey, we act dumb elsewhere, so let's do that here too switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) { case 'gzip': case 'x-gzip': $decoder = new \SimplePie\Gzdecode($this->body); if (!$decoder->parse()) { $this->error = 'Unable to decode HTTP "gzip" stream'; $this->success = false; } else { $this->body = trim($decoder->data); } break; case 'deflate': if (($decompressed = gzinflate($this->body)) !== false) { $this->body = $decompressed; } elseif (($decompressed = gzuncompress($this->body)) !== false) { $this->body = $decompressed; } elseif (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false) { $this->body = $decompressed; } else { $this->error = 'Unable to decode HTTP "deflate" stream'; $this->success = false; } break; default: $this->error = 'Unknown content coding'; $this->success = false; } } } } else { $this->error = 'fsocket timed out'; $this->success = false; } fclose($fp); } } } else { $this->method = \SimplePie\SimplePie::FILE_SOURCE_LOCAL | \SimplePie\SimplePie::FILE_SOURCE_FILE_GET_CONTENTS; if (empty($url) || !($this->body = trim(file_get_contents($url)))) { $this->error = 'file_get_contents could not read the file'; $this->success = false; } } } } class_alias('SimplePie\File', 'SimplePie_File'); Item.php000064400000400572150211552310006156 0ustar00feed = $feed; $this->data = $data; } /** * Set the registry handler * * This is usually used by {@see \SimplePie\Registry::create} * * @since 1.3 * @param \SimplePie\Registry $registry */ public function set_registry(\SimplePie\Registry $registry)/* : void */ { $this->registry = $registry; } /** * Get a string representation of the item * * @return string */ public function __toString() { return md5(serialize($this->data)); } /** * Remove items that link back to this before destroying this object */ public function __destruct() { if (!gc_enabled()) { unset($this->feed); } } /** * Get data for an item-level element * * This method allows you to get access to ANY element/attribute that is a * sub-element of the item/entry tag. * * See {@see \SimplePie\SimplePie::get_feed_tags()} for a description of the return value * * @since 1.0 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces * @param string $namespace The URL of the XML namespace of the elements you're trying to access * @param string $tag Tag name * @return array */ public function get_item_tags($namespace, $tag) { if (isset($this->data['child'][$namespace][$tag])) { return $this->data['child'][$namespace][$tag]; } return null; } /** * Get the base URL value. * Uses ``, or item link, or feed base URL. * * @param array $element * @return string */ public function get_base($element = []) { if (!empty($element['xml_base_explicit']) && isset($element['xml_base'])) { return $element['xml_base']; } $link = $this->get_permalink(); if ($link != null) { return $link; } return $this->feed->get_base($element); } /** * Sanitize feed data * * @access private * @see \SimplePie\SimplePie::sanitize() * @param string $data Data to sanitize * @param int $type One of the \SimplePie\SimplePie::CONSTRUCT_* constants * @param string $base Base URL to resolve URLs against * @return string Sanitized data */ public function sanitize($data, $type, $base = '') { return $this->feed->sanitize($data, $type, $base); } /** * Get the parent feed * * Note: this may not work as you think for multifeeds! * * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed * @since 1.0 * @return \SimplePie\SimplePie */ public function get_feed() { return $this->feed; } /** * Get the unique identifier for the item * * This is usually used when writing code to check for new items in a feed. * * Uses ``, ``, `` or the `about` attribute * for RDF. If none of these are supplied (or `$hash` is true), creates an * MD5 hash based on the permalink, title and content. * * @since Beta 2 * @param boolean $hash Should we force using a hash instead of the supplied ID? * @param string|false $fn User-supplied function to generate an hash * @return string|null */ public function get_id($hash = false, $fn = 'md5') { if (!$hash) { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'id')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'id')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'guid')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'identifier')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'identifier')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif (isset($this->data['attribs'][\SimplePie\SimplePie::NAMESPACE_RDF]['about'])) { return $this->sanitize($this->data['attribs'][\SimplePie\SimplePie::NAMESPACE_RDF]['about'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } } if ($fn === false) { return null; } elseif (!is_callable($fn)) { trigger_error('User-supplied function $fn must be callable', E_USER_WARNING); $fn = 'md5'; } return call_user_func( $fn, $this->get_permalink().$this->get_title().$this->get_content() ); } /** * Get the title of the item * * Uses ``, `` or `<dc:title>` * * @since Beta 2 (previously called `get_item_title` since 0.8) * @return string|null */ public function get_title() { if (!isset($this->data['title'])) { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'title')) { $this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $this->data['title'] = null; } } return $this->data['title']; } /** * Get the content for the item * * Prefers summaries over full content , but will return full content if a * summary does not exist. * * To prefer full content instead, use {@see get_content} * * Uses `<atom:summary>`, `<description>`, `<dc:description>` or * `<itunes:subtitle>` * * @since 0.8 * @param boolean $description_only Should we avoid falling back to the content? * @return string|null */ public function get_description($description_only = false) { if (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'summary')) && ($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'summary')) && ($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'description')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'description')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'description')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'description')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'summary')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'subtitle')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'description')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML))) { return $return; } elseif (!$description_only) { return $this->get_content(true); } return null; } /** * Get the content for the item * * Prefers full content over summaries, but will return a summary if full * content does not exist. * * To prefer summaries instead, use {@see get_description} * * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module) * * @since 1.0 * @param boolean $content_only Should we avoid falling back to the description? * @return string|null */ public function get_content($content_only = false) { if (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'content')) && ($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_10_content_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'content')) && ($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) { return $return; } elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded')) && ($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($tags[0])))) { return $return; } elseif (!$content_only) { return $this->get_description(true); } return null; } /** * Get the media:thumbnail of the item * * Uses `<media:thumbnail>` * * * @return array|null */ public function get_thumbnail() { if (!isset($this->data['thumbnail'])) { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'thumbnail')) { $thumbnail = $return[0]['attribs']['']; if (empty($thumbnail['url'])) { $this->data['thumbnail'] = null; } else { $thumbnail['url'] = $this->sanitize($thumbnail['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($return[0])); $this->data['thumbnail'] = $thumbnail; } } else { $this->data['thumbnail'] = null; } } return $this->data['thumbnail']; } /** * Get a category for the item * * @since Beta 3 (previously called `get_categories()` since Beta 2) * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Category|null */ public function get_category($key = 0) { $categories = $this->get_categories(); if (isset($categories[$key])) { return $categories[$key]; } return null; } /** * Get all categories for the item * * Uses `<atom:category>`, `<category>` or `<dc:subject>` * * @since Beta 3 * @return \SimplePie\Category[]|null List of {@see \SimplePie\Category} objects */ public function get_categories() { $categories = []; $type = 'category'; foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, $type) as $category) { $term = null; $scheme = null; $label = null; if (isset($category['attribs']['']['term'])) { $term = $this->sanitize($category['attribs']['']['term'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories[] = $this->registry->create(Category::class, [$term, $scheme, $label, $type]); } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, $type) as $category) { // This is really the label, but keep this as the term also for BC. // Label will also work on retrieving because that falls back to term. $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); if (isset($category['attribs']['']['domain'])) { $scheme = $this->sanitize($category['attribs']['']['domain'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = null; } $categories[] = $this->registry->create(Category::class, [$term, $scheme, null, $type]); } $type = 'subject'; foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, $type) as $category) { $categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null, $type]); } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, $type) as $category) { $categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null, $type]); } if (!empty($categories)) { return array_unique($categories); } return null; } /** * Get an author for the item * * @since Beta 2 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Author|null */ public function get_author($key = 0) { $authors = $this->get_authors(); if (isset($authors[$key])) { return $authors[$key]; } return null; } /** * Get a contributor for the item * * @since 1.1 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Author|null */ public function get_contributor($key = 0) { $contributors = $this->get_contributors(); if (isset($contributors[$key])) { return $contributors[$key]; } return null; } /** * Get all contributors for the item * * Uses `<atom:contributor>` * * @since 1.1 * @return \SimplePie\Author[]|null List of {@see \SimplePie\Author} objects */ public function get_contributors() { $contributors = []; foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'contributor') as $contributor) { $name = null; $uri = null; $email = null; if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'])) { $name = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'])) { $uri = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0])); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'])) { $email = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $uri !== null) { $contributors[] = $this->registry->create(Author::class, [$name, $uri, $email]); } } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'contributor') as $contributor) { $name = null; $url = null; $email = null; if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'])) { $name = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'])) { $url = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0])); } if (isset($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($contributor['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $url !== null) { $contributors[] = $this->registry->create(Author::class, [$name, $url, $email]); } } if (!empty($contributors)) { return array_unique($contributors); } return null; } /** * Get all authors for the item * * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>` * * @since Beta 2 * @return \SimplePie\Author[]|null List of {@see \SimplePie\Author} objects */ public function get_authors() { $authors = []; foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'author') as $author) { $name = null; $uri = null; $email = null; if (isset($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'])) { $name = $this->sanitize($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'])) { $uri = $this->sanitize($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['uri'][0])); } if (isset($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'])) { $email = $this->sanitize($author['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_10]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $uri !== null) { $authors[] = $this->registry->create(Author::class, [$name, $uri, $email]); } } if ($author = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'author')) { $name = null; $url = null; $email = null; if (isset($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'])) { $name = $this->sanitize($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['name'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'])) { $url = $this->sanitize($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['url'][0])); } if (isset($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($author[0]['child'][\SimplePie\SimplePie::NAMESPACE_ATOM_03]['email'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $url !== null) { $authors[] = $this->registry->create(Author::class, [$name, $url, $email]); } } if ($author = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'author')) { $authors[] = $this->registry->create(Author::class, [null, null, $this->sanitize($author[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)]); } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'creator') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'creator') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'author') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null]); } if (!empty($authors)) { return array_unique($authors); } elseif (($source = $this->get_source()) && ($authors = $source->get_authors())) { return $authors; } elseif ($authors = $this->feed->get_authors()) { return $authors; } return null; } /** * Get the copyright info for the item * * Uses `<atom:rights>` or `<dc:rights>` * * @since 1.1 * @return string */ public function get_copyright() { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'rights')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'rights')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'rights')) { return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } return null; } /** * Get the posting date/time for the item * * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`, * `<atom:modified>`, `<pubDate>` or `<dc:date>` * * Note: obeys PHP's timezone setting. To get a UTC date/time, use * {@see get_gmdate} * * @since Beta 2 (previously called `get_item_date` since 0.8) * * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data) * @return int|string|null */ public function get_date($date_format = 'j F Y, g:i a') { if (!isset($this->data['date'])) { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'published')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'pubDate')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'date')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'date')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'updated')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'issued')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'created')) { $this->data['date']['raw'] = $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'modified')) { $this->data['date']['raw'] = $return[0]['data']; } if (!empty($this->data['date']['raw'])) { $parser = $this->registry->call(Parse\Date::class, 'get'); $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']) ?: null; } else { $this->data['date'] = null; } } if ($this->data['date']) { $date_format = (string) $date_format; switch ($date_format) { case '': return $this->sanitize($this->data['date']['raw'], \SimplePie\SimplePie::CONSTRUCT_TEXT); case 'U': return $this->data['date']['parsed']; default: return date($date_format, $this->data['date']['parsed']); } } return null; } /** * Get the update date/time for the item * * Uses `<atom:updated>` * * Note: obeys PHP's timezone setting. To get a UTC date/time, use * {@see get_gmdate} * * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data) * @return int|string|null */ public function get_updated_date($date_format = 'j F Y, g:i a') { if (!isset($this->data['updated'])) { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'updated')) { $this->data['updated']['raw'] = $return[0]['data']; } if (!empty($this->data['updated']['raw'])) { $parser = $this->registry->call(Parse\Date::class, 'get'); $this->data['updated']['parsed'] = $parser->parse($this->data['updated']['raw']) ?: null; } else { $this->data['updated'] = null; } } if ($this->data['updated']) { $date_format = (string) $date_format; switch ($date_format) { case '': return $this->sanitize($this->data['updated']['raw'], \SimplePie\SimplePie::CONSTRUCT_TEXT); case 'U': return $this->data['updated']['parsed']; default: return date($date_format, $this->data['updated']['parsed']); } } return null; } /** * Get the localized posting date/time for the item * * Returns the date formatted in the localized language. To display in * languages other than the server's default, you need to change the locale * with {@link http://php.net/setlocale setlocale()}. The available * localizations depend on which ones are installed on your web server. * * @since 1.0 * * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data) * @return int|string|null */ public function get_local_date($date_format = '%c') { if (!$date_format) { return $this->sanitize($this->get_date(''), \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif (($date = $this->get_date('U')) !== null && $date !== false) { return strftime($date_format, $date); } return null; } /** * Get the posting date/time for the item (UTC time) * * @see get_date * @param string $date_format Supports any PHP date format from {@see http://php.net/date} * @return int|string|null */ public function get_gmdate($date_format = 'j F Y, g:i a') { $date = $this->get_date('U'); if ($date === null) { return null; } return gmdate($date_format, $date); } /** * Get the update date/time for the item (UTC time) * * @see get_updated_date * @param string $date_format Supports any PHP date format from {@see http://php.net/date} * @return int|string|null */ public function get_updated_gmdate($date_format = 'j F Y, g:i a') { $date = $this->get_updated_date('U'); if ($date === null) { return null; } return gmdate($date_format, $date); } /** * Get the permalink for the item * * Returns the first link available with a relationship of "alternate". * Identical to {@see get_link()} with key 0 * * @see get_link * @since 0.8 * @return string|null Permalink URL */ public function get_permalink() { $link = $this->get_link(); $enclosure = $this->get_enclosure(0); if ($link !== null) { return $link; } elseif ($enclosure !== null) { return $enclosure->get_link(); } return null; } /** * Get a single link for the item * * @since Beta 3 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 * @param string $rel The relationship of the link to return * @return string|null Link URL */ public function get_link($key = 0, $rel = 'alternate') { $links = $this->get_links($rel); if ($links && $links[$key] !== null) { return $links[$key]; } return null; } /** * Get all links for the item * * Uses `<atom:link>`, `<link>` or `<guid>` * * @since Beta 2 * @param string $rel The relationship of links to return * @return array|null Links found for the item (strings) */ public function get_links($rel = 'alternate') { if (!isset($this->data['links'])) { $this->data['links'] = []; foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'link') as $link) { if (isset($link['attribs']['']['href'])) { $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); } } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'link') as $link) { if (isset($link['attribs']['']['href'])) { $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); } } if ($links = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'guid')) { if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true') { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($links[0])); } } $keys = array_keys($this->data['links']); foreach ($keys as $key) { if ($this->registry->call(Misc::class, 'is_isegment_nz_nc', [$key])) { if (isset($this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key])) { $this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key]); $this->data['links'][$key] = &$this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key]; } else { $this->data['links'][\SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY . $key] = &$this->data['links'][$key]; } } elseif (substr($key, 0, 41) === \SimplePie\SimplePie::IANA_LINK_RELATIONS_REGISTRY) { $this->data['links'][substr($key, 41)] = &$this->data['links'][$key]; } $this->data['links'][$key] = array_unique($this->data['links'][$key]); } } if (isset($this->data['links'][$rel])) { return $this->data['links'][$rel]; } return null; } /** * Get an enclosure from the item * * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS. * * @since Beta 2 * @todo Add ability to prefer one type of content over another (in a media group). * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Enclosure|null */ public function get_enclosure($key = 0, $prefer = null) { $enclosures = $this->get_enclosures(); if (isset($enclosures[$key])) { return $enclosures[$key]; } return null; } /** * Get all available enclosures (podcasts, etc.) * * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS. * * At this point, we're pretty much assuming that all enclosures for an item * are the same content. Anything else is too complicated to * properly support. * * @since Beta 2 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4). * @todo If an element exists at a level, but its value is empty, we should fall back to the value from the parent (if it exists). * @return \SimplePie\Enclosure[]|null List of \SimplePie\Enclosure items */ public function get_enclosures() { if (!isset($this->data['enclosures'])) { $this->data['enclosures'] = []; // Elements $captions_parent = null; $categories_parent = null; $copyrights_parent = null; $credits_parent = null; $description_parent = null; $duration_parent = null; $hashes_parent = null; $keywords_parent = null; $player_parent = null; $ratings_parent = null; $restrictions_parent = null; $thumbnails_parent = null; $title_parent = null; // Let's do the channel and item-level ones first, and just re-use them if we need to. $parent = $this->get_feed(); // CAPTIONS if ($captions = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'text')) { foreach ($captions as $caption) { $caption_type = null; $caption_lang = null; $caption_startTime = null; $caption_endTime = null; $caption_text = null; if (isset($caption['attribs']['']['type'])) { $caption_type = $this->sanitize($caption['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['lang'])) { $caption_lang = $this->sanitize($caption['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['start'])) { $caption_startTime = $this->sanitize($caption['attribs']['']['start'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['end'])) { $caption_endTime = $this->sanitize($caption['attribs']['']['end'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['data'])) { $caption_text = $this->sanitize($caption['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $captions_parent[] = $this->registry->create(Caption::class, [$caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text]); } } elseif ($captions = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'text')) { foreach ($captions as $caption) { $caption_type = null; $caption_lang = null; $caption_startTime = null; $caption_endTime = null; $caption_text = null; if (isset($caption['attribs']['']['type'])) { $caption_type = $this->sanitize($caption['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['lang'])) { $caption_lang = $this->sanitize($caption['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['start'])) { $caption_startTime = $this->sanitize($caption['attribs']['']['start'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['end'])) { $caption_endTime = $this->sanitize($caption['attribs']['']['end'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['data'])) { $caption_text = $this->sanitize($caption['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $captions_parent[] = $this->registry->create(Caption::class, [$caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text]); } } if (is_array($captions_parent)) { $captions_parent = array_values(array_unique($captions_parent)); } // CATEGORIES foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'category') as $category) { $term = null; $scheme = null; $label = null; if (isset($category['data'])) { $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = 'http://search.yahoo.com/mrss/category_schema'; } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories_parent[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } foreach ((array) $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'category') as $category) { $term = null; $scheme = null; $label = null; if (isset($category['data'])) { $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = 'http://search.yahoo.com/mrss/category_schema'; } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories_parent[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } foreach ((array) $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'category') as $category) { $term = null; $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; $label = null; if (isset($category['attribs']['']['text'])) { $label = $this->sanitize($category['attribs']['']['text'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories_parent[] = $this->registry->create(Category::class, [$term, $scheme, $label]); if (isset($category['child'][\SimplePie\SimplePie::NAMESPACE_ITUNES]['category'])) { foreach ((array) $category['child'][\SimplePie\SimplePie::NAMESPACE_ITUNES]['category'] as $subcategory) { if (isset($subcategory['attribs']['']['text'])) { $label = $this->sanitize($subcategory['attribs']['']['text'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories_parent[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } } } if (is_array($categories_parent)) { $categories_parent = array_values(array_unique($categories_parent)); } // COPYRIGHT if ($copyright = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'copyright')) { $copyright_url = null; $copyright_label = null; if (isset($copyright[0]['attribs']['']['url'])) { $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($copyright[0]['data'])) { $copyright_label = $this->sanitize($copyright[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $copyrights_parent = $this->registry->create(Copyright::class, [$copyright_url, $copyright_label]); } elseif ($copyright = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'copyright')) { $copyright_url = null; $copyright_label = null; if (isset($copyright[0]['attribs']['']['url'])) { $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($copyright[0]['data'])) { $copyright_label = $this->sanitize($copyright[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $copyrights_parent = $this->registry->create(Copyright::class, [$copyright_url, $copyright_label]); } // CREDITS if ($credits = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'credit')) { foreach ($credits as $credit) { $credit_role = null; $credit_scheme = null; $credit_name = null; if (isset($credit['attribs']['']['role'])) { $credit_role = $this->sanitize($credit['attribs']['']['role'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($credit['attribs']['']['scheme'])) { $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $credit_scheme = 'urn:ebu'; } if (isset($credit['data'])) { $credit_name = $this->sanitize($credit['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $credits_parent[] = $this->registry->create(Credit::class, [$credit_role, $credit_scheme, $credit_name]); } } elseif ($credits = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'credit')) { foreach ($credits as $credit) { $credit_role = null; $credit_scheme = null; $credit_name = null; if (isset($credit['attribs']['']['role'])) { $credit_role = $this->sanitize($credit['attribs']['']['role'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($credit['attribs']['']['scheme'])) { $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $credit_scheme = 'urn:ebu'; } if (isset($credit['data'])) { $credit_name = $this->sanitize($credit['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $credits_parent[] = $this->registry->create(Credit::class, [$credit_role, $credit_scheme, $credit_name]); } } if (is_array($credits_parent)) { $credits_parent = array_values(array_unique($credits_parent)); } // DESCRIPTION if ($description_parent = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'description')) { if (isset($description_parent[0]['data'])) { $description_parent = $this->sanitize($description_parent[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } } elseif ($description_parent = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'description')) { if (isset($description_parent[0]['data'])) { $description_parent = $this->sanitize($description_parent[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } } // DURATION if ($duration_parent = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'duration')) { $seconds = null; $minutes = null; $hours = null; if (isset($duration_parent[0]['data'])) { $temp = explode(':', $this->sanitize($duration_parent[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); if (sizeof($temp) > 0) { $seconds = (int) array_pop($temp); } if (sizeof($temp) > 0) { $minutes = (int) array_pop($temp); $seconds += $minutes * 60; } if (sizeof($temp) > 0) { $hours = (int) array_pop($temp); $seconds += $hours * 3600; } unset($temp); $duration_parent = $seconds; } } // HASHES if ($hashes_iterator = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'hash')) { foreach ($hashes_iterator as $hash) { $value = null; $algo = null; if (isset($hash['data'])) { $value = $this->sanitize($hash['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($hash['attribs']['']['algo'])) { $algo = $this->sanitize($hash['attribs']['']['algo'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $algo = 'md5'; } $hashes_parent[] = $algo.':'.$value; } } elseif ($hashes_iterator = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'hash')) { foreach ($hashes_iterator as $hash) { $value = null; $algo = null; if (isset($hash['data'])) { $value = $this->sanitize($hash['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($hash['attribs']['']['algo'])) { $algo = $this->sanitize($hash['attribs']['']['algo'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $algo = 'md5'; } $hashes_parent[] = $algo.':'.$value; } } if (is_array($hashes_parent)) { $hashes_parent = array_values(array_unique($hashes_parent)); } // KEYWORDS if ($keywords = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'keywords')) { if (isset($keywords[0]['data'])) { $temp = explode(',', $this->sanitize($keywords[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords_parent[] = trim($word); } } unset($temp); } elseif ($keywords = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'keywords')) { if (isset($keywords[0]['data'])) { $temp = explode(',', $this->sanitize($keywords[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords_parent[] = trim($word); } } unset($temp); } elseif ($keywords = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'keywords')) { if (isset($keywords[0]['data'])) { $temp = explode(',', $this->sanitize($keywords[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords_parent[] = trim($word); } } unset($temp); } elseif ($keywords = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'keywords')) { if (isset($keywords[0]['data'])) { $temp = explode(',', $this->sanitize($keywords[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords_parent[] = trim($word); } } unset($temp); } if (is_array($keywords_parent)) { $keywords_parent = array_values(array_unique($keywords_parent)); } // PLAYER if ($player_parent = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'player')) { if (isset($player_parent[0]['attribs']['']['url'])) { $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } } elseif ($player_parent = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'player')) { if (isset($player_parent[0]['attribs']['']['url'])) { $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } } // RATINGS if ($ratings = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'rating')) { foreach ($ratings as $rating) { $rating_scheme = null; $rating_value = null; if (isset($rating['attribs']['']['scheme'])) { $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $rating_scheme = 'urn:simple'; } if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings_parent[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } } elseif ($ratings = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'explicit')) { foreach ($ratings as $rating) { $rating_scheme = 'urn:itunes'; $rating_value = null; if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings_parent[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } } elseif ($ratings = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'rating')) { foreach ($ratings as $rating) { $rating_scheme = null; $rating_value = null; if (isset($rating['attribs']['']['scheme'])) { $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $rating_scheme = 'urn:simple'; } if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings_parent[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } } elseif ($ratings = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'explicit')) { foreach ($ratings as $rating) { $rating_scheme = 'urn:itunes'; $rating_value = null; if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings_parent[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } } if (is_array($ratings_parent)) { $ratings_parent = array_values(array_unique($ratings_parent)); } // RESTRICTIONS if ($restrictions = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'restriction')) { foreach ($restrictions as $restriction) { $restriction_relationship = null; $restriction_type = null; $restriction_value = null; if (isset($restriction['attribs']['']['relationship'])) { $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['attribs']['']['type'])) { $restriction_type = $this->sanitize($restriction['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['data'])) { $restriction_value = $this->sanitize($restriction['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $restrictions_parent[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } } elseif ($restrictions = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'block')) { foreach ($restrictions as $restriction) { $restriction_relationship = 'allow'; $restriction_type = null; $restriction_value = 'itunes'; if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') { $restriction_relationship = 'deny'; } $restrictions_parent[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } } elseif ($restrictions = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'restriction')) { foreach ($restrictions as $restriction) { $restriction_relationship = null; $restriction_type = null; $restriction_value = null; if (isset($restriction['attribs']['']['relationship'])) { $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['attribs']['']['type'])) { $restriction_type = $this->sanitize($restriction['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['data'])) { $restriction_value = $this->sanitize($restriction['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $restrictions_parent[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } } elseif ($restrictions = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'block')) { foreach ($restrictions as $restriction) { $restriction_relationship = 'allow'; $restriction_type = null; $restriction_value = 'itunes'; if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') { $restriction_relationship = 'deny'; } $restrictions_parent[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } } if (is_array($restrictions_parent)) { $restrictions_parent = array_values(array_unique($restrictions_parent)); } else { $restrictions_parent = [new \SimplePie\Restriction('allow', null, 'default')]; } // THUMBNAILS if ($thumbnails = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'thumbnail')) { foreach ($thumbnails as $thumbnail) { if (isset($thumbnail['attribs']['']['url'])) { $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } } } elseif ($thumbnails = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'thumbnail')) { foreach ($thumbnails as $thumbnail) { if (isset($thumbnail['attribs']['']['url'])) { $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } } } // TITLES if ($title_parent = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'title')) { if (isset($title_parent[0]['data'])) { $title_parent = $this->sanitize($title_parent[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } } elseif ($title_parent = $parent->get_channel_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'title')) { if (isset($title_parent[0]['data'])) { $title_parent = $this->sanitize($title_parent[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } } // Clear the memory unset($parent); // Attributes $bitrate = null; $channels = null; $duration = null; $expression = null; $framerate = null; $height = null; $javascript = null; $lang = null; $length = null; $medium = null; $samplingrate = null; $type = null; $url = null; $width = null; // Elements $captions = null; $categories = null; $copyrights = null; $credits = null; $description = null; $hashes = null; $keywords = null; $player = null; $ratings = null; $restrictions = null; $thumbnails = null; $title = null; // If we have media:group tags, loop through them. foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'group') as $group) { if (isset($group['child']) && isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['content'])) { // If we have media:content tags, loop through them. foreach ((array) $group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['content'] as $content) { if (isset($content['attribs']['']['url'])) { // Attributes $bitrate = null; $channels = null; $duration = null; $expression = null; $framerate = null; $height = null; $javascript = null; $lang = null; $length = null; $medium = null; $samplingrate = null; $type = null; $url = null; $width = null; // Elements $captions = null; $categories = null; $copyrights = null; $credits = null; $description = null; $hashes = null; $keywords = null; $player = null; $ratings = null; $restrictions = null; $thumbnails = null; $title = null; // Start checking the attributes of media:content if (isset($content['attribs']['']['bitrate'])) { $bitrate = $this->sanitize($content['attribs']['']['bitrate'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['channels'])) { $channels = $this->sanitize($content['attribs']['']['channels'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['duration'])) { $duration = $this->sanitize($content['attribs']['']['duration'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $duration = $duration_parent; } if (isset($content['attribs']['']['expression'])) { $expression = $this->sanitize($content['attribs']['']['expression'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['framerate'])) { $framerate = $this->sanitize($content['attribs']['']['framerate'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['height'])) { $height = $this->sanitize($content['attribs']['']['height'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['lang'])) { $lang = $this->sanitize($content['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['fileSize'])) { $length = intval($content['attribs']['']['fileSize']); } if (isset($content['attribs']['']['medium'])) { $medium = $this->sanitize($content['attribs']['']['medium'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['samplingrate'])) { $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['type'])) { $type = $this->sanitize($content['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['width'])) { $width = $this->sanitize($content['attribs']['']['width'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $url = $this->sanitize($content['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); // Checking the other optional media: elements. Priority: media:content, media:group, item, channel // CAPTIONS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['text'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['text'] as $caption) { $caption_type = null; $caption_lang = null; $caption_startTime = null; $caption_endTime = null; $caption_text = null; if (isset($caption['attribs']['']['type'])) { $caption_type = $this->sanitize($caption['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['lang'])) { $caption_lang = $this->sanitize($caption['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['start'])) { $caption_startTime = $this->sanitize($caption['attribs']['']['start'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['end'])) { $caption_endTime = $this->sanitize($caption['attribs']['']['end'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['data'])) { $caption_text = $this->sanitize($caption['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $captions[] = $this->registry->create(Caption::class, [$caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text]); } if (is_array($captions)) { $captions = array_values(array_unique($captions)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['text'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['text'] as $caption) { $caption_type = null; $caption_lang = null; $caption_startTime = null; $caption_endTime = null; $caption_text = null; if (isset($caption['attribs']['']['type'])) { $caption_type = $this->sanitize($caption['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['lang'])) { $caption_lang = $this->sanitize($caption['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['start'])) { $caption_startTime = $this->sanitize($caption['attribs']['']['start'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['end'])) { $caption_endTime = $this->sanitize($caption['attribs']['']['end'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['data'])) { $caption_text = $this->sanitize($caption['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $captions[] = $this->registry->create(Caption::class, [$caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text]); } if (is_array($captions)) { $captions = array_values(array_unique($captions)); } } else { $captions = $captions_parent; } // CATEGORIES if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['category'])) { foreach ((array) $content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['category'] as $category) { $term = null; $scheme = null; $label = null; if (isset($category['data'])) { $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = 'http://search.yahoo.com/mrss/category_schema'; } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } } if (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['category'])) { foreach ((array) $group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['category'] as $category) { $term = null; $scheme = null; $label = null; if (isset($category['data'])) { $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = 'http://search.yahoo.com/mrss/category_schema'; } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } } if (is_array($categories) && is_array($categories_parent)) { $categories = array_values(array_unique(array_merge($categories, $categories_parent))); } elseif (is_array($categories)) { $categories = array_values(array_unique($categories)); } elseif (is_array($categories_parent)) { $categories = array_values(array_unique($categories_parent)); } // COPYRIGHTS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'])) { $copyright_url = null; $copyright_label = null; if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) { $copyright_url = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['data'])) { $copyright_label = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $copyrights = $this->registry->create(Copyright::class, [$copyright_url, $copyright_label]); } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'])) { $copyright_url = null; $copyright_label = null; if (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) { $copyright_url = $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['data'])) { $copyright_label = $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $copyrights = $this->registry->create(Copyright::class, [$copyright_url, $copyright_label]); } else { $copyrights = $copyrights_parent; } // CREDITS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['credit'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['credit'] as $credit) { $credit_role = null; $credit_scheme = null; $credit_name = null; if (isset($credit['attribs']['']['role'])) { $credit_role = $this->sanitize($credit['attribs']['']['role'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($credit['attribs']['']['scheme'])) { $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $credit_scheme = 'urn:ebu'; } if (isset($credit['data'])) { $credit_name = $this->sanitize($credit['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $credits[] = $this->registry->create(Credit::class, [$credit_role, $credit_scheme, $credit_name]); } if (is_array($credits)) { $credits = array_values(array_unique($credits)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['credit'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['credit'] as $credit) { $credit_role = null; $credit_scheme = null; $credit_name = null; if (isset($credit['attribs']['']['role'])) { $credit_role = $this->sanitize($credit['attribs']['']['role'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($credit['attribs']['']['scheme'])) { $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $credit_scheme = 'urn:ebu'; } if (isset($credit['data'])) { $credit_name = $this->sanitize($credit['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $credits[] = $this->registry->create(Credit::class, [$credit_role, $credit_scheme, $credit_name]); } if (is_array($credits)) { $credits = array_values(array_unique($credits)); } } else { $credits = $credits_parent; } // DESCRIPTION if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['description'])) { $description = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['description'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['description'])) { $description = $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['description'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $description = $description_parent; } // HASHES if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['hash'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['hash'] as $hash) { $value = null; $algo = null; if (isset($hash['data'])) { $value = $this->sanitize($hash['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($hash['attribs']['']['algo'])) { $algo = $this->sanitize($hash['attribs']['']['algo'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $algo = 'md5'; } $hashes[] = $algo.':'.$value; } if (is_array($hashes)) { $hashes = array_values(array_unique($hashes)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['hash'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['hash'] as $hash) { $value = null; $algo = null; if (isset($hash['data'])) { $value = $this->sanitize($hash['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($hash['attribs']['']['algo'])) { $algo = $this->sanitize($hash['attribs']['']['algo'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $algo = 'md5'; } $hashes[] = $algo.':'.$value; } if (is_array($hashes)) { $hashes = array_values(array_unique($hashes)); } } else { $hashes = $hashes_parent; } // KEYWORDS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'])) { if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'][0]['data'])) { $temp = explode(',', $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords[] = trim($word); } unset($temp); } if (is_array($keywords)) { $keywords = array_values(array_unique($keywords)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'])) { if (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'][0]['data'])) { $temp = explode(',', $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords[] = trim($word); } unset($temp); } if (is_array($keywords)) { $keywords = array_values(array_unique($keywords)); } } else { $keywords = $keywords_parent; } // PLAYER if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { $player = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { $player = $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } else { $player = $player_parent; } // RATINGS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['rating'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['rating'] as $rating) { $rating_scheme = null; $rating_value = null; if (isset($rating['attribs']['']['scheme'])) { $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $rating_scheme = 'urn:simple'; } if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } if (is_array($ratings)) { $ratings = array_values(array_unique($ratings)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['rating'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['rating'] as $rating) { $rating_scheme = null; $rating_value = null; if (isset($rating['attribs']['']['scheme'])) { $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $rating_scheme = 'urn:simple'; } if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } if (is_array($ratings)) { $ratings = array_values(array_unique($ratings)); } } else { $ratings = $ratings_parent; } // RESTRICTIONS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['restriction'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['restriction'] as $restriction) { $restriction_relationship = null; $restriction_type = null; $restriction_value = null; if (isset($restriction['attribs']['']['relationship'])) { $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['attribs']['']['type'])) { $restriction_type = $this->sanitize($restriction['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['data'])) { $restriction_value = $this->sanitize($restriction['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $restrictions[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } if (is_array($restrictions)) { $restrictions = array_values(array_unique($restrictions)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['restriction'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['restriction'] as $restriction) { $restriction_relationship = null; $restriction_type = null; $restriction_value = null; if (isset($restriction['attribs']['']['relationship'])) { $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['attribs']['']['type'])) { $restriction_type = $this->sanitize($restriction['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['data'])) { $restriction_value = $this->sanitize($restriction['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $restrictions[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } if (is_array($restrictions)) { $restrictions = array_values(array_unique($restrictions)); } } else { $restrictions = $restrictions_parent; } // THUMBNAILS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } if (is_array($thumbnails)) { $thumbnails = array_values(array_unique($thumbnails)); } } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'])) { foreach ($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } if (is_array($thumbnails)) { $thumbnails = array_values(array_unique($thumbnails)); } } else { $thumbnails = $thumbnails_parent; } // TITLES if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['title'])) { $title = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['title'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } elseif (isset($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['title'])) { $title = $this->sanitize($group['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['title'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $title = $title_parent; } $this->data['enclosures'][] = $this->registry->create(Enclosure::class, [$url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width]); } } } } // If we have standalone media:content tags, loop through them. if (isset($this->data['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['content'])) { foreach ((array) $this->data['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['content'] as $content) { if (isset($content['attribs']['']['url']) || isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { // Attributes $bitrate = null; $channels = null; $duration = null; $expression = null; $framerate = null; $height = null; $javascript = null; $lang = null; $length = null; $medium = null; $samplingrate = null; $type = null; $url = null; $width = null; // Elements $captions = null; $categories = null; $copyrights = null; $credits = null; $description = null; $hashes = null; $keywords = null; $player = null; $ratings = null; $restrictions = null; $thumbnails = null; $title = null; // Start checking the attributes of media:content if (isset($content['attribs']['']['bitrate'])) { $bitrate = $this->sanitize($content['attribs']['']['bitrate'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['channels'])) { $channels = $this->sanitize($content['attribs']['']['channels'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['duration'])) { $duration = $this->sanitize($content['attribs']['']['duration'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $duration = $duration_parent; } if (isset($content['attribs']['']['expression'])) { $expression = $this->sanitize($content['attribs']['']['expression'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['framerate'])) { $framerate = $this->sanitize($content['attribs']['']['framerate'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['height'])) { $height = $this->sanitize($content['attribs']['']['height'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['lang'])) { $lang = $this->sanitize($content['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['fileSize'])) { $length = intval($content['attribs']['']['fileSize']); } if (isset($content['attribs']['']['medium'])) { $medium = $this->sanitize($content['attribs']['']['medium'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['samplingrate'])) { $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['type'])) { $type = $this->sanitize($content['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['width'])) { $width = $this->sanitize($content['attribs']['']['width'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['attribs']['']['url'])) { $url = $this->sanitize($content['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } // Checking the other optional media: elements. Priority: media:content, media:group, item, channel // CAPTIONS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['text'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['text'] as $caption) { $caption_type = null; $caption_lang = null; $caption_startTime = null; $caption_endTime = null; $caption_text = null; if (isset($caption['attribs']['']['type'])) { $caption_type = $this->sanitize($caption['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['lang'])) { $caption_lang = $this->sanitize($caption['attribs']['']['lang'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['start'])) { $caption_startTime = $this->sanitize($caption['attribs']['']['start'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['attribs']['']['end'])) { $caption_endTime = $this->sanitize($caption['attribs']['']['end'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($caption['data'])) { $caption_text = $this->sanitize($caption['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $captions[] = $this->registry->create(Caption::class, [$caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text]); } if (is_array($captions)) { $captions = array_values(array_unique($captions)); } } else { $captions = $captions_parent; } // CATEGORIES if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['category'])) { foreach ((array) $content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['category'] as $category) { $term = null; $scheme = null; $label = null; if (isset($category['data'])) { $term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $scheme = 'http://search.yahoo.com/mrss/category_schema'; } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $categories[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } } if (is_array($categories) && is_array($categories_parent)) { $categories = array_values(array_unique(array_merge($categories, $categories_parent))); } elseif (is_array($categories)) { $categories = array_values(array_unique($categories)); } elseif (is_array($categories_parent)) { $categories = array_values(array_unique($categories_parent)); } else { $categories = null; } // COPYRIGHTS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'])) { $copyright_url = null; $copyright_label = null; if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) { $copyright_url = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['data'])) { $copyright_label = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['copyright'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $copyrights = $this->registry->create(Copyright::class, [$copyright_url, $copyright_label]); } else { $copyrights = $copyrights_parent; } // CREDITS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['credit'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['credit'] as $credit) { $credit_role = null; $credit_scheme = null; $credit_name = null; if (isset($credit['attribs']['']['role'])) { $credit_role = $this->sanitize($credit['attribs']['']['role'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($credit['attribs']['']['scheme'])) { $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $credit_scheme = 'urn:ebu'; } if (isset($credit['data'])) { $credit_name = $this->sanitize($credit['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $credits[] = $this->registry->create(Credit::class, [$credit_role, $credit_scheme, $credit_name]); } if (is_array($credits)) { $credits = array_values(array_unique($credits)); } } else { $credits = $credits_parent; } // DESCRIPTION if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['description'])) { $description = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['description'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $description = $description_parent; } // HASHES if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['hash'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['hash'] as $hash) { $value = null; $algo = null; if (isset($hash['data'])) { $value = $this->sanitize($hash['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($hash['attribs']['']['algo'])) { $algo = $this->sanitize($hash['attribs']['']['algo'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $algo = 'md5'; } $hashes[] = $algo.':'.$value; } if (is_array($hashes)) { $hashes = array_values(array_unique($hashes)); } } else { $hashes = $hashes_parent; } // KEYWORDS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'])) { if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'][0]['data'])) { $temp = explode(',', $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['keywords'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT)); foreach ($temp as $word) { $keywords[] = trim($word); } unset($temp); } if (is_array($keywords)) { $keywords = array_values(array_unique($keywords)); } } else { $keywords = $keywords_parent; } // PLAYER if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'])) { if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'])) { $player = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } } else { $player = $player_parent; } // RATINGS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['rating'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['rating'] as $rating) { $rating_scheme = null; $rating_value = null; if (isset($rating['attribs']['']['scheme'])) { $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $rating_scheme = 'urn:simple'; } if (isset($rating['data'])) { $rating_value = $this->sanitize($rating['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $ratings[] = $this->registry->create(Rating::class, [$rating_scheme, $rating_value]); } if (is_array($ratings)) { $ratings = array_values(array_unique($ratings)); } } else { $ratings = $ratings_parent; } // RESTRICTIONS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['restriction'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['restriction'] as $restriction) { $restriction_relationship = null; $restriction_type = null; $restriction_value = null; if (isset($restriction['attribs']['']['relationship'])) { $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['attribs']['']['type'])) { $restriction_type = $this->sanitize($restriction['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($restriction['data'])) { $restriction_value = $this->sanitize($restriction['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } $restrictions[] = $this->registry->create(Restriction::class, [$restriction_relationship, $restriction_type, $restriction_value]); } if (is_array($restrictions)) { $restrictions = array_values(array_unique($restrictions)); } } else { $restrictions = $restrictions_parent; } // THUMBNAILS if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'])) { foreach ($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) { if (isset($thumbnail['attribs']['']['url'])) { $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI); } } if (is_array($thumbnails)) { $thumbnails = array_values(array_unique($thumbnails)); } } else { $thumbnails = $thumbnails_parent; } // TITLES if (isset($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['title'])) { $title = $this->sanitize($content['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['title'][0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $title = $title_parent; } $this->data['enclosures'][] = $this->registry->create(Enclosure::class, [$url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width]); } } } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'link') as $link) { if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') { // Attributes $bitrate = null; $channels = null; $duration = null; $expression = null; $framerate = null; $height = null; $javascript = null; $lang = null; $length = null; $medium = null; $samplingrate = null; $type = null; $url = null; $width = null; $url = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); if (isset($link['attribs']['']['type'])) { $type = $this->sanitize($link['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($link['attribs']['']['length'])) { $length = intval($link['attribs']['']['length']); } if (isset($link['attribs']['']['title'])) { $title = $this->sanitize($link['attribs']['']['title'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } else { $title = $title_parent; } // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor $this->data['enclosures'][] = $this->registry->create(Enclosure::class, [$url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title, $width]); } } foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'link') as $link) { if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') { // Attributes $bitrate = null; $channels = null; $duration = null; $expression = null; $framerate = null; $height = null; $javascript = null; $lang = null; $length = null; $medium = null; $samplingrate = null; $type = null; $url = null; $width = null; $url = $this->sanitize($link['attribs']['']['href'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($link)); if (isset($link['attribs']['']['type'])) { $type = $this->sanitize($link['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($link['attribs']['']['length'])) { $length = intval($link['attribs']['']['length']); } // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor $this->data['enclosures'][] = $this->registry->create(Enclosure::class, [$url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width]); } } foreach ($this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'enclosure') ?? [] as $enclosure) { if (isset($enclosure['attribs']['']['url'])) { // Attributes $bitrate = null; $channels = null; $duration = null; $expression = null; $framerate = null; $height = null; $javascript = null; $lang = null; $length = null; $medium = null; $samplingrate = null; $type = null; $url = null; $width = null; $url = $this->sanitize($enclosure['attribs']['']['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($enclosure)); $url = $this->feed->sanitize->https_url($url); if (isset($enclosure['attribs']['']['type'])) { $type = $this->sanitize($enclosure['attribs']['']['type'], \SimplePie\SimplePie::CONSTRUCT_TEXT); } if (isset($enclosure['attribs']['']['length'])) { $length = intval($enclosure['attribs']['']['length']); } // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor $this->data['enclosures'][] = $this->registry->create(Enclosure::class, [$url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width]); } } if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width)) { // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor $this->data['enclosures'][] = $this->registry->create(Enclosure::class, [$url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width]); } $this->data['enclosures'] = array_values(array_unique($this->data['enclosures'])); } if (!empty($this->data['enclosures'])) { return $this->data['enclosures']; } return null; } /** * Get the latitude coordinates for the item * * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications * * Uses `<geo:lat>` or `<georss:point>` * * @since 1.0 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo * @link http://www.georss.org/ GeoRSS * @return string|null */ public function get_latitude() { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_W3C_BASIC_GEO, 'lat')) { return (float) $return[0]['data']; } elseif (($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) { return (float) $match[1]; } return null; } /** * Get the longitude coordinates for the item * * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications * * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>` * * @since 1.0 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo * @link http://www.georss.org/ GeoRSS * @return string|null */ public function get_longitude() { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_W3C_BASIC_GEO, 'long')) { return (float) $return[0]['data']; } elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_W3C_BASIC_GEO, 'lon')) { return (float) $return[0]['data']; } elseif (($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) { return (float) $match[2]; } return null; } /** * Get the `<atom:source>` for the item * * @since 1.1 * @return \SimplePie\Source|null */ public function get_source() { if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'source')) { return $this->registry->create(Source::class, [$this, $return[0]]); } return null; } } class_alias('SimplePie\Item', 'SimplePie_Item'); ��������������������������������������������������������������������������������������������������������������������������������������IRI.php���������������������������������������������������������������������������������������������0000644�����������������00000105473�15021155231�0005705 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; /** * IRI parser/serialiser/normaliser * * @package SimplePie * @subpackage HTTP * @author Sam Sneddon * @author Steve Minutillo * @author Ryan McCue * @copyright 2007-2012 Sam Sneddon, Steve Minutillo, Ryan McCue * @license http://www.opensource.org/licenses/bsd-license.php */ class IRI { /** * Scheme * * @var string */ protected $scheme = null; /** * User Information * * @var string */ protected $iuserinfo = null; /** * ihost * * @var string */ protected $ihost = null; /** * Port * * @var string */ protected $port = null; /** * ipath * * @var string */ protected $ipath = ''; /** * iquery * * @var string */ protected $iquery = null; /** * ifragment * * @var string */ protected $ifragment = null; /** * Normalization database * * Each key is the scheme, each value is an array with each key as the IRI * part and value as the default value for that part. */ protected $normalization = [ 'acap' => [ 'port' => 674 ], 'dict' => [ 'port' => 2628 ], 'file' => [ 'ihost' => 'localhost' ], 'http' => [ 'port' => 80, 'ipath' => '/' ], 'https' => [ 'port' => 443, 'ipath' => '/' ], ]; /** * Return the entire IRI when you try and read the object as a string * * @return string */ public function __toString() { return $this->get_iri(); } /** * Overload __set() to provide access via properties * * @param string $name Property name * @param mixed $value Property value */ public function __set($name, $value) { if (method_exists($this, 'set_' . $name)) { call_user_func([$this, 'set_' . $name], $value); } elseif ( $name === 'iauthority' || $name === 'iuserinfo' || $name === 'ihost' || $name === 'ipath' || $name === 'iquery' || $name === 'ifragment' ) { call_user_func([$this, 'set_' . substr($name, 1)], $value); } } /** * Overload __get() to provide access via properties * * @param string $name Property name * @return mixed */ public function __get($name) { // isset() returns false for null, we don't want to do that // Also why we use array_key_exists below instead of isset() $props = get_object_vars($this); if ( $name === 'iri' || $name === 'uri' || $name === 'iauthority' || $name === 'authority' ) { $return = $this->{"get_$name"}(); } elseif (array_key_exists($name, $props)) { $return = $this->$name; } // host -> ihost elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) { $name = $prop; $return = $this->$prop; } // ischeme -> scheme elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) { $name = $prop; $return = $this->$prop; } else { trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); $return = null; } if ($return === null && isset($this->normalization[$this->scheme][$name])) { return $this->normalization[$this->scheme][$name]; } return $return; } /** * Overload __isset() to provide access via properties * * @param string $name Property name * @return bool */ public function __isset($name) { return method_exists($this, 'get_' . $name) || isset($this->$name); } /** * Overload __unset() to provide access via properties * * @param string $name Property name */ public function __unset($name) { if (method_exists($this, 'set_' . $name)) { call_user_func([$this, 'set_' . $name], ''); } } /** * Create a new IRI object, from a specified string * * @param string $iri */ public function __construct($iri = null) { $this->set_iri($iri); } /** * Clean up */ public function __destruct() { $this->set_iri(null, true); $this->set_path(null, true); $this->set_authority(null, true); } /** * Create a new IRI object by resolving a relative IRI * * Returns false if $base is not absolute, otherwise an IRI. * * @param IRI|string $base (Absolute) Base IRI * @param IRI|string $relative Relative IRI * @return IRI|false */ public static function absolutize($base, $relative) { if (!($relative instanceof IRI)) { $relative = new IRI($relative); } if (!$relative->is_valid()) { return false; } elseif ($relative->scheme !== null) { return clone $relative; } else { if (!($base instanceof IRI)) { $base = new IRI($base); } if ($base->scheme !== null && $base->is_valid()) { if ($relative->get_iri() !== '') { if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) { $target = clone $relative; $target->scheme = $base->scheme; } else { $target = new IRI(); $target->scheme = $base->scheme; $target->iuserinfo = $base->iuserinfo; $target->ihost = $base->ihost; $target->port = $base->port; if ($relative->ipath !== '') { if ($relative->ipath[0] === '/') { $target->ipath = $relative->ipath; } elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') { $target->ipath = '/' . $relative->ipath; } elseif (($last_segment = strrpos($base->ipath, '/')) !== false) { $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; } else { $target->ipath = $relative->ipath; } $target->ipath = $target->remove_dot_segments($target->ipath); $target->iquery = $relative->iquery; } else { $target->ipath = $base->ipath; if ($relative->iquery !== null) { $target->iquery = $relative->iquery; } elseif ($base->iquery !== null) { $target->iquery = $base->iquery; } } $target->ifragment = $relative->ifragment; } } else { $target = clone $base; $target->ifragment = null; } $target->scheme_normalization(); return $target; } return false; } } /** * Parse an IRI into scheme/authority/path/query/fragment segments * * @param string $iri * @return array */ protected function parse_iri($iri) { $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match)) { if ($match[1] === '') { $match['scheme'] = null; } if (!isset($match[3]) || $match[3] === '') { $match['authority'] = null; } if (!isset($match[5])) { $match['path'] = ''; } if (!isset($match[6]) || $match[6] === '') { $match['query'] = null; } if (!isset($match[8]) || $match[8] === '') { $match['fragment'] = null; } return $match; } // This can occur when a paragraph is accidentally parsed as a URI return false; } /** * Remove dot segments from a path * * @param string $input * @return string */ protected function remove_dot_segments($input) { $output = ''; while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') { // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, if (strpos($input, '../') === 0) { $input = substr($input, 3); } elseif (strpos($input, './') === 0) { $input = substr($input, 2); } // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, elseif (strpos($input, '/./') === 0) { $input = substr($input, 2); } elseif ($input === '/.') { $input = '/'; } // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, elseif (strpos($input, '/../') === 0) { $input = substr($input, 3); $output = substr_replace($output, '', intval(strrpos($output, '/'))); } elseif ($input === '/..') { $input = '/'; $output = substr_replace($output, '', intval(strrpos($output, '/'))); } // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, elseif ($input === '.' || $input === '..') { $input = ''; } // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer elseif (($pos = strpos($input, '/', 1)) !== false) { $output .= substr($input, 0, $pos); $input = substr_replace($input, '', 0, $pos); } else { $output .= $input; $input = ''; } } return $output . $input; } /** * Replace invalid character with percent encoding * * @param string $string Input string * @param string $extra_chars Valid characters not in iunreserved or * iprivate (this is ASCII-only) * @param bool $iprivate Allow iprivate * @return string */ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) { // Normalize as many pct-encoded sections as possible $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', [$this, 'remove_iunreserved_percent_encoded'], $string); // Replace invalid percent characters $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); // Add unreserved and % to $extra_chars (the latter is safe because all // pct-encoded sections are now valid). $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; // Now replace any bytes that aren't allowed with their pct-encoded versions $position = 0; $strlen = strlen($string); while (($position += strspn($string, $extra_chars, $position)) < $strlen) { $value = ord($string[$position]); $character = 0; // Start position $start = $position; // By default we are valid $valid = true; // No one byte sequences are valid due to the while. // Two byte sequence: if (($value & 0xE0) === 0xC0) { $character = ($value & 0x1F) << 6; $length = 2; $remaining = 1; } // Three byte sequence: elseif (($value & 0xF0) === 0xE0) { $character = ($value & 0x0F) << 12; $length = 3; $remaining = 2; } // Four byte sequence: elseif (($value & 0xF8) === 0xF0) { $character = ($value & 0x07) << 18; $length = 4; $remaining = 3; } // Invalid byte: else { $valid = false; $length = 1; $remaining = 0; } if ($remaining) { if ($position + $length <= $strlen) { for ($position++; $remaining; $position++) { $value = ord($string[$position]); // Check that the byte is valid, then add it to the character: if (($value & 0xC0) === 0x80) { $character |= ($value & 0x3F) << (--$remaining * 6); } // If it is invalid, count the sequence as invalid and reprocess the current byte: else { $valid = false; $position--; break; } } } else { $position = $strlen - 1; $valid = false; } } // Percent encode anything invalid or not in ucschar if ( // Invalid sequences !$valid // Non-shortest form sequences are invalid || $length > 1 && $character <= 0x7F || $length > 2 && $character <= 0x7FF || $length > 3 && $character <= 0xFFFF // Outside of range of ucschar codepoints // Noncharacters || ($character & 0xFFFE) === 0xFFFE || $character >= 0xFDD0 && $character <= 0xFDEF || ( // Everything else not in ucschar $character > 0xD7FF && $character < 0xF900 || $character < 0xA0 || $character > 0xEFFFD ) && ( // Everything not in iprivate, if it applies !$iprivate || $character < 0xE000 || $character > 0x10FFFD ) ) { // If we were a character, pretend we weren't, but rather an error. if ($valid) { $position--; } for ($j = $start; $j <= $position; $j++) { $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); $j += 2; $position += 2; $strlen += 2; } } } return $string; } /** * Callback function for preg_replace_callback. * * Removes sequences of percent encoded bytes that represent UTF-8 * encoded characters in iunreserved * * @param array $match PCRE match * @return string Replacement */ protected function remove_iunreserved_percent_encoded($match) { // As we just have valid percent encoded sequences we can just explode // and ignore the first member of the returned array (an empty string). $bytes = explode('%', $match[0]); // Initialize the new string (this is what will be returned) and that // there are no bytes remaining in the current sequence (unsurprising // at the first byte!). $string = ''; $remaining = 0; // these variables will be initialized in the loop but PHPStan is not able to detect it currently $start = 0; $character = 0; $length = 0; $valid = true; // Loop over each and every byte, and set $value to its value for ($i = 1, $len = count($bytes); $i < $len; $i++) { $value = hexdec($bytes[$i]); // If we're the first byte of sequence: if (!$remaining) { // Start position $start = $i; // By default we are valid $valid = true; // One byte sequence: if ($value <= 0x7F) { $character = $value; $length = 1; } // Two byte sequence: elseif (($value & 0xE0) === 0xC0) { $character = ($value & 0x1F) << 6; $length = 2; $remaining = 1; } // Three byte sequence: elseif (($value & 0xF0) === 0xE0) { $character = ($value & 0x0F) << 12; $length = 3; $remaining = 2; } // Four byte sequence: elseif (($value & 0xF8) === 0xF0) { $character = ($value & 0x07) << 18; $length = 4; $remaining = 3; } // Invalid byte: else { $valid = false; $remaining = 0; } } // Continuation byte: else { // Check that the byte is valid, then add it to the character: if (($value & 0xC0) === 0x80) { $remaining--; $character |= ($value & 0x3F) << ($remaining * 6); } // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: else { $valid = false; $remaining = 0; $i--; } } // If we've reached the end of the current byte sequence, append it to Unicode::$data if (!$remaining) { // Percent encode anything invalid or not in iunreserved if ( // Invalid sequences !$valid // Non-shortest form sequences are invalid || $length > 1 && $character <= 0x7F || $length > 2 && $character <= 0x7FF || $length > 3 && $character <= 0xFFFF // Outside of range of iunreserved codepoints || $character < 0x2D || $character > 0xEFFFD // Noncharacters || ($character & 0xFFFE) === 0xFFFE || $character >= 0xFDD0 && $character <= 0xFDEF // Everything else not in iunreserved (this is all BMP) || $character === 0x2F || $character > 0x39 && $character < 0x41 || $character > 0x5A && $character < 0x61 || $character > 0x7A && $character < 0x7E || $character > 0x7E && $character < 0xA0 || $character > 0xD7FF && $character < 0xF900 ) { for ($j = $start; $j <= $i; $j++) { $string .= '%' . strtoupper($bytes[$j]); } } else { for ($j = $start; $j <= $i; $j++) { $string .= chr(hexdec($bytes[$j])); } } } } // If we have any bytes left over they are invalid (i.e., we are // mid-way through a multi-byte sequence) if ($remaining) { for ($j = $start; $j < $len; $j++) { $string .= '%' . strtoupper($bytes[$j]); } } return $string; } protected function scheme_normalization() { if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) { $this->iuserinfo = null; } if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) { $this->ihost = null; } if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) { $this->port = null; } if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) { $this->ipath = ''; } if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) { $this->iquery = null; } if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) { $this->ifragment = null; } } /** * Check if the object represents a valid IRI. This needs to be done on each * call as some things change depending on another part of the IRI. * * @return bool */ public function is_valid() { if ($this->ipath === '') { return true; } $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; if ($isauthority && $this->ipath[0] === '/') { return true; } if (!$isauthority && (substr($this->ipath, 0, 2) === '//')) { return false; } // Relative urls cannot have a colon in the first path segment (and the // slashes themselves are not included so skip the first character). if (!$this->scheme && !$isauthority && strpos($this->ipath, ':') !== false && strpos($this->ipath, '/', 1) !== false && strpos($this->ipath, ':') < strpos($this->ipath, '/', 1)) { return false; } return true; } /** * Set the entire IRI. Returns true on success, false on failure (if there * are any invalid characters). * * @param string $iri * @return bool */ public function set_iri($iri, $clear_cache = false) { static $cache; if ($clear_cache) { $cache = null; return; } if (!$cache) { $cache = []; } if ($iri === null) { return true; } elseif (isset($cache[$iri])) { [ $this->scheme, $this->iuserinfo, $this->ihost, $this->port, $this->ipath, $this->iquery, $this->ifragment, $return ] = $cache[$iri]; return $return; } $parsed = $this->parse_iri((string) $iri); if (!$parsed) { return false; } $return = $this->set_scheme($parsed['scheme']) && $this->set_authority($parsed['authority']) && $this->set_path($parsed['path']) && $this->set_query($parsed['query']) && $this->set_fragment($parsed['fragment']); $cache[$iri] = [ $this->scheme, $this->iuserinfo, $this->ihost, $this->port, $this->ipath, $this->iquery, $this->ifragment, $return ]; return $return; } /** * Set the scheme. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $scheme * @return bool */ public function set_scheme($scheme) { if ($scheme === null) { $this->scheme = null; } elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) { $this->scheme = null; return false; } else { $this->scheme = strtolower($scheme); } return true; } /** * Set the authority. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $authority * @return bool */ public function set_authority($authority, $clear_cache = false) { static $cache; if ($clear_cache) { $cache = null; return; } if (!$cache) { $cache = []; } if ($authority === null) { $this->iuserinfo = null; $this->ihost = null; $this->port = null; return true; } elseif (isset($cache[$authority])) { [ $this->iuserinfo, $this->ihost, $this->port, $return ] = $cache[$authority]; return $return; } $remaining = $authority; if (($iuserinfo_end = strrpos($remaining, '@')) !== false) { $iuserinfo = substr($remaining, 0, $iuserinfo_end); $remaining = substr($remaining, $iuserinfo_end + 1); } else { $iuserinfo = null; } if (($port_start = strpos($remaining, ':', intval(strpos($remaining, ']')))) !== false) { if (($port = substr($remaining, $port_start + 1)) === false) { $port = null; } $remaining = substr($remaining, 0, $port_start); } else { $port = null; } $return = $this->set_userinfo($iuserinfo) && $this->set_host($remaining) && $this->set_port($port); $cache[$authority] = [ $this->iuserinfo, $this->ihost, $this->port, $return ]; return $return; } /** * Set the iuserinfo. * * @param string $iuserinfo * @return bool */ public function set_userinfo($iuserinfo) { if ($iuserinfo === null) { $this->iuserinfo = null; } else { $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:'); $this->scheme_normalization(); } return true; } /** * Set the ihost. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $ihost * @return bool */ public function set_host($ihost) { if ($ihost === null) { $this->ihost = null; return true; } elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') { if (\SimplePie\Net\IPv6::check_ipv6(substr($ihost, 1, -1))) { $this->ihost = '[' . \SimplePie\Net\IPv6::compress(substr($ihost, 1, -1)) . ']'; } else { $this->ihost = null; return false; } } else { $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;='); // Lowercase, but ignore pct-encoded sections (as they should // remain uppercase). This must be done after the previous step // as that can add unescaped characters. $position = 0; $strlen = strlen($ihost); while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) { if ($ihost[$position] === '%') { $position += 3; } else { $ihost[$position] = strtolower($ihost[$position]); $position++; } } $this->ihost = $ihost; } $this->scheme_normalization(); return true; } /** * Set the port. Returns true on success, false on failure (if there are * any invalid characters). * * @param string $port * @return bool */ public function set_port($port) { if ($port === null) { $this->port = null; return true; } elseif (strspn($port, '0123456789') === strlen($port)) { $this->port = (int) $port; $this->scheme_normalization(); return true; } $this->port = null; return false; } /** * Set the ipath. * * @param string $ipath * @return bool */ public function set_path($ipath, $clear_cache = false) { static $cache; if ($clear_cache) { $cache = null; return; } if (!$cache) { $cache = []; } $ipath = (string) $ipath; if (isset($cache[$ipath])) { $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; } else { $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/'); $removed = $this->remove_dot_segments($valid); $cache[$ipath] = [$valid, $removed]; $this->ipath = ($this->scheme !== null) ? $removed : $valid; } $this->scheme_normalization(); return true; } /** * Set the iquery. * * @param string $iquery * @return bool */ public function set_query($iquery) { if ($iquery === null) { $this->iquery = null; } else { $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true); $this->scheme_normalization(); } return true; } /** * Set the ifragment. * * @param string $ifragment * @return bool */ public function set_fragment($ifragment) { if ($ifragment === null) { $this->ifragment = null; } else { $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?'); $this->scheme_normalization(); } return true; } /** * Convert an IRI to a URI (or parts thereof) * * @return string */ public function to_uri($string) { static $non_ascii; if (!$non_ascii) { $non_ascii = implode('', range("\x80", "\xFF")); } $position = 0; $strlen = strlen($string); while (($position += strcspn($string, $non_ascii, $position)) < $strlen) { $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); $position += 3; $strlen += 2; } return $string; } /** * Get the complete IRI * * @return string */ public function get_iri() { if (!$this->is_valid()) { return false; } $iri = ''; if ($this->scheme !== null) { $iri .= $this->scheme . ':'; } if (($iauthority = $this->get_iauthority()) !== null) { $iri .= '//' . $iauthority; } if ($this->ipath !== '') { $iri .= $this->ipath; } elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '') { $iri .= $this->normalization[$this->scheme]['ipath']; } if ($this->iquery !== null) { $iri .= '?' . $this->iquery; } if ($this->ifragment !== null) { $iri .= '#' . $this->ifragment; } return $iri; } /** * Get the complete URI * * @return string */ public function get_uri() { return $this->to_uri($this->get_iri()); } /** * Get the complete iauthority * * @return string */ protected function get_iauthority() { if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null) { $iauthority = ''; if ($this->iuserinfo !== null) { $iauthority .= $this->iuserinfo . '@'; } if ($this->ihost !== null) { $iauthority .= $this->ihost; } if ($this->port !== null && $this->port !== 0) { $iauthority .= ':' . $this->port; } return $iauthority; } return null; } /** * Get the complete authority * * @return string */ protected function get_authority() { $iauthority = $this->get_iauthority(); if (is_string($iauthority)) { return $this->to_uri($iauthority); } return $iauthority; } } class_alias('SimplePie\IRI', 'SimplePie_IRI'); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������HTTP/Parser.php�������������������������������������������������������������������������������������0000644�����������������00000035073�15021155231�0007273 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie\HTTP; /** * HTTP Response Parser * * @package SimplePie * @subpackage HTTP */ class Parser { /** * HTTP Version * * @var float */ public $http_version = 0.0; /** * Status code * * @var int */ public $status_code = 0; /** * Reason phrase * * @var string */ public $reason = ''; /** * Key/value pairs of the headers * * @var array */ public $headers = []; /** * Body of the response * * @var string */ public $body = ''; private const STATE_HTTP_VERSION = 'http_version'; private const STATE_STATUS = 'status'; private const STATE_REASON = 'reason'; private const STATE_NEW_LINE = 'new_line'; private const STATE_BODY = 'body'; private const STATE_NAME = 'name'; private const STATE_VALUE = 'value'; private const STATE_VALUE_CHAR = 'value_char'; private const STATE_QUOTE = 'quote'; private const STATE_QUOTE_ESCAPED = 'quote_escaped'; private const STATE_QUOTE_CHAR = 'quote_char'; private const STATE_CHUNKED = 'chunked'; private const STATE_EMIT = 'emit'; private const STATE_ERROR = false; /** * Current state of the state machine * * @var self::STATE_* */ protected $state = self::STATE_HTTP_VERSION; /** * Input data * * @var string */ protected $data = ''; /** * Input data length (to avoid calling strlen() everytime this is needed) * * @var int */ protected $data_length = 0; /** * Current position of the pointer * * @var int */ protected $position = 0; /** * Name of the hedaer currently being parsed * * @var string */ protected $name = ''; /** * Value of the hedaer currently being parsed * * @var string */ protected $value = ''; /** * Create an instance of the class with the input data * * @param string $data Input data */ public function __construct($data) { $this->data = $data; $this->data_length = strlen($this->data); } /** * Parse the input data * * @return bool true on success, false on failure */ public function parse() { while ($this->state && $this->state !== self::STATE_EMIT && $this->has_data()) { $state = $this->state; $this->$state(); } $this->data = ''; if ($this->state === self::STATE_EMIT || $this->state === self::STATE_BODY) { return true; } $this->http_version = ''; $this->status_code = 0; $this->reason = ''; $this->headers = []; $this->body = ''; return false; } /** * Check whether there is data beyond the pointer * * @return bool true if there is further data, false if not */ protected function has_data() { return (bool) ($this->position < $this->data_length); } /** * See if the next character is LWS * * @return bool true if the next character is LWS, false if not */ protected function is_linear_whitespace() { return (bool) ($this->data[$this->position] === "\x09" || $this->data[$this->position] === "\x20" || ($this->data[$this->position] === "\x0A" && isset($this->data[$this->position + 1]) && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20"))); } /** * Parse the HTTP version */ protected function http_version() { if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/') { $len = strspn($this->data, '0123456789.', 5); $this->http_version = substr($this->data, 5, $len); $this->position += 5 + $len; if (substr_count($this->http_version, '.') <= 1) { $this->http_version = (float) $this->http_version; $this->position += strspn($this->data, "\x09\x20", $this->position); $this->state = self::STATE_STATUS; } else { $this->state = self::STATE_ERROR; } } else { $this->state = self::STATE_ERROR; } } /** * Parse the status code */ protected function status() { if ($len = strspn($this->data, '0123456789', $this->position)) { $this->status_code = (int) substr($this->data, $this->position, $len); $this->position += $len; $this->state = self::STATE_REASON; } else { $this->state = self::STATE_ERROR; } } /** * Parse the reason phrase */ protected function reason() { $len = strcspn($this->data, "\x0A", $this->position); $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20"); $this->position += $len + 1; $this->state = self::STATE_NEW_LINE; } /** * Deal with a new line, shifting data around as needed */ protected function new_line() { $this->value = trim($this->value, "\x0D\x20"); if ($this->name !== '' && $this->value !== '') { $this->name = strtolower($this->name); // We should only use the last Content-Type header. c.f. issue #1 if (isset($this->headers[$this->name]) && $this->name !== 'content-type') { $this->headers[$this->name] .= ', ' . $this->value; } else { $this->headers[$this->name] = $this->value; } } $this->name = ''; $this->value = ''; if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A") { $this->position += 2; $this->state = self::STATE_BODY; } elseif ($this->data[$this->position] === "\x0A") { $this->position++; $this->state = self::STATE_BODY; } else { $this->state = self::STATE_NAME; } } /** * Parse a header name */ protected function name() { $len = strcspn($this->data, "\x0A:", $this->position); if (isset($this->data[$this->position + $len])) { if ($this->data[$this->position + $len] === "\x0A") { $this->position += $len; $this->state = self::STATE_NEW_LINE; } else { $this->name = substr($this->data, $this->position, $len); $this->position += $len + 1; $this->state = self::STATE_VALUE; } } else { $this->state = self::STATE_ERROR; } } /** * Parse LWS, replacing consecutive LWS characters with a single space */ protected function linear_whitespace() { do { if (substr($this->data, $this->position, 2) === "\x0D\x0A") { $this->position += 2; } elseif ($this->data[$this->position] === "\x0A") { $this->position++; } $this->position += strspn($this->data, "\x09\x20", $this->position); } while ($this->has_data() && $this->is_linear_whitespace()); $this->value .= "\x20"; } /** * See what state to move to while within non-quoted header values */ protected function value() { if ($this->is_linear_whitespace()) { $this->linear_whitespace(); } else { switch ($this->data[$this->position]) { case '"': // Workaround for ETags: we have to include the quotes as // part of the tag. if (strtolower($this->name) === 'etag') { $this->value .= '"'; $this->position++; $this->state = self::STATE_VALUE_CHAR; break; } $this->position++; $this->state = self::STATE_QUOTE; break; case "\x0A": $this->position++; $this->state = self::STATE_NEW_LINE; break; default: $this->state = self::STATE_VALUE_CHAR; break; } } } /** * Parse a header value while outside quotes */ protected function value_char() { $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position); $this->value .= substr($this->data, $this->position, $len); $this->position += $len; $this->state = self::STATE_VALUE; } /** * See what state to move to while within quoted header values */ protected function quote() { if ($this->is_linear_whitespace()) { $this->linear_whitespace(); } else { switch ($this->data[$this->position]) { case '"': $this->position++; $this->state = self::STATE_VALUE; break; case "\x0A": $this->position++; $this->state = self::STATE_NEW_LINE; break; case '\\': $this->position++; $this->state = self::STATE_QUOTE_ESCAPED; break; default: $this->state = self::STATE_QUOTE_CHAR; break; } } } /** * Parse a header value while within quotes */ protected function quote_char() { $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position); $this->value .= substr($this->data, $this->position, $len); $this->position += $len; $this->state = self::STATE_VALUE; } /** * Parse an escaped character within quotes */ protected function quote_escaped() { $this->value .= $this->data[$this->position]; $this->position++; $this->state = self::STATE_QUOTE; } /** * Parse the body */ protected function body() { $this->body = substr($this->data, $this->position); if (!empty($this->headers['transfer-encoding'])) { unset($this->headers['transfer-encoding']); $this->state = self::STATE_CHUNKED; } else { $this->state = self::STATE_EMIT; } } /** * Parsed a "Transfer-Encoding: chunked" body */ protected function chunked() { if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body))) { $this->state = self::STATE_EMIT; return; } $decoded = ''; $encoded = $this->body; while (true) { $is_chunked = (bool) preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches); if (!$is_chunked) { // Looks like it's not chunked after all $this->state = self::STATE_EMIT; return; } $length = hexdec(trim($matches[1])); if ($length === 0) { // Ignore trailer headers $this->state = self::STATE_EMIT; $this->body = $decoded; return; } $chunk_length = strlen($matches[0]); $decoded .= substr($encoded, $chunk_length, $length); $encoded = substr($encoded, $chunk_length + $length + 2); // BC for PHP < 8.0: substr() can return bool instead of string $encoded = ($encoded === false) ? '' : $encoded; if (trim($encoded) === '0' || empty($encoded)) { $this->state = self::STATE_EMIT; $this->body = $decoded; return; } } } /** * Prepare headers (take care of proxies headers) * * @param string $headers Raw headers * @param integer $count Redirection count. Default to 1. * * @return string */ public static function prepareHeaders($headers, $count = 1) { $data = explode("\r\n\r\n", $headers, $count); $data = array_pop($data); if (false !== stripos($data, "HTTP/1.0 200 Connection established\r\n")) { $exploded = explode("\r\n\r\n", $data, 2); $data = end($exploded); } if (false !== stripos($data, "HTTP/1.1 200 Connection established\r\n")) { $exploded = explode("\r\n\r\n", $data, 2); $data = end($exploded); } return $data; } } class_alias('SimplePie\HTTP\Parser', 'SimplePie_HTTP_Parser'); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SimplePie.php���������������������������������������������������������������������������������������0000644�����������������00000352313�15021155231�0007146 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; use InvalidArgumentException; use Psr\SimpleCache\CacheInterface; use SimplePie\Cache\Base; use SimplePie\Cache\BaseDataCache; use SimplePie\Cache\CallableNameFilter; use SimplePie\Cache\DataCache; use SimplePie\Cache\NameFilter; use SimplePie\Cache\Psr16; use SimplePie\Content\Type\Sniffer; /** * SimplePie * * @package SimplePie * @subpackage API */ class SimplePie { /** * SimplePie Name */ public const NAME = 'SimplePie'; /** * SimplePie Version */ public const VERSION = '1.8.0'; /** * SimplePie Website URL */ public const URL = 'http://simplepie.org'; /** * SimplePie Linkback */ public const LINKBACK = '<a href="' . self::URL . '" title="' . self::NAME . ' ' . self::VERSION . '">' . self::NAME . '</a>'; /** * No Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_NONE = 0; /** * Feed Link Element Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_AUTODISCOVERY = 1; /** * Local Feed Extension Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_LOCAL_EXTENSION = 2; /** * Local Feed Body Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_LOCAL_BODY = 4; /** * Remote Feed Extension Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_REMOTE_EXTENSION = 8; /** * Remote Feed Body Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_REMOTE_BODY = 16; /** * All Feed Autodiscovery * @see SimplePie::set_autodiscovery_level() */ public const LOCATOR_ALL = 31; /** * No known feed type */ public const TYPE_NONE = 0; /** * RSS 0.90 */ public const TYPE_RSS_090 = 1; /** * RSS 0.91 (Netscape) */ public const TYPE_RSS_091_NETSCAPE = 2; /** * RSS 0.91 (Userland) */ public const TYPE_RSS_091_USERLAND = 4; /** * RSS 0.91 (both Netscape and Userland) */ public const TYPE_RSS_091 = 6; /** * RSS 0.92 */ public const TYPE_RSS_092 = 8; /** * RSS 0.93 */ public const TYPE_RSS_093 = 16; /** * RSS 0.94 */ public const TYPE_RSS_094 = 32; /** * RSS 1.0 */ public const TYPE_RSS_10 = 64; /** * RSS 2.0 */ public const TYPE_RSS_20 = 128; /** * RDF-based RSS */ public const TYPE_RSS_RDF = 65; /** * Non-RDF-based RSS (truly intended as syndication format) */ public const TYPE_RSS_SYNDICATION = 190; /** * All RSS */ public const TYPE_RSS_ALL = 255; /** * Atom 0.3 */ public const TYPE_ATOM_03 = 256; /** * Atom 1.0 */ public const TYPE_ATOM_10 = 512; /** * All Atom */ public const TYPE_ATOM_ALL = 768; /** * All feed types */ public const TYPE_ALL = 1023; /** * No construct */ public const CONSTRUCT_NONE = 0; /** * Text construct */ public const CONSTRUCT_TEXT = 1; /** * HTML construct */ public const CONSTRUCT_HTML = 2; /** * XHTML construct */ public const CONSTRUCT_XHTML = 4; /** * base64-encoded construct */ public const CONSTRUCT_BASE64 = 8; /** * IRI construct */ public const CONSTRUCT_IRI = 16; /** * A construct that might be HTML */ public const CONSTRUCT_MAYBE_HTML = 32; /** * All constructs */ public const CONSTRUCT_ALL = 63; /** * Don't change case */ public const SAME_CASE = 1; /** * Change to lowercase */ public const LOWERCASE = 2; /** * Change to uppercase */ public const UPPERCASE = 4; /** * PCRE for HTML attributes */ public const PCRE_HTML_ATTRIBUTE = '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*'; /** * PCRE for XML attributes */ public const PCRE_XML_ATTRIBUTE = '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*'; /** * XML Namespace */ public const NAMESPACE_XML = 'http://www.w3.org/XML/1998/namespace'; /** * Atom 1.0 Namespace */ public const NAMESPACE_ATOM_10 = 'http://www.w3.org/2005/Atom'; /** * Atom 0.3 Namespace */ public const NAMESPACE_ATOM_03 = 'http://purl.org/atom/ns#'; /** * RDF Namespace */ public const NAMESPACE_RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; /** * RSS 0.90 Namespace */ public const NAMESPACE_RSS_090 = 'http://my.netscape.com/rdf/simple/0.9/'; /** * RSS 1.0 Namespace */ public const NAMESPACE_RSS_10 = 'http://purl.org/rss/1.0/'; /** * RSS 1.0 Content Module Namespace */ public const NAMESPACE_RSS_10_MODULES_CONTENT = 'http://purl.org/rss/1.0/modules/content/'; /** * RSS 2.0 Namespace * (Stupid, I know, but I'm certain it will confuse people less with support.) */ public const NAMESPACE_RSS_20 = ''; /** * DC 1.0 Namespace */ public const NAMESPACE_DC_10 = 'http://purl.org/dc/elements/1.0/'; /** * DC 1.1 Namespace */ public const NAMESPACE_DC_11 = 'http://purl.org/dc/elements/1.1/'; /** * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace */ public const NAMESPACE_W3C_BASIC_GEO = 'http://www.w3.org/2003/01/geo/wgs84_pos#'; /** * GeoRSS Namespace */ public const NAMESPACE_GEORSS = 'http://www.georss.org/georss'; /** * Media RSS Namespace */ public const NAMESPACE_MEDIARSS = 'http://search.yahoo.com/mrss/'; /** * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec. */ public const NAMESPACE_MEDIARSS_WRONG = 'http://search.yahoo.com/mrss'; /** * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5. */ public const NAMESPACE_MEDIARSS_WRONG2 = 'http://video.search.yahoo.com/mrss'; /** * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace. */ public const NAMESPACE_MEDIARSS_WRONG3 = 'http://video.search.yahoo.com/mrss/'; /** * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace. */ public const NAMESPACE_MEDIARSS_WRONG4 = 'http://www.rssboard.org/media-rss'; /** * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL. */ public const NAMESPACE_MEDIARSS_WRONG5 = 'http://www.rssboard.org/media-rss/'; /** * iTunes RSS Namespace */ public const NAMESPACE_ITUNES = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; /** * XHTML Namespace */ public const NAMESPACE_XHTML = 'http://www.w3.org/1999/xhtml'; /** * IANA Link Relations Registry */ public const IANA_LINK_RELATIONS_REGISTRY = 'http://www.iana.org/assignments/relation/'; /** * No file source */ public const FILE_SOURCE_NONE = 0; /** * Remote file source */ public const FILE_SOURCE_REMOTE = 1; /** * Local file source */ public const FILE_SOURCE_LOCAL = 2; /** * fsockopen() file source */ public const FILE_SOURCE_FSOCKOPEN = 4; /** * cURL file source */ public const FILE_SOURCE_CURL = 8; /** * file_get_contents() file source */ public const FILE_SOURCE_FILE_GET_CONTENTS = 16; /** * @var array Raw data * @access private */ public $data = []; /** * @var mixed Error string * @access private */ public $error; /** * @var int HTTP status code * @see SimplePie::status_code() * @access private */ public $status_code = 0; /** * @var object Instance of \SimplePie\Sanitize (or other class) * @see SimplePie::set_sanitize_class() * @access private */ public $sanitize; /** * @var string SimplePie Useragent * @see SimplePie::set_useragent() * @access private */ public $useragent = ''; /** * @var string Feed URL * @see SimplePie::set_feed_url() * @access private */ public $feed_url; /** * @var string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently * @see SimplePie::subscribe_url() * @access private */ public $permanent_url = null; /** * @var object Instance of \SimplePie\File to use as a feed * @see SimplePie::set_file() * @access private */ public $file; /** * @var string Raw feed data * @see SimplePie::set_raw_data() * @access private */ public $raw_data; /** * @var int Timeout for fetching remote files * @see SimplePie::set_timeout() * @access private */ public $timeout = 10; /** * @var array Custom curl options * @see SimplePie::set_curl_options() * @access private */ public $curl_options = []; /** * @var bool Forces fsockopen() to be used for remote files instead * of cURL, even if a new enough version is installed * @see SimplePie::force_fsockopen() * @access private */ public $force_fsockopen = false; /** * @var bool Force the given data/URL to be treated as a feed no matter what * it appears like * @see SimplePie::force_feed() * @access private */ public $force_feed = false; /** * @var bool Enable/Disable Caching * @see SimplePie::enable_cache() * @access private */ private $enable_cache = true; /** * @var DataCache|null * @see SimplePie::set_cache() */ private $cache = null; /** * @var NameFilter * @see SimplePie::set_cache_namefilter() */ private $cache_namefilter; /** * @var bool Force SimplePie to fallback to expired cache, if enabled, * when feed is unavailable. * @see SimplePie::force_cache_fallback() * @access private */ public $force_cache_fallback = false; /** * @var int Cache duration (in seconds) * @see SimplePie::set_cache_duration() * @access private */ public $cache_duration = 3600; /** * @var int Auto-discovery cache duration (in seconds) * @see SimplePie::set_autodiscovery_cache_duration() * @access private */ public $autodiscovery_cache_duration = 604800; // 7 Days. /** * @var string Cache location (relative to executing script) * @see SimplePie::set_cache_location() * @access private */ public $cache_location = './cache'; /** * @var string Function that creates the cache filename * @see SimplePie::set_cache_name_function() * @access private */ public $cache_name_function = 'md5'; /** * @var bool Reorder feed by date descending * @see SimplePie::enable_order_by_date() * @access private */ public $order_by_date = true; /** * @var mixed Force input encoding to be set to the follow value * (false, or anything type-cast to false, disables this feature) * @see SimplePie::set_input_encoding() * @access private */ public $input_encoding = false; /** * @var int Feed Autodiscovery Level * @see SimplePie::set_autodiscovery_level() * @access private */ public $autodiscovery = self::LOCATOR_ALL; /** * Class registry object * * @var \SimplePie\Registry */ public $registry; /** * @var int Maximum number of feeds to check with autodiscovery * @see SimplePie::set_max_checked_feeds() * @access private */ public $max_checked_feeds = 10; /** * @var array All the feeds found during the autodiscovery process * @see SimplePie::get_all_discovered_feeds() * @access private */ public $all_discovered_feeds = []; /** * @var string Web-accessible path to the handler_image.php file. * @see SimplePie::set_image_handler() * @access private */ public $image_handler = ''; /** * @var array Stores the URLs when multiple feeds are being initialized. * @see SimplePie::set_feed_url() * @access private */ public $multifeed_url = []; /** * @var array Stores SimplePie objects when multiple feeds initialized. * @access private */ public $multifeed_objects = []; /** * @var array Stores the get_object_vars() array for use with multifeeds. * @see SimplePie::set_feed_url() * @access private */ public $config_settings = null; /** * @var integer Stores the number of items to return per-feed with multifeeds. * @see SimplePie::set_item_limit() * @access private */ public $item_limit = 0; /** * @var bool Stores if last-modified and/or etag headers were sent with the * request when checking a feed. */ public $check_modified = false; /** * @var array Stores the default attributes to be stripped by strip_attributes(). * @see SimplePie::strip_attributes() * @access private */ public $strip_attributes = ['bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc']; /** * @var array Stores the default attributes to add to different tags by add_attributes(). * @see SimplePie::add_attributes() * @access private */ public $add_attributes = ['audio' => ['preload' => 'none'], 'iframe' => ['sandbox' => 'allow-scripts allow-same-origin'], 'video' => ['preload' => 'none']]; /** * @var array Stores the default tags to be stripped by strip_htmltags(). * @see SimplePie::strip_htmltags() * @access private */ public $strip_htmltags = ['base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style']; /** * @var array Stores the default attributes to be renamed by rename_attributes(). * @see SimplePie::rename_attributes() * @access private */ public $rename_attributes = []; /** * @var bool Should we throw exceptions, or use the old-style error property? * @access private */ public $enable_exceptions = false; /** * The SimplePie class contains feed level data and options * * To use SimplePie, create the SimplePie object with no parameters. You can * then set configuration options using the provided methods. After setting * them, you must initialise the feed using $feed->init(). At that point the * object's methods and properties will be available to you. * * Previously, it was possible to pass in the feed URL along with cache * options directly into the constructor. This has been removed as of 1.3 as * it caused a lot of confusion. * * @since 1.0 Preview Release */ public function __construct() { if (version_compare(PHP_VERSION, '7.2', '<')) { exit('Please upgrade to PHP 7.2 or newer.'); } $this->set_useragent(); $this->set_cache_namefilter(new CallableNameFilter($this->cache_name_function)); // Other objects, instances created here so we can set options on them $this->sanitize = new \SimplePie\Sanitize(); $this->registry = new \SimplePie\Registry(); if (func_num_args() > 0) { trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_duration() directly.', \E_USER_DEPRECATED); $args = func_get_args(); switch (count($args)) { case 3: $this->set_cache_duration($args[2]); // no break case 2: $this->set_cache_location($args[1]); // no break case 1: $this->set_feed_url($args[0]); $this->init(); } } } /** * Used for converting object to a string */ public function __toString() { return md5(serialize($this->data)); } /** * Remove items that link back to this before destroying this object */ public function __destruct() { if (!gc_enabled()) { if (!empty($this->data['items'])) { foreach ($this->data['items'] as $item) { $item->__destruct(); } unset($item, $this->data['items']); } if (!empty($this->data['ordered_items'])) { foreach ($this->data['ordered_items'] as $item) { $item->__destruct(); } unset($item, $this->data['ordered_items']); } } } /** * Force the given data/URL to be treated as a feed * * This tells SimplePie to ignore the content-type provided by the server. * Be careful when using this option, as it will also disable autodiscovery. * * @since 1.1 * @param bool $enable Force the given data/URL to be treated as a feed */ public function force_feed($enable = false) { $this->force_feed = (bool) $enable; } /** * Set the URL of the feed you want to parse * * This allows you to enter the URL of the feed you want to parse, or the * website you want to try to use auto-discovery on. This takes priority * over any set raw data. * * You can set multiple feeds to mash together by passing an array instead * of a string for the $url. Remember that with each additional feed comes * additional processing and resources. * * @since 1.0 Preview Release * @see set_raw_data() * @param string|array $url This is the URL (or array of URLs) that you want to parse. */ public function set_feed_url($url) { $this->multifeed_url = []; if (is_array($url)) { foreach ($url as $value) { $this->multifeed_url[] = $this->registry->call(Misc::class, 'fix_protocol', [$value, 1]); } } else { $this->feed_url = $this->registry->call(Misc::class, 'fix_protocol', [$url, 1]); $this->permanent_url = $this->feed_url; } } /** * Set an instance of {@see \SimplePie\File} to use as a feed * * @param \SimplePie\File &$file * @return bool True on success, false on failure */ public function set_file(&$file) { if ($file instanceof \SimplePie\File) { $this->feed_url = $file->url; $this->permanent_url = $this->feed_url; $this->file = &$file; return true; } return false; } /** * Set the raw XML data to parse * * Allows you to use a string of RSS/Atom data instead of a remote feed. * * If you have a feed available as a string in PHP, you can tell SimplePie * to parse that data string instead of a remote feed. Any set feed URL * takes precedence. * * @since 1.0 Beta 3 * @param string $data RSS or Atom data as a string. * @see set_feed_url() */ public function set_raw_data($data) { $this->raw_data = $data; } /** * Set the default timeout for fetching remote feeds * * This allows you to change the maximum time the feed's server to respond * and send the feed back. * * @since 1.0 Beta 3 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed. */ public function set_timeout($timeout = 10) { $this->timeout = (int) $timeout; } /** * Set custom curl options * * This allows you to change default curl options * * @since 1.0 Beta 3 * @param array $curl_options Curl options to add to default settings */ public function set_curl_options(array $curl_options = []) { $this->curl_options = $curl_options; } /** * Force SimplePie to use fsockopen() instead of cURL * * @since 1.0 Beta 3 * @param bool $enable Force fsockopen() to be used */ public function force_fsockopen($enable = false) { $this->force_fsockopen = (bool) $enable; } /** * Enable/disable caching in SimplePie. * * This option allows you to disable caching all-together in SimplePie. * However, disabling the cache can lead to longer load times. * * @since 1.0 Preview Release * @param bool $enable Enable caching */ public function enable_cache($enable = true) { $this->enable_cache = (bool) $enable; } /** * Set a PSR-16 implementation as cache * * @param CacheInterface $psr16cache The PSR-16 cache implementation * * @return void */ public function set_cache(CacheInterface $cache) { $this->cache = new Psr16($cache); } /** * SimplePie to continue to fall back to expired cache, if enabled, when * feed is unavailable. * * This tells SimplePie to ignore any file errors and fall back to cache * instead. This only works if caching is enabled and cached content * still exists. * * @deprecated since SimplePie 1.8.0, expired cache will not be used anymore. * * @param bool $enable Force use of cache on fail. */ public function force_cache_fallback($enable = false) { // @trigger_error(sprintf('SimplePie\SimplePie::force_cache_fallback() is deprecated since SimplePie 1.8.0, expired cache will not be used anymore.'), \E_USER_DEPRECATED); $this->force_cache_fallback = (bool) $enable; } /** * Set the length of time (in seconds) that the contents of a feed will be * cached * * @param int $seconds The feed content cache duration */ public function set_cache_duration($seconds = 3600) { $this->cache_duration = (int) $seconds; } /** * Set the length of time (in seconds) that the autodiscovered feed URL will * be cached * * @param int $seconds The autodiscovered feed URL cache duration. */ public function set_autodiscovery_cache_duration($seconds = 604800) { $this->autodiscovery_cache_duration = (int) $seconds; } /** * Set the file system location where the cached files should be stored * * @deprecated since SimplePie 1.8.0, use \SimplePie\SimplePie::set_cache() instead. * * @param string $location The file system location. */ public function set_cache_location($location = './cache') { // @trigger_error(sprintf('SimplePie\SimplePie::set_cache_location() is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache()" instead.'), \E_USER_DEPRECATED); $this->cache_location = (string) $location; } /** * Return the filename (i.e. hash, without path and without extension) of the file to cache a given URL. * * @param string $url The URL of the feed to be cached. * @return string A filename (i.e. hash, without path and without extension). */ public function get_cache_filename($url) { // Append custom parameters to the URL to avoid cache pollution in case of multiple calls with different parameters. $url .= $this->force_feed ? '#force_feed' : ''; $options = []; if ($this->timeout != 10) { $options[CURLOPT_TIMEOUT] = $this->timeout; } if ($this->useragent !== \SimplePie\Misc::get_default_useragent()) { $options[CURLOPT_USERAGENT] = $this->useragent; } if (!empty($this->curl_options)) { foreach ($this->curl_options as $k => $v) { $options[$k] = $v; } } if (!empty($options)) { ksort($options); $url .= '#' . urlencode(var_export($options, true)); } return $this->cache_namefilter->filter($url); } /** * Set whether feed items should be sorted into reverse chronological order * * @param bool $enable Sort as reverse chronological order. */ public function enable_order_by_date($enable = true) { $this->order_by_date = (bool) $enable; } /** * Set the character encoding used to parse the feed * * This overrides the encoding reported by the feed, however it will fall * back to the normal encoding detection if the override fails * * @param string $encoding Character encoding */ public function set_input_encoding($encoding = false) { if ($encoding) { $this->input_encoding = (string) $encoding; } else { $this->input_encoding = false; } } /** * Set how much feed autodiscovery to do * * @see \SimplePie\SimplePie::LOCATOR_NONE * @see \SimplePie\SimplePie::LOCATOR_AUTODISCOVERY * @see \SimplePie\SimplePie::LOCATOR_LOCAL_EXTENSION * @see \SimplePie\SimplePie::LOCATOR_LOCAL_BODY * @see \SimplePie\SimplePie::LOCATOR_REMOTE_EXTENSION * @see \SimplePie\SimplePie::LOCATOR_REMOTE_BODY * @see \SimplePie\SimplePie::LOCATOR_ALL * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator) */ public function set_autodiscovery_level($level = self::LOCATOR_ALL) { $this->autodiscovery = (int) $level; } /** * Get the class registry * * Use this to override SimplePie's default classes * @see \SimplePie\Registry * * @return Registry */ public function &get_registry() { return $this->registry; } /** * Set which class SimplePie uses for caching * * @deprecated since SimplePie 1.3, use {@see set_cache()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_cache_class($class = Cache::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::set_cache()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Cache::class, $class, true); } /** * Set which class SimplePie uses for auto-discovery * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_locator_class($class = Locator::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Locator::class, $class, true); } /** * Set which class SimplePie uses for XML parsing * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_parser_class($class = Parser::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Parser::class, $class, true); } /** * Set which class SimplePie uses for remote file fetching * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_file_class($class = File::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(File::class, $class, true); } /** * Set which class SimplePie uses for data sanitization * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_sanitize_class($class = Sanitize::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Sanitize::class, $class, true); } /** * Set which class SimplePie uses for handling feed items * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_item_class($class = Item::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Item::class, $class, true); } /** * Set which class SimplePie uses for handling author data * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_author_class($class = Author::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Author::class, $class, true); } /** * Set which class SimplePie uses for handling category data * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_category_class($class = Category::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Category::class, $class, true); } /** * Set which class SimplePie uses for feed enclosures * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_enclosure_class($class = Enclosure::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Enclosure::class, $class, true); } /** * Set which class SimplePie uses for `<media:text>` captions * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_caption_class($class = Caption::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Caption::class, $class, true); } /** * Set which class SimplePie uses for `<media:copyright>` * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_copyright_class($class = Copyright::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Copyright::class, $class, true); } /** * Set which class SimplePie uses for `<media:credit>` * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_credit_class($class = Credit::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Credit::class, $class, true); } /** * Set which class SimplePie uses for `<media:rating>` * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_rating_class($class = Rating::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Rating::class, $class, true); } /** * Set which class SimplePie uses for `<media:restriction>` * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_restriction_class($class = Restriction::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Restriction::class, $class, true); } /** * Set which class SimplePie uses for content-type sniffing * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_content_type_sniffer_class($class = Sniffer::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Sniffer::class, $class, true); } /** * Set which class SimplePie uses item sources * * @deprecated since SimplePie 1.3, use {@see get_registry()} instead * * @param string $class Name of custom class * * @return boolean True on success, false otherwise */ public function set_source_class($class = Source::class) { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.3, please use "SimplePie\SimplePie::get_registry()" instead.', __METHOD__), \E_USER_DEPRECATED); return $this->registry->register(Source::class, $class, true); } /** * Set the user agent string * * @param string $ua New user agent string. */ public function set_useragent($ua = null) { if ($ua === null) { $ua = \SimplePie\Misc::get_default_useragent(); } $this->useragent = (string) $ua; } /** * Set a namefilter to modify the cache filename with * * @param NameFilter $filter * * @return void */ public function set_cache_namefilter(NameFilter $filter): void { $this->cache_namefilter = $filter; } /** * Set callback function to create cache filename with * * @deprecated since SimplePie 1.8.0, use {@see set_cache_namefilter()} instead * * @param mixed $function Callback function */ public function set_cache_name_function($function = 'md5') { // trigger_error(sprintf('"%s()" is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache_namefilter()" instead.', __METHOD__), \E_USER_DEPRECATED); if (is_callable($function)) { $this->cache_name_function = $function; $this->set_cache_namefilter(new CallableNameFilter($this->cache_name_function)); } } /** * Set options to make SP as fast as possible * * Forgoes a substantial amount of data sanitization in favor of speed. This * turns SimplePie into a dumb parser of feeds. * * @param bool $set Whether to set them or not */ public function set_stupidly_fast($set = false) { if ($set) { $this->enable_order_by_date(false); $this->remove_div(false); $this->strip_comments(false); $this->strip_htmltags(false); $this->strip_attributes(false); $this->add_attributes(false); $this->set_image_handler(false); $this->set_https_domains([]); } } /** * Set maximum number of feeds to check with autodiscovery * * @param int $max Maximum number of feeds to check */ public function set_max_checked_feeds($max = 10) { $this->max_checked_feeds = (int) $max; } public function remove_div($enable = true) { $this->sanitize->remove_div($enable); } public function strip_htmltags($tags = '', $encode = null) { if ($tags === '') { $tags = $this->strip_htmltags; } $this->sanitize->strip_htmltags($tags); if ($encode !== null) { $this->sanitize->encode_instead_of_strip($tags); } } public function encode_instead_of_strip($enable = true) { $this->sanitize->encode_instead_of_strip($enable); } public function rename_attributes($attribs = '') { if ($attribs === '') { $attribs = $this->rename_attributes; } $this->sanitize->rename_attributes($attribs); } public function strip_attributes($attribs = '') { if ($attribs === '') { $attribs = $this->strip_attributes; } $this->sanitize->strip_attributes($attribs); } public function add_attributes($attribs = '') { if ($attribs === '') { $attribs = $this->add_attributes; } $this->sanitize->add_attributes($attribs); } /** * Set the output encoding * * Allows you to override SimplePie's output to match that of your webpage. * This is useful for times when your webpages are not being served as * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and * is similar to {@see set_input_encoding()}. * * It should be noted, however, that not all character encodings can support * all characters. If your page is being served as ISO-8859-1 and you try * to display a Japanese feed, you'll likely see garbled characters. * Because of this, it is highly recommended to ensure that your webpages * are served as UTF-8. * * The number of supported character encodings depends on whether your web * host supports {@link http://php.net/mbstring mbstring}, * {@link http://php.net/iconv iconv}, or both. See * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for * more information. * * @param string $encoding */ public function set_output_encoding($encoding = 'UTF-8') { $this->sanitize->set_output_encoding($encoding); } public function strip_comments($strip = false) { $this->sanitize->strip_comments($strip); } /** * Set element/attribute key/value pairs of HTML attributes * containing URLs that need to be resolved relative to the feed * * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite, * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite, * |q|@cite * * @since 1.0 * @param array|null $element_attribute Element/attribute key/value pairs, null for default */ public function set_url_replacements($element_attribute = null) { $this->sanitize->set_url_replacements($element_attribute); } /** * Set the list of domains for which to force HTTPS. * @see \SimplePie\Sanitize::set_https_domains() * @param array List of HTTPS domains. Example array('biz', 'example.com', 'example.org', 'www.example.net'). */ public function set_https_domains($domains = []) { if (is_array($domains)) { $this->sanitize->set_https_domains($domains); } } /** * Set the handler to enable the display of cached images. * * @param string $page Web-accessible path to the handler_image.php file. * @param string $qs The query string that the value should be passed to. */ public function set_image_handler($page = false, $qs = 'i') { if ($page !== false) { $this->sanitize->set_image_handler($page . '?' . $qs . '='); } else { $this->image_handler = ''; } } /** * Set the limit for items returned per-feed with multifeeds * * @param integer $limit The maximum number of items to return. */ public function set_item_limit($limit = 0) { $this->item_limit = (int) $limit; } /** * Enable throwing exceptions * * @param boolean $enable Should we throw exceptions, or use the old-style error property? */ public function enable_exceptions($enable = true) { $this->enable_exceptions = $enable; } /** * Initialize the feed object * * This is what makes everything happen. Period. This is where all of the * configuration options get processed, feeds are fetched, cached, and * parsed, and all of that other good stuff. * * @return boolean True if successful, false otherwise */ public function init() { // Check absolute bare minimum requirements. if (!extension_loaded('xml') || !extension_loaded('pcre')) { $this->error = 'XML or PCRE extensions not loaded!'; return false; } // Then check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader. elseif (!extension_loaded('xmlreader')) { static $xml_is_sane = null; if ($xml_is_sane === null) { $parser_check = xml_parser_create(); xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); xml_parser_free($parser_check); $xml_is_sane = isset($values[0]['value']); } if (!$xml_is_sane) { return false; } } // The default sanitize class gets set in the constructor, check if it has // changed. if ($this->registry->get_class(Sanitize::class) !== 'SimplePie\Sanitize') { $this->sanitize = $this->registry->create(Sanitize::class); } if (method_exists($this->sanitize, 'set_registry')) { $this->sanitize->set_registry($this->registry); } // Pass whatever was set with config options over to the sanitizer. // Pass the classes in for legacy support; new classes should use the registry instead $this->sanitize->pass_cache_data( $this->enable_cache, $this->cache_location, $this->cache_namefilter, $this->registry->get_class(Cache::class), $this->cache ); $this->sanitize->pass_file_data($this->registry->get_class(File::class), $this->timeout, $this->useragent, $this->force_fsockopen, $this->curl_options); if (!empty($this->multifeed_url)) { $i = 0; $success = 0; $this->multifeed_objects = []; $this->error = []; foreach ($this->multifeed_url as $url) { $this->multifeed_objects[$i] = clone $this; $this->multifeed_objects[$i]->set_feed_url($url); $single_success = $this->multifeed_objects[$i]->init(); $success |= $single_success; if (!$single_success) { $this->error[$i] = $this->multifeed_objects[$i]->error(); } $i++; } return (bool) $success; } elseif ($this->feed_url === null && $this->raw_data === null) { return false; } $this->error = null; $this->data = []; $this->check_modified = false; $this->multifeed_objects = []; $cache = false; if ($this->feed_url !== null) { $parsed_feed_url = $this->registry->call(Misc::class, 'parse_url', [$this->feed_url]); // Decide whether to enable caching if ($this->enable_cache && $parsed_feed_url['scheme'] !== '') { $cache = $this->get_cache($this->feed_url); } // Fetch the data via \SimplePie\File into $this->raw_data if (($fetched = $this->fetch_data($cache)) === true) { return true; } elseif ($fetched === false) { return false; } [$headers, $sniffed] = $fetched; } // Empty response check if (empty($this->raw_data)) { $this->error = "A feed could not be found at `$this->feed_url`. Empty body."; $this->registry->call(Misc::class, 'error', [$this->error, E_USER_NOTICE, __FILE__, __LINE__]); return false; } // Set up array of possible encodings $encodings = []; // First check to see if input has been overridden. if ($this->input_encoding !== false) { $encodings[] = strtoupper($this->input_encoding); } $application_types = ['application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity']; $text_types = ['text/xml', 'text/xml-external-parsed-entity']; // RFC 3023 (only applies to sniffed content) if (isset($sniffed)) { if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml') { if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) { $encodings[] = strtoupper($charset[1]); } $encodings = array_merge($encodings, $this->registry->call(Misc::class, 'xml_encoding', [$this->raw_data, &$this->registry])); $encodings[] = 'UTF-8'; } elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml') { if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) { $encodings[] = strtoupper($charset[1]); } $encodings[] = 'US-ASCII'; } // Text MIME-type default elseif (substr($sniffed, 0, 5) === 'text/') { $encodings[] = 'UTF-8'; } } // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1 $encodings = array_merge($encodings, $this->registry->call(Misc::class, 'xml_encoding', [$this->raw_data, &$this->registry])); $encodings[] = 'UTF-8'; $encodings[] = 'ISO-8859-1'; // There's no point in trying an encoding twice $encodings = array_unique($encodings); // Loop through each possible encoding, till we return something, or run out of possibilities foreach ($encodings as $encoding) { // Change the encoding to UTF-8 (as we always use UTF-8 internally) if ($utf8_data = $this->registry->call(Misc::class, 'change_encoding', [$this->raw_data, $encoding, 'UTF-8'])) { // Create new parser $parser = $this->registry->create(Parser::class); // If it's parsed fine if ($parser->parse($utf8_data, 'UTF-8', $this->permanent_url)) { $this->data = $parser->get_data(); if (!($this->get_type() & ~self::TYPE_NONE)) { $this->error = "A feed could not be found at `$this->feed_url`. This does not appear to be a valid RSS or Atom feed."; $this->registry->call(Misc::class, 'error', [$this->error, E_USER_NOTICE, __FILE__, __LINE__]); return false; } if (isset($headers)) { $this->data['headers'] = $headers; } $this->data['build'] = \SimplePie\Misc::get_build(); // Cache the file if caching is enabled $this->data['cache_expiration_time'] = $this->cache_duration + time(); if ($cache && !$cache->set_data($this->get_cache_filename($this->feed_url), $this->data, $this->cache_duration)) { trigger_error("$this->cache_location is not writable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); } return true; } } } if (isset($parser)) { // We have an error, just set \SimplePie\Misc::error to it and quit $this->error = $this->feed_url; $this->error .= sprintf(' is invalid XML, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column()); } else { $this->error = 'The data could not be converted to UTF-8.'; if (!extension_loaded('mbstring') && !extension_loaded('iconv') && !class_exists('\UConverter')) { $this->error .= ' You MUST have either the iconv, mbstring or intl (PHP 5.5+) extension installed and enabled.'; } else { $missingExtensions = []; if (!extension_loaded('iconv')) { $missingExtensions[] = 'iconv'; } if (!extension_loaded('mbstring')) { $missingExtensions[] = 'mbstring'; } if (!class_exists('\UConverter')) { $missingExtensions[] = 'intl (PHP 5.5+)'; } $this->error .= ' Try installing/enabling the ' . implode(' or ', $missingExtensions) . ' extension.'; } } $this->registry->call(Misc::class, 'error', [$this->error, E_USER_NOTICE, __FILE__, __LINE__]); return false; } /** * Fetch the data via \SimplePie\File * * If the data is already cached, attempt to fetch it from there instead * @param Base|DataCache|false $cache Cache handler, or false to not load from the cache * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type */ protected function fetch_data(&$cache) { if (is_object($cache) && $cache instanceof Base) { // @trigger_error(sprintf('Providing $cache as "\SimplePie\Cache\Base" in %s() is deprecated since SimplePie 1.8.0, please provide "\SimplePie\Cache\DataCache" implementation instead.', __METHOD__), \E_USER_DEPRECATED); $cache = new BaseDataCache($cache); } if ($cache !== false && !$cache instanceof DataCache) { throw new InvalidArgumentException(sprintf( '%s(): Argument #1 ($cache) must be of type %s|false', __METHOD__, DataCache::class ), 1); } $cacheKey = $this->get_cache_filename($this->feed_url); // If it's enabled, use the cache if ($cache) { // Load the Cache $this->data = $cache->get_data($cacheKey, []); if (!empty($this->data)) { // If the cache is for an outdated build of SimplePie if (!isset($this->data['build']) || $this->data['build'] !== \SimplePie\Misc::get_build()) { $cache->delete_data($cacheKey); $this->data = []; } // If we've hit a collision just rerun it with caching disabled elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url) { $cache = false; $this->data = []; } // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL. elseif (isset($this->data['feed_url'])) { // Do not need to do feed autodiscovery yet. if ($this->data['feed_url'] !== $this->data['url']) { $this->set_feed_url($this->data['feed_url']); $this->data['url'] = $this->data['feed_url']; $cache->set_data($this->get_cache_filename($this->feed_url), $this->data, $this->autodiscovery_cache_duration); return $this->init(); } $cache->delete_data($this->get_cache_filename($this->feed_url)); $this->data = []; } // Check if the cache has been updated elseif (isset($this->data['cache_expiration_time']) && $this->data['cache_expiration_time'] > time()) { // Want to know if we tried to send last-modified and/or etag headers // when requesting this file. (Note that it's up to the file to // support this, but we don't always send the headers either.) $this->check_modified = true; if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) { $headers = [ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', ]; if (isset($this->data['headers']['last-modified'])) { $headers['if-modified-since'] = $this->data['headers']['last-modified']; } if (isset($this->data['headers']['etag'])) { $headers['if-none-match'] = $this->data['headers']['etag']; } $file = $this->registry->create(File::class, [$this->feed_url, $this->timeout / 10, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options]); $this->status_code = $file->status_code; if ($file->success) { if ($file->status_code === 304) { // Set raw_data to false here too, to signify that the cache // is still valid. $this->raw_data = false; $cache->set_data($cacheKey, $this->data, $this->cache_duration); return true; } } else { $this->check_modified = false; if ($this->force_cache_fallback) { $cache->set_data($cacheKey, $this->data, $this->cache_duration); return true; } unset($file); } } } // If the cache is still valid, just return true else { $this->raw_data = false; return true; } } // If the cache is empty else { $this->data = []; } } // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it. if (!isset($file)) { if ($this->file instanceof \SimplePie\File && $this->file->url === $this->feed_url) { $file = &$this->file; } else { $headers = [ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', ]; $file = $this->registry->create(File::class, [$this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options]); } } $this->status_code = $file->status_code; // If the file connection has an error, set SimplePie::error to that and quit if (!$file->success && !($file->method & self::FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) { $this->error = $file->error; return !empty($this->data); } if (!$this->force_feed) { // Check if the supplied URL is a feed, if it isn't, look for it. $locate = $this->registry->create(Locator::class, [&$file, $this->timeout, $this->useragent, $this->max_checked_feeds, $this->force_fsockopen, $this->curl_options]); if (!$locate->is_feed($file)) { $copyStatusCode = $file->status_code; $copyContentType = $file->headers['content-type']; try { $microformats = false; if (class_exists('DOMXpath') && function_exists('Mf2\parse')) { $doc = new \DOMDocument(); @$doc->loadHTML($file->body); $xpath = new \DOMXpath($doc); // Check for both h-feed and h-entry, as both a feed with no entries // and a list of entries without an h-feed wrapper are both valid. $query = '//*[contains(concat(" ", @class, " "), " h-feed ") or '. 'contains(concat(" ", @class, " "), " h-entry ")]'; $result = $xpath->query($query); $microformats = $result->length !== 0; } // Now also do feed discovery, but if microformats were found don't // overwrite the current value of file. $discovered = $locate->find( $this->autodiscovery, $this->all_discovered_feeds ); if ($microformats) { if ($hub = $locate->get_rel_link('hub')) { $self = $locate->get_rel_link('self'); $this->store_links($file, $hub, $self); } // Push the current file onto all_discovered feeds so the user can // be shown this as one of the options. if (isset($this->all_discovered_feeds)) { $this->all_discovered_feeds[] = $file; } } else { if ($discovered) { $file = $discovered; } else { // We need to unset this so that if SimplePie::set_file() has // been called that object is untouched unset($file); $this->error = "A feed could not be found at `$this->feed_url`; the status code is `$copyStatusCode` and content-type is `$copyContentType`"; $this->registry->call(Misc::class, 'error', [$this->error, E_USER_NOTICE, __FILE__, __LINE__]); return false; } } } catch (\SimplePie\Exception $e) { // We need to unset this so that if SimplePie::set_file() has been called that object is untouched unset($file); // This is usually because DOMDocument doesn't exist $this->error = $e->getMessage(); $this->registry->call(Misc::class, 'error', [$this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()]); return false; } if ($cache) { $this->data = [ 'url' => $this->feed_url, 'feed_url' => $file->url, 'build' => \SimplePie\Misc::get_build(), 'cache_expiration_time' => $this->cache_duration + time(), ]; if (!$cache->set_data($cacheKey, $this->data, $this->cache_duration)) { trigger_error("$this->cache_location is not writable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); } } } $this->feed_url = $file->url; $locate = null; } $this->raw_data = $file->body; $this->permanent_url = $file->permanent_url; $headers = $file->headers; $sniffer = $this->registry->create(Sniffer::class, [&$file]); $sniffed = $sniffer->get_type(); return [$headers, $sniffed]; } /** * Get the error message for the occurred error * * @return string|array Error message, or array of messages for multifeeds */ public function error() { return $this->error; } /** * Get the last HTTP status code * * @return int Status code */ public function status_code() { return $this->status_code; } /** * Get the raw XML * * This is the same as the old `$feed->enable_xml_dump(true)`, but returns * the data instead of printing it. * * @return string|boolean Raw XML data, false if the cache is used */ public function get_raw_data() { return $this->raw_data; } /** * Get the character encoding used for output * * @since Preview Release * @return string */ public function get_encoding() { return $this->sanitize->output_encoding; } /** * Send the content-type header with correct encoding * * This method ensures that the SimplePie-enabled page is being served with * the correct {@link http://www.iana.org/assignments/media-types/ mime-type} * and character encoding HTTP headers (character encoding determined by the * {@see set_output_encoding} config option). * * This won't work properly if any content or whitespace has already been * sent to the browser, because it relies on PHP's * {@link http://php.net/header header()} function, and these are the * circumstances under which the function works. * * Because it's setting these settings for the entire page (as is the nature * of HTTP headers), this should only be used once per page (again, at the * top). * * @param string $mime MIME type to serve the page as */ public function handle_content_type($mime = 'text/html') { if (!headers_sent()) { $header = "Content-type: $mime;"; if ($this->get_encoding()) { $header .= ' charset=' . $this->get_encoding(); } else { $header .= ' charset=UTF-8'; } header($header); } } /** * Get the type of the feed * * This returns a \SimplePie\SimplePie::TYPE_* constant, which can be tested against * using {@link http://php.net/language.operators.bitwise bitwise operators} * * @since 0.8 (usage changed to using constants in 1.0) * @see \SimplePie\SimplePie::TYPE_NONE Unknown. * @see \SimplePie\SimplePie::TYPE_RSS_090 RSS 0.90. * @see \SimplePie\SimplePie::TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape). * @see \SimplePie\SimplePie::TYPE_RSS_091_USERLAND RSS 0.91 (Userland). * @see \SimplePie\SimplePie::TYPE_RSS_091 RSS 0.91. * @see \SimplePie\SimplePie::TYPE_RSS_092 RSS 0.92. * @see \SimplePie\SimplePie::TYPE_RSS_093 RSS 0.93. * @see \SimplePie\SimplePie::TYPE_RSS_094 RSS 0.94. * @see \SimplePie\SimplePie::TYPE_RSS_10 RSS 1.0. * @see \SimplePie\SimplePie::TYPE_RSS_20 RSS 2.0.x. * @see \SimplePie\SimplePie::TYPE_RSS_RDF RDF-based RSS. * @see \SimplePie\SimplePie::TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format). * @see \SimplePie\SimplePie::TYPE_RSS_ALL Any version of RSS. * @see \SimplePie\SimplePie::TYPE_ATOM_03 Atom 0.3. * @see \SimplePie\SimplePie::TYPE_ATOM_10 Atom 1.0. * @see \SimplePie\SimplePie::TYPE_ATOM_ALL Any version of Atom. * @see \SimplePie\SimplePie::TYPE_ALL Any known/supported feed type. * @return int \SimplePie\SimplePie::TYPE_* constant */ public function get_type() { if (!isset($this->data['type'])) { $this->data['type'] = self::TYPE_ALL; if (isset($this->data['child'][self::NAMESPACE_ATOM_10]['feed'])) { $this->data['type'] &= self::TYPE_ATOM_10; } elseif (isset($this->data['child'][self::NAMESPACE_ATOM_03]['feed'])) { $this->data['type'] &= self::TYPE_ATOM_03; } elseif (isset($this->data['child'][self::NAMESPACE_RDF]['RDF'])) { if (isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_10]['channel']) || isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_10]['image']) || isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_10]['item']) || isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_10]['textinput'])) { $this->data['type'] &= self::TYPE_RSS_10; } if (isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_090]['channel']) || isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_090]['image']) || isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_090]['item']) || isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][self::NAMESPACE_RSS_090]['textinput'])) { $this->data['type'] &= self::TYPE_RSS_090; } } elseif (isset($this->data['child'][self::NAMESPACE_RSS_20]['rss'])) { $this->data['type'] &= self::TYPE_RSS_ALL; if (isset($this->data['child'][self::NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version'])) { switch (trim($this->data['child'][self::NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version'])) { case '0.91': $this->data['type'] &= self::TYPE_RSS_091; if (isset($this->data['child'][self::NAMESPACE_RSS_20]['rss'][0]['child'][self::NAMESPACE_RSS_20]['skiphours']['hour'][0]['data'])) { switch (trim($this->data['child'][self::NAMESPACE_RSS_20]['rss'][0]['child'][self::NAMESPACE_RSS_20]['skiphours']['hour'][0]['data'])) { case '0': $this->data['type'] &= self::TYPE_RSS_091_NETSCAPE; break; case '24': $this->data['type'] &= self::TYPE_RSS_091_USERLAND; break; } } break; case '0.92': $this->data['type'] &= self::TYPE_RSS_092; break; case '0.93': $this->data['type'] &= self::TYPE_RSS_093; break; case '0.94': $this->data['type'] &= self::TYPE_RSS_094; break; case '2.0': $this->data['type'] &= self::TYPE_RSS_20; break; } } } else { $this->data['type'] = self::TYPE_NONE; } } return $this->data['type']; } /** * Get the URL for the feed * * When the 'permanent' mode is enabled, returns the original feed URL, * except in the case of an `HTTP 301 Moved Permanently` status response, * in which case the location of the first redirection is returned. * * When the 'permanent' mode is disabled (default), * may or may not be different from the URL passed to {@see set_feed_url()}, * depending on whether auto-discovery was used, and whether there were * any redirects along the way. * * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.) * @todo Support <itunes:new-feed-url> * @todo Also, |atom:link|@rel=self * @param bool $permanent Permanent mode to return only the original URL or the first redirection * iff it is a 301 redirection * @return string|null */ public function subscribe_url($permanent = false) { if ($permanent) { if ($this->permanent_url !== null) { // sanitize encodes ampersands which are required when used in a url. return str_replace( '&', '&', $this->sanitize( $this->permanent_url, self::CONSTRUCT_IRI ) ); } } else { if ($this->feed_url !== null) { return str_replace( '&', '&', $this->sanitize( $this->feed_url, self::CONSTRUCT_IRI ) ); } } return null; } /** * Get data for an feed-level element * * This method allows you to get access to ANY element/attribute that is a * sub-element of the opening feed tag. * * The return value is an indexed array of elements matching the given * namespace and tag name. Each element has `attribs`, `data` and `child` * subkeys. For `attribs` and `child`, these contain namespace subkeys. * `attribs` then has one level of associative name => value data (where * `value` is a string) after the namespace. `child` has tag-indexed keys * after the namespace, each member of which is an indexed array matching * this same format. * * For example: * <pre> * // This is probably a bad example because we already support * // <media:content> natively, but it shows you how to parse through * // the nodes. * $group = $item->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'group'); * $content = $group[0]['child'][\SimplePie\SimplePie::NAMESPACE_MEDIARSS]['content']; * $file = $content[0]['attribs']['']['url']; * echo $file; * </pre> * * @since 1.0 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces * @param string $namespace The URL of the XML namespace of the elements you're trying to access * @param string $tag Tag name * @return array */ public function get_feed_tags($namespace, $tag) { $type = $this->get_type(); if ($type & self::TYPE_ATOM_10) { if (isset($this->data['child'][self::NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag])) { return $this->data['child'][self::NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]; } } if ($type & self::TYPE_ATOM_03) { if (isset($this->data['child'][self::NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag])) { return $this->data['child'][self::NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]; } } if ($type & self::TYPE_RSS_RDF) { if (isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag])) { return $this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]; } } if ($type & self::TYPE_RSS_SYNDICATION) { if (isset($this->data['child'][self::NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag])) { return $this->data['child'][self::NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]; } } return null; } /** * Get data for an channel-level element * * This method allows you to get access to ANY element/attribute in the * channel/header section of the feed. * * See {@see SimplePie::get_feed_tags()} for a description of the return value * * @since 1.0 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces * @param string $namespace The URL of the XML namespace of the elements you're trying to access * @param string $tag Tag name * @return array */ public function get_channel_tags($namespace, $tag) { $type = $this->get_type(); if ($type & self::TYPE_ATOM_ALL) { if ($return = $this->get_feed_tags($namespace, $tag)) { return $return; } } if ($type & self::TYPE_RSS_10) { if ($channel = $this->get_feed_tags(self::NAMESPACE_RSS_10, 'channel')) { if (isset($channel[0]['child'][$namespace][$tag])) { return $channel[0]['child'][$namespace][$tag]; } } } if ($type & self::TYPE_RSS_090) { if ($channel = $this->get_feed_tags(self::NAMESPACE_RSS_090, 'channel')) { if (isset($channel[0]['child'][$namespace][$tag])) { return $channel[0]['child'][$namespace][$tag]; } } } if ($type & self::TYPE_RSS_SYNDICATION) { if ($channel = $this->get_feed_tags(self::NAMESPACE_RSS_20, 'channel')) { if (isset($channel[0]['child'][$namespace][$tag])) { return $channel[0]['child'][$namespace][$tag]; } } } return null; } /** * Get data for an channel-level element * * This method allows you to get access to ANY element/attribute in the * image/logo section of the feed. * * See {@see SimplePie::get_feed_tags()} for a description of the return value * * @since 1.0 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces * @param string $namespace The URL of the XML namespace of the elements you're trying to access * @param string $tag Tag name * @return array */ public function get_image_tags($namespace, $tag) { $type = $this->get_type(); if ($type & self::TYPE_RSS_10) { if ($image = $this->get_feed_tags(self::NAMESPACE_RSS_10, 'image')) { if (isset($image[0]['child'][$namespace][$tag])) { return $image[0]['child'][$namespace][$tag]; } } } if ($type & self::TYPE_RSS_090) { if ($image = $this->get_feed_tags(self::NAMESPACE_RSS_090, 'image')) { if (isset($image[0]['child'][$namespace][$tag])) { return $image[0]['child'][$namespace][$tag]; } } } if ($type & self::TYPE_RSS_SYNDICATION) { if ($image = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'image')) { if (isset($image[0]['child'][$namespace][$tag])) { return $image[0]['child'][$namespace][$tag]; } } } return null; } /** * Get the base URL value from the feed * * Uses `<xml:base>` if available, otherwise uses the first link in the * feed, or failing that, the URL of the feed itself. * * @see get_link * @see subscribe_url * * @param array $element * @return string */ public function get_base($element = []) { if (!empty($element['xml_base_explicit']) && isset($element['xml_base'])) { return $element['xml_base']; } elseif ($this->get_link() !== null) { return $this->get_link(); } return $this->subscribe_url(); } /** * Sanitize feed data * * @access private * @see \SimplePie\Sanitize::sanitize() * @param string $data Data to sanitize * @param int $type One of the \SimplePie\SimplePie::CONSTRUCT_* constants * @param string $base Base URL to resolve URLs against * @return string Sanitized data */ public function sanitize($data, $type, $base = '') { try { return $this->sanitize->sanitize($data, $type, $base); } catch (\SimplePie\Exception $e) { if (!$this->enable_exceptions) { $this->error = $e->getMessage(); $this->registry->call(Misc::class, 'error', [$this->error, E_USER_WARNING, $e->getFile(), $e->getLine()]); return ''; } throw $e; } } /** * Get the title of the feed * * Uses `<atom:title>`, `<title>` or `<dc:title>` * * @since 1.0 (previously called `get_feed_title` since 0.8) * @return string|null */ public function get_title() { if ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'title')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'title')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_10, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_090, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } return null; } /** * Get a category for the feed * * @since Unknown * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Category|null */ public function get_category($key = 0) { $categories = $this->get_categories(); if (isset($categories[$key])) { return $categories[$key]; } return null; } /** * Get all categories for the feed * * Uses `<atom:category>`, `<category>` or `<dc:subject>` * * @since Unknown * @return array|null List of {@see \SimplePie\Category} objects */ public function get_categories() { $categories = []; foreach ((array) $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'category') as $category) { $term = null; $scheme = null; $label = null; if (isset($category['attribs']['']['term'])) { $term = $this->sanitize($category['attribs']['']['term'], self::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['scheme'])) { $scheme = $this->sanitize($category['attribs']['']['scheme'], self::CONSTRUCT_TEXT); } if (isset($category['attribs']['']['label'])) { $label = $this->sanitize($category['attribs']['']['label'], self::CONSTRUCT_TEXT); } $categories[] = $this->registry->create(Category::class, [$term, $scheme, $label]); } foreach ((array) $this->get_channel_tags(self::NAMESPACE_RSS_20, 'category') as $category) { // This is really the label, but keep this as the term also for BC. // Label will also work on retrieving because that falls back to term. $term = $this->sanitize($category['data'], self::CONSTRUCT_TEXT); if (isset($category['attribs']['']['domain'])) { $scheme = $this->sanitize($category['attribs']['']['domain'], self::CONSTRUCT_TEXT); } else { $scheme = null; } $categories[] = $this->registry->create(Category::class, [$term, $scheme, null]); } foreach ((array) $this->get_channel_tags(self::NAMESPACE_DC_11, 'subject') as $category) { $categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], self::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_channel_tags(self::NAMESPACE_DC_10, 'subject') as $category) { $categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], self::CONSTRUCT_TEXT), null, null]); } if (!empty($categories)) { return array_unique($categories); } return null; } /** * Get an author for the feed * * @since 1.1 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Author|null */ public function get_author($key = 0) { $authors = $this->get_authors(); if (isset($authors[$key])) { return $authors[$key]; } return null; } /** * Get all authors for the feed * * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>` * * @since 1.1 * @return array|null List of {@see \SimplePie\Author} objects */ public function get_authors() { $authors = []; foreach ((array) $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'author') as $author) { $name = null; $uri = null; $email = null; if (isset($author['child'][self::NAMESPACE_ATOM_10]['name'][0]['data'])) { $name = $this->sanitize($author['child'][self::NAMESPACE_ATOM_10]['name'][0]['data'], self::CONSTRUCT_TEXT); } if (isset($author['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'])) { $uri = $this->sanitize($author['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($author['child'][self::NAMESPACE_ATOM_10]['uri'][0])); } if (isset($author['child'][self::NAMESPACE_ATOM_10]['email'][0]['data'])) { $email = $this->sanitize($author['child'][self::NAMESPACE_ATOM_10]['email'][0]['data'], self::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $uri !== null) { $authors[] = $this->registry->create(Author::class, [$name, $uri, $email]); } } if ($author = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'author')) { $name = null; $url = null; $email = null; if (isset($author[0]['child'][self::NAMESPACE_ATOM_03]['name'][0]['data'])) { $name = $this->sanitize($author[0]['child'][self::NAMESPACE_ATOM_03]['name'][0]['data'], self::CONSTRUCT_TEXT); } if (isset($author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'])) { $url = $this->sanitize($author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($author[0]['child'][self::NAMESPACE_ATOM_03]['url'][0])); } if (isset($author[0]['child'][self::NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($author[0]['child'][self::NAMESPACE_ATOM_03]['email'][0]['data'], self::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $url !== null) { $authors[] = $this->registry->create(Author::class, [$name, $url, $email]); } } foreach ((array) $this->get_channel_tags(self::NAMESPACE_DC_11, 'creator') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], self::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_channel_tags(self::NAMESPACE_DC_10, 'creator') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], self::CONSTRUCT_TEXT), null, null]); } foreach ((array) $this->get_channel_tags(self::NAMESPACE_ITUNES, 'author') as $author) { $authors[] = $this->registry->create(Author::class, [$this->sanitize($author['data'], self::CONSTRUCT_TEXT), null, null]); } if (!empty($authors)) { return array_unique($authors); } return null; } /** * Get a contributor for the feed * * @since 1.1 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Author|null */ public function get_contributor($key = 0) { $contributors = $this->get_contributors(); if (isset($contributors[$key])) { return $contributors[$key]; } return null; } /** * Get all contributors for the feed * * Uses `<atom:contributor>` * * @since 1.1 * @return array|null List of {@see \SimplePie\Author} objects */ public function get_contributors() { $contributors = []; foreach ((array) $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'contributor') as $contributor) { $name = null; $uri = null; $email = null; if (isset($contributor['child'][self::NAMESPACE_ATOM_10]['name'][0]['data'])) { $name = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_10]['name'][0]['data'], self::CONSTRUCT_TEXT); } if (isset($contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'])) { $uri = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($contributor['child'][self::NAMESPACE_ATOM_10]['uri'][0])); } if (isset($contributor['child'][self::NAMESPACE_ATOM_10]['email'][0]['data'])) { $email = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_10]['email'][0]['data'], self::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $uri !== null) { $contributors[] = $this->registry->create(Author::class, [$name, $uri, $email]); } } foreach ((array) $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'contributor') as $contributor) { $name = null; $url = null; $email = null; if (isset($contributor['child'][self::NAMESPACE_ATOM_03]['name'][0]['data'])) { $name = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_03]['name'][0]['data'], self::CONSTRUCT_TEXT); } if (isset($contributor['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'])) { $url = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_03]['url'][0]['data'], self::CONSTRUCT_IRI, $this->get_base($contributor['child'][self::NAMESPACE_ATOM_03]['url'][0])); } if (isset($contributor['child'][self::NAMESPACE_ATOM_03]['email'][0]['data'])) { $email = $this->sanitize($contributor['child'][self::NAMESPACE_ATOM_03]['email'][0]['data'], self::CONSTRUCT_TEXT); } if ($name !== null || $email !== null || $url !== null) { $contributors[] = $this->registry->create(Author::class, [$name, $url, $email]); } } if (!empty($contributors)) { return array_unique($contributors); } return null; } /** * Get a single link for the feed * * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8) * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 * @param string $rel The relationship of the link to return * @return string|null Link URL */ public function get_link($key = 0, $rel = 'alternate') { $links = $this->get_links($rel); if (isset($links[$key])) { return $links[$key]; } return null; } /** * Get the permalink for the item * * Returns the first link available with a relationship of "alternate". * Identical to {@see get_link()} with key 0 * * @see get_link * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8) * @internal Added for parity between the parent-level and the item/entry-level. * @return string|null Link URL */ public function get_permalink() { return $this->get_link(0); } /** * Get all links for the feed * * Uses `<atom:link>` or `<link>` * * @since Beta 2 * @param string $rel The relationship of links to return * @return array|null Links found for the feed (strings) */ public function get_links($rel = 'alternate') { if (!isset($this->data['links'])) { $this->data['links'] = []; if ($links = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'link')) { foreach ($links as $link) { if (isset($link['attribs']['']['href'])) { $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], self::CONSTRUCT_IRI, $this->get_base($link)); } } } if ($links = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'link')) { foreach ($links as $link) { if (isset($link['attribs']['']['href'])) { $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], self::CONSTRUCT_IRI, $this->get_base($link)); } } } if ($links = $this->get_channel_tags(self::NAMESPACE_RSS_10, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], self::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_channel_tags(self::NAMESPACE_RSS_090, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], self::CONSTRUCT_IRI, $this->get_base($links[0])); } if ($links = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'link')) { $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], self::CONSTRUCT_IRI, $this->get_base($links[0])); } $keys = array_keys($this->data['links']); foreach ($keys as $key) { if ($this->registry->call(Misc::class, 'is_isegment_nz_nc', [$key])) { if (isset($this->data['links'][self::IANA_LINK_RELATIONS_REGISTRY . $key])) { $this->data['links'][self::IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][self::IANA_LINK_RELATIONS_REGISTRY . $key]); $this->data['links'][$key] = &$this->data['links'][self::IANA_LINK_RELATIONS_REGISTRY . $key]; } else { $this->data['links'][self::IANA_LINK_RELATIONS_REGISTRY . $key] = &$this->data['links'][$key]; } } elseif (substr($key, 0, 41) === self::IANA_LINK_RELATIONS_REGISTRY) { $this->data['links'][substr($key, 41)] = &$this->data['links'][$key]; } $this->data['links'][$key] = array_unique($this->data['links'][$key]); } } if (isset($this->data['headers']['link'])) { $link_headers = $this->data['headers']['link']; if (is_array($link_headers)) { $link_headers = implode(',', $link_headers); } // https://datatracker.ietf.org/doc/html/rfc8288 if (is_string($link_headers) && preg_match_all('/<(?P<uri>[^>]+)>\s*;\s*rel\s*=\s*(?P<quote>"?)' . preg_quote($rel) . '(?P=quote)\s*(?=,|$)/i', $link_headers, $matches)) { return $matches['uri']; } } if (isset($this->data['links'][$rel])) { return $this->data['links'][$rel]; } return null; } public function get_all_discovered_feeds() { return $this->all_discovered_feeds; } /** * Get the content for the item * * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`, * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>` * * @since 1.0 (previously called `get_feed_description()` since 0.8) * @return string|null */ public function get_description() { if ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'subtitle')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'tagline')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_10, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_090, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'description')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ITUNES, 'summary')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_HTML, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ITUNES, 'subtitle')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_HTML, $this->get_base($return[0])); } return null; } /** * Get the copyright info for the feed * * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>` * * @since 1.0 (previously called `get_feed_copyright()` since 0.8) * @return string|null */ public function get_copyright() { if ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'rights')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_03, 'copyright')) { return $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'copyright')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'rights')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'rights')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } return null; } /** * Get the language for the feed * * Uses `<language>`, `<dc:language>`, or @xml_lang * * @since 1.0 (previously called `get_feed_language()` since 0.8) * @return string|null */ public function get_language() { if ($return = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'language')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_11, 'language')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_DC_10, 'language')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['child'][self::NAMESPACE_ATOM_10]['feed'][0]['xml_lang'])) { return $this->sanitize($this->data['child'][self::NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['child'][self::NAMESPACE_ATOM_03]['feed'][0]['xml_lang'])) { return $this->sanitize($this->data['child'][self::NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['xml_lang'])) { return $this->sanitize($this->data['child'][self::NAMESPACE_RDF]['RDF'][0]['xml_lang'], self::CONSTRUCT_TEXT); } elseif (isset($this->data['headers']['content-language'])) { return $this->sanitize($this->data['headers']['content-language'], self::CONSTRUCT_TEXT); } return null; } /** * Get the latitude coordinates for the item * * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications * * Uses `<geo:lat>` or `<georss:point>` * * @since 1.0 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo * @link http://www.georss.org/ GeoRSS * @return string|null */ public function get_latitude() { if ($return = $this->get_channel_tags(self::NAMESPACE_W3C_BASIC_GEO, 'lat')) { return (float) $return[0]['data']; } elseif (($return = $this->get_channel_tags(self::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) { return (float) $match[1]; } return null; } /** * Get the longitude coordinates for the feed * * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications * * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>` * * @since 1.0 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo * @link http://www.georss.org/ GeoRSS * @return string|null */ public function get_longitude() { if ($return = $this->get_channel_tags(self::NAMESPACE_W3C_BASIC_GEO, 'long')) { return (float) $return[0]['data']; } elseif ($return = $this->get_channel_tags(self::NAMESPACE_W3C_BASIC_GEO, 'lon')) { return (float) $return[0]['data']; } elseif (($return = $this->get_channel_tags(self::NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) { return (float) $match[2]; } return null; } /** * Get the feed logo's title * * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title. * * Uses `<image><title>` or `<image><dc:title>` * * @return string|null */ public function get_image_title() { if ($return = $this->get_image_tags(self::NAMESPACE_RSS_10, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_090, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_image_tags(self::NAMESPACE_DC_11, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } elseif ($return = $this->get_image_tags(self::NAMESPACE_DC_10, 'title')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_TEXT); } return null; } /** * Get the feed logo's URL * * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to * have a "feed logo" URL. This points directly to the image itself. * * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`, * `<image><title>` or `<image><dc:title>` * * @return string|null */ public function get_image_url() { if ($return = $this->get_channel_tags(self::NAMESPACE_ITUNES, 'image')) { return $this->sanitize($return[0]['attribs']['']['href'], self::CONSTRUCT_IRI); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'logo')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_channel_tags(self::NAMESPACE_ATOM_10, 'icon')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_10, 'url')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_090, 'url')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'url')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } return null; } /** * Get the feed logo's link * * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This * points to a human-readable page that the image should link to. * * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`, * `<image><title>` or `<image><dc:title>` * * @return string|null */ public function get_image_link() { if ($return = $this->get_image_tags(self::NAMESPACE_RSS_10, 'link')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_090, 'link')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } elseif ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'link')) { return $this->sanitize($return[0]['data'], self::CONSTRUCT_IRI, $this->get_base($return[0])); } return null; } /** * Get the feed logo's link * * RSS 2.0 feeds are allowed to have a "feed logo" width. * * Uses `<image><width>` or defaults to 88 if no width is specified and * the feed is an RSS 2.0 feed. * * @return int|null */ public function get_image_width() { if ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'width')) { return intval($return[0]['data']); } elseif ($this->get_type() & self::TYPE_RSS_SYNDICATION && $this->get_image_tags(self::NAMESPACE_RSS_20, 'url')) { return 88; } return null; } /** * Get the feed logo's height * * RSS 2.0 feeds are allowed to have a "feed logo" height. * * Uses `<image><height>` or defaults to 31 if no height is specified and * the feed is an RSS 2.0 feed. * * @return int|null */ public function get_image_height() { if ($return = $this->get_image_tags(self::NAMESPACE_RSS_20, 'height')) { return intval($return[0]['data']); } elseif ($this->get_type() & self::TYPE_RSS_SYNDICATION && $this->get_image_tags(self::NAMESPACE_RSS_20, 'url')) { return 31; } return null; } /** * Get the number of items in the feed * * This is well-suited for {@link http://php.net/for for()} loops with * {@see get_item()} * * @param int $max Maximum value to return. 0 for no limit * @return int Number of items in the feed */ public function get_item_quantity($max = 0) { $max = (int) $max; $qty = count($this->get_items()); if ($max === 0) { return $qty; } return ($qty > $max) ? $max : $qty; } /** * Get a single item from the feed * * This is better suited for {@link http://php.net/for for()} loops, whereas * {@see get_items()} is better suited for * {@link http://php.net/foreach foreach()} loops. * * @see get_item_quantity() * @since Beta 2 * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1 * @return \SimplePie\Item|null */ public function get_item($key = 0) { $items = $this->get_items(); if (isset($items[$key])) { return $items[$key]; } return null; } /** * Get all items from the feed * * This is better suited for {@link http://php.net/for for()} loops, whereas * {@see get_items()} is better suited for * {@link http://php.net/foreach foreach()} loops. * * @see get_item_quantity * @since Beta 2 * @param int $start Index to start at * @param int $end Number of items to return. 0 for all items after `$start` * @return \SimplePie\Item[]|null List of {@see \SimplePie\Item} objects */ public function get_items($start = 0, $end = 0) { if (!isset($this->data['items'])) { if (!empty($this->multifeed_objects)) { $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit); if (empty($this->data['items'])) { return []; } return $this->data['items']; } $this->data['items'] = []; if ($items = $this->get_feed_tags(self::NAMESPACE_ATOM_10, 'entry')) { $keys = array_keys($items); foreach ($keys as $key) { $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]); } } if ($items = $this->get_feed_tags(self::NAMESPACE_ATOM_03, 'entry')) { $keys = array_keys($items); foreach ($keys as $key) { $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]); } } if ($items = $this->get_feed_tags(self::NAMESPACE_RSS_10, 'item')) { $keys = array_keys($items); foreach ($keys as $key) { $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]); } } if ($items = $this->get_feed_tags(self::NAMESPACE_RSS_090, 'item')) { $keys = array_keys($items); foreach ($keys as $key) { $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]); } } if ($items = $this->get_channel_tags(self::NAMESPACE_RSS_20, 'item')) { $keys = array_keys($items); foreach ($keys as $key) { $this->data['items'][] = $this->registry->create(Item::class, [$this, $items[$key]]); } } } if (empty($this->data['items'])) { return []; } if ($this->order_by_date) { if (!isset($this->data['ordered_items'])) { $this->data['ordered_items'] = $this->data['items']; usort($this->data['ordered_items'], [get_class($this), 'sort_items']); } $items = $this->data['ordered_items']; } else { $items = $this->data['items']; } // Slice the data as desired if ($end === 0) { return array_slice($items, $start); } return array_slice($items, $start, $end); } /** * Set the favicon handler * * @deprecated Use your own favicon handling instead */ public function set_favicon_handler($page = false, $qs = 'i') { trigger_error('Favicon handling has been removed, please use your own handling', \E_USER_DEPRECATED); return false; } /** * Get the favicon for the current feed * * @deprecated Use your own favicon handling instead */ public function get_favicon() { trigger_error('Favicon handling has been removed, please use your own handling', \E_USER_DEPRECATED); if (($url = $this->get_link()) !== null) { return 'https://www.google.com/s2/favicons?domain=' . urlencode($url); } return false; } /** * Magic method handler * * @param string $method Method name * @param array $args Arguments to the method * @return mixed */ public function __call($method, $args) { if (strpos($method, 'subscribe_') === 0) { trigger_error('subscribe_*() has been deprecated, implement the callback yourself', \E_USER_DEPRECATED); return ''; } if ($method === 'enable_xml_dump') { trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', \E_USER_DEPRECATED); return false; } $class = get_class($this); $trace = debug_backtrace(); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection $file = $trace[0]['file']; $line = $trace[0]['line']; throw new SimplePieException("Call to undefined method $class::$method() in $file on line $line"); } /** * Sorting callback for items * * @access private * @param SimplePie $a * @param SimplePie $b * @return boolean */ public static function sort_items($a, $b) { $a_date = $a->get_date('U'); $b_date = $b->get_date('U'); if ($a_date && $b_date) { return $a_date > $b_date ? -1 : 1; } // Sort items without dates to the top. if ($a_date) { return 1; } if ($b_date) { return -1; } return 0; } /** * Merge items from several feeds into one * * If you're merging multiple feeds together, they need to all have dates * for the items or else SimplePie will refuse to sort them. * * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings * @param array $urls List of SimplePie feed objects to merge * @param int $start Starting item * @param int $end Number of items to return * @param int $limit Maximum number of items per feed * @return array */ public static function merge_items($urls, $start = 0, $end = 0, $limit = 0) { if (is_array($urls) && sizeof($urls) > 0) { $items = []; foreach ($urls as $arg) { if ($arg instanceof SimplePie) { $items = array_merge($items, $arg->get_items(0, $limit)); } else { trigger_error('Arguments must be SimplePie objects', E_USER_WARNING); } } usort($items, [get_class($urls[0]), 'sort_items']); if ($end === 0) { return array_slice($items, $start); } return array_slice($items, $start, $end); } trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING); return []; } /** * Store PubSubHubbub links as headers * * There is no way to find PuSH links in the body of a microformats feed, * so they are added to the headers when found, to be used later by get_links. * @param \SimplePie\File $file * @param string $hub * @param string $self */ private function store_links(&$file, $hub, $self) { if (isset($file->headers['link']['hub']) || (isset($file->headers['link']) && preg_match('/rel=hub/', $file->headers['link']))) { return; } if ($hub) { if (isset($file->headers['link'])) { if ($file->headers['link'] !== '') { $file->headers['link'] = ', '; } } else { $file->headers['link'] = ''; } $file->headers['link'] .= '<'.$hub.'>; rel=hub'; if ($self) { $file->headers['link'] .= ', <'.$self.'>; rel=self'; } } } /** * Get a DataCache * * @param string $feed_url Only needed for BC, can be removed in SimplePie 2.0.0 * * @return DataCache */ private function get_cache($feed_url = '') { if ($this->cache === null) { // @trigger_error(sprintf('Not providing as PSR-16 cache implementation is deprecated since SimplePie 1.8.0, please use "SimplePie\SimplePie::set_cache()".'), \E_USER_DEPRECATED); $cache = $this->registry->call(Cache::class, 'get_handler', [ $this->cache_location, $this->get_cache_filename($feed_url), Base::TYPE_FEED ]); return new BaseDataCache($cache); } return $this->cache; } } class_alias('SimplePie\SimplePie', 'SimplePie'); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Cache.php�������������������������������������������������������������������������������������������0000644�����������������00000011363�15021155231�0006257 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; use SimplePie\Cache\Base; /** * Used to create cache objects * * This class can be overloaded with {@see SimplePie::set_cache_class()}, * although the preferred way is to create your own handler * via {@see register()} * * @package SimplePie * @subpackage Caching * @deprecated since SimplePie 1.8.0, use "SimplePie\SimplePie::set_cache()" instead */ class Cache { /** * Cache handler classes * * These receive 3 parameters to their constructor, as documented in * {@see register()} * @var array */ protected static $handlers = [ 'mysql' => 'SimplePie\Cache\MySQL', 'memcache' => 'SimplePie\Cache\Memcache', 'memcached' => 'SimplePie\Cache\Memcached', 'redis' => 'SimplePie\Cache\Redis' ]; /** * Don't call the constructor. Please. */ private function __construct() { } /** * Create a new SimplePie\Cache object * * @param string $location URL location (scheme is used to determine handler) * @param string $filename Unique identifier for cache object * @param Base::TYPE_FEED|Base::TYPE_IMAGE $extension 'spi' or 'spc' * @return Base Type of object depends on scheme of `$location` */ public static function get_handler($location, $filename, $extension) { $type = explode(':', $location, 2); $type = $type[0]; if (!empty(self::$handlers[$type])) { $class = self::$handlers[$type]; return new $class($location, $filename, $extension); } return new \SimplePie\Cache\File($location, $filename, $extension); } /** * Create a new SimplePie\Cache object * * @deprecated since SimplePie 1.3.1, use {@see get_handler()} instead */ public function create($location, $filename, $extension) { trigger_error('Cache::create() has been replaced with Cache::get_handler() since SimplePie 1.3.1, use the registry system instead.', \E_USER_DEPRECATED); return self::get_handler($location, $filename, $extension); } /** * Register a handler * * @param string $type DSN type to register for * @param class-string<Base> $class Name of handler class. Must implement Base */ public static function register($type, $class) { self::$handlers[$type] = $class; } /** * Parse a URL into an array * * @param string $url * @return array */ public static function parse_URL($url) { $params = parse_url($url); $params['extras'] = []; if (isset($params['query'])) { parse_str($params['query'], $params['extras']); } return $params; } } class_alias('SimplePie\Cache', 'SimplePie_Cache'); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Net/IPv6.php����������������������������������������������������������������������������������������0000644�����������������00000021041�15021155231�0006560 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie\Net; /** * Class to validate and to work with IPv6 addresses. * * @package SimplePie * @subpackage HTTP * @copyright 2003-2005 The PHP Group * @license http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/package/Net_IPv6 * @author Alexander Merz <alexander.merz@web.de> * @author elfrink at introweb dot nl * @author Josh Peck <jmp at joshpeck dot org> * @author Sam Sneddon <geoffers@gmail.com> */ class IPv6 { /** * Uncompresses an IPv6 address * * RFC 4291 allows you to compress concecutive zero pieces in an address to * '::'. This method expects a valid IPv6 address and expands the '::' to * the required number of zero pieces. * * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 * ::1 -> 0:0:0:0:0:0:0:1 * * @author Alexander Merz <alexander.merz@web.de> * @author elfrink at introweb dot nl * @author Josh Peck <jmp at joshpeck dot org> * @copyright 2003-2005 The PHP Group * @license http://www.opensource.org/licenses/bsd-license.php * @param string $ip An IPv6 address * @return string The uncompressed IPv6 address */ public static function uncompress($ip) { $c1 = -1; $c2 = -1; if (substr_count($ip, '::') === 1) { [$ip1, $ip2] = explode('::', $ip); if ($ip1 === '') { $c1 = -1; } else { $c1 = substr_count($ip1, ':'); } if ($ip2 === '') { $c2 = -1; } else { $c2 = substr_count($ip2, ':'); } if (strpos($ip2, '.') !== false) { $c2++; } // :: if ($c1 === -1 && $c2 === -1) { $ip = '0:0:0:0:0:0:0:0'; } // ::xxx elseif ($c1 === -1) { $fill = str_repeat('0:', 7 - $c2); $ip = str_replace('::', $fill, $ip); } // xxx:: elseif ($c2 === -1) { $fill = str_repeat(':0', 7 - $c1); $ip = str_replace('::', $fill, $ip); } // xxx::xxx else { $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); $ip = str_replace('::', $fill, $ip); } } return $ip; } /** * Compresses an IPv6 address * * RFC 4291 allows you to compress concecutive zero pieces in an address to * '::'. This method expects a valid IPv6 address and compresses consecutive * zero pieces to '::'. * * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 * 0:0:0:0:0:0:0:1 -> ::1 * * @see uncompress() * @param string $ip An IPv6 address * @return string The compressed IPv6 address */ public static function compress($ip) { // Prepare the IP to be compressed $ip = self::uncompress($ip); $ip_parts = self::split_v6_v4($ip); // Replace all leading zeros $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]); // Find bunches of zeros if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) { $max = 0; $pos = null; foreach ($matches[0] as $match) { if (strlen($match[0]) > $max) { $max = strlen($match[0]); $pos = $match[1]; } } $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max); } if ($ip_parts[1] !== '') { return implode(':', $ip_parts); } return $ip_parts[0]; } /** * Splits an IPv6 address into the IPv6 and IPv4 representation parts * * RFC 4291 allows you to represent the last two parts of an IPv6 address * using the standard IPv4 representation * * Example: 0:0:0:0:0:0:13.1.68.3 * 0:0:0:0:0:FFFF:129.144.52.38 * * @param string $ip An IPv6 address * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part */ private static function split_v6_v4($ip) { if (strpos($ip, '.') !== false) { $pos = strrpos($ip, ':'); $ipv6_part = substr($ip, 0, $pos); $ipv4_part = substr($ip, $pos + 1); return [$ipv6_part, $ipv4_part]; } return [$ip, '']; } /** * Checks an IPv6 address * * Checks if the given IP is a valid IPv6 address * * @param string $ip An IPv6 address * @return bool true if $ip is a valid IPv6 address */ public static function check_ipv6($ip) { $ip = self::uncompress($ip); [$ipv6, $ipv4] = self::split_v6_v4($ip); $ipv6 = explode(':', $ipv6); $ipv4 = explode('.', $ipv4); if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) { foreach ($ipv6 as $ipv6_part) { // The section can't be empty if ($ipv6_part === '') { return false; } // Nor can it be over four characters if (strlen($ipv6_part) > 4) { return false; } // Remove leading zeros (this is safe because of the above) $ipv6_part = ltrim($ipv6_part, '0'); if ($ipv6_part === '') { $ipv6_part = '0'; } // Check the value is valid $value = hexdec($ipv6_part); if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) { return false; } } if (count($ipv4) === 4) { foreach ($ipv4 as $ipv4_part) { $value = (int) $ipv4_part; if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) { return false; } } } return true; } return false; } /** * Checks if the given IP is a valid IPv6 address * * @codeCoverageIgnore * @deprecated Use {@see IPv6::check_ipv6()} instead * @see check_ipv6 * @param string $ip An IPv6 address * @return bool true if $ip is a valid IPv6 address */ public static function checkIPv6($ip) { return self::check_ipv6($ip); } } class_alias('SimplePie\Net\IPv6', 'SimplePie_Net_IPv6'); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Decode/HTML/Entities.php����������������������������������������������������������������������������0000644�����������������00000041531�15021155231�0010767 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2016, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ /** * Decode HTML Entities * * This implements HTML5 as of revision 967 (2007-06-28) * * @deprecated Use DOMDocument instead! * @package SimplePie */ class SimplePie_Decode_HTML_Entities { /** * Data to be parsed * * @access private * @var string */ var $data = ''; /** * Currently consumed bytes * * @access private * @var string */ var $consumed = ''; /** * Position of the current byte being parsed * * @access private * @var int */ var $position = 0; /** * Create an instance of the class with the input data * * @access public * @param string $data Input data */ public function __construct($data) { $this->data = $data; } /** * Parse the input data * * @access public * @return string Output data */ public function parse() { while (($this->position = strpos($this->data, '&', $this->position)) !== false) { $this->consume(); $this->entity(); $this->consumed = ''; } return $this->data; } /** * Consume the next byte * * @access private * @return mixed The next byte, or false, if there is no more data */ public function consume() { if (isset($this->data[$this->position])) { $this->consumed .= $this->data[$this->position]; return $this->data[$this->position++]; } return false; } /** * Consume a range of characters * * @access private * @param string $chars Characters to consume * @return mixed A series of characters that match the range, or false */ public function consume_range($chars) { if ($len = strspn($this->data, $chars, $this->position)) { $data = substr($this->data, $this->position, $len); $this->consumed .= $data; $this->position += $len; return $data; } return false; } /** * Unconsume one byte * * @access private */ public function unconsume() { $this->consumed = substr($this->consumed, 0, -1); $this->position--; } /** * Decode an entity * * @access private */ public function entity() { switch ($this->consume()) { case "\x09": case "\x0A": case "\x0B": case "\x0C": case "\x20": case "\x3C": case "\x26": case false: break; case "\x23": switch ($this->consume()) { case "\x78": case "\x58": $range = '0123456789ABCDEFabcdef'; $hex = true; break; default: $range = '0123456789'; $hex = false; $this->unconsume(); break; } if ($codepoint = $this->consume_range($range)) { static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8"); if ($hex) { $codepoint = hexdec($codepoint); } else { $codepoint = intval($codepoint); } if (isset($windows_1252_specials[$codepoint])) { $replacement = $windows_1252_specials[$codepoint]; } else { $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); } if (!in_array($this->consume(), array(';', false), true)) { $this->unconsume(); } $consumed_length = strlen($this->consumed); $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); $this->position += strlen($replacement) - $consumed_length; } break; default: static $entities = array( 'Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C" ); for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++) { $consumed = substr($this->consumed, 1); if (isset($entities[$consumed])) { $match = $consumed; } } if ($match !== null) { $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); $this->position += strlen($entities[$match]) - strlen($consumed) - 1; } break; } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������Parser.php������������������������������������������������������������������������������������������0000644�����������������00000103543�15021155231�0006512 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; use SimplePie\XML\Declaration\Parser as DeclarationParser; /** * Parses XML into something sane * * * This class can be overloaded with {@see \SimplePie\SimplePie::set_parser_class()} * * @package SimplePie * @subpackage Parsing */ class Parser implements RegistryAware { public $error_code; public $error_string; public $current_line; public $current_column; public $current_byte; public $separator = ' '; public $namespace = ['']; public $element = ['']; public $xml_base = ['']; public $xml_base_explicit = [false]; public $xml_lang = ['']; public $data = []; public $datas = [[]]; public $current_xhtml_construct = -1; public $encoding; protected $registry; public function set_registry(\SimplePie\Registry $registry)/* : void */ { $this->registry = $registry; } public function parse(&$data, $encoding, $url = '') { if (class_exists('DOMXpath') && function_exists('Mf2\parse')) { $doc = new \DOMDocument(); @$doc->loadHTML($data); $xpath = new \DOMXpath($doc); // Check for both h-feed and h-entry, as both a feed with no entries // and a list of entries without an h-feed wrapper are both valid. $query = '//*[contains(concat(" ", @class, " "), " h-feed ") or '. 'contains(concat(" ", @class, " "), " h-entry ")]'; $result = $xpath->query($query); if ($result->length !== 0) { return $this->parse_microformats($data, $url); } } // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character if (strtoupper($encoding) === 'US-ASCII') { $this->encoding = 'UTF-8'; } else { $this->encoding = $encoding; } // Strip BOM: // UTF-32 Big Endian BOM if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") { $data = substr($data, 4); } // UTF-32 Little Endian BOM elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") { $data = substr($data, 4); } // UTF-16 Big Endian BOM elseif (substr($data, 0, 2) === "\xFE\xFF") { $data = substr($data, 2); } // UTF-16 Little Endian BOM elseif (substr($data, 0, 2) === "\xFF\xFE") { $data = substr($data, 2); } // UTF-8 BOM elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") { $data = substr($data, 3); } if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false) { $declaration = $this->registry->create(DeclarationParser::class, [substr($data, 5, $pos - 5)]); if ($declaration->parse()) { $data = substr($data, $pos + 2); $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' ."\n". $this->declare_html_entities() . $data; } else { $this->error_string = 'SimplePie bug! Please report this!'; return false; } } $return = true; static $xml_is_sane = null; if ($xml_is_sane === null) { $parser_check = xml_parser_create(); xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); xml_parser_free($parser_check); $xml_is_sane = isset($values[0]['value']); } // Create the parser if ($xml_is_sane) { $xml = xml_parser_create_ns($this->encoding, $this->separator); xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); xml_set_character_data_handler($xml, [$this, 'cdata']); xml_set_element_handler($xml, [$this, 'tag_open'], [$this, 'tag_close']); // Parse! $wrapper = @is_writable(sys_get_temp_dir()) ? 'php://temp' : 'php://memory'; if (($stream = fopen($wrapper, 'r+')) && fwrite($stream, $data) && rewind($stream)) { //Parse by chunks not to use too much memory do { $stream_data = fread($stream, 1048576); if (!xml_parse($xml, $stream_data === false ? '' : $stream_data, feof($stream))) { $this->error_code = xml_get_error_code($xml); $this->error_string = xml_error_string($this->error_code); $return = false; break; } } while (!feof($stream)); fclose($stream); } else { $return = false; } $this->current_line = xml_get_current_line_number($xml); $this->current_column = xml_get_current_column_number($xml); $this->current_byte = xml_get_current_byte_index($xml); xml_parser_free($xml); return $return; } libxml_clear_errors(); $xml = new \XMLReader(); $xml->xml($data); while (@$xml->read()) { switch ($xml->nodeType) { case constant('XMLReader::END_ELEMENT'): if ($xml->namespaceURI !== '') { $tagName = $xml->namespaceURI . $this->separator . $xml->localName; } else { $tagName = $xml->localName; } $this->tag_close(null, $tagName); break; case constant('XMLReader::ELEMENT'): $empty = $xml->isEmptyElement; if ($xml->namespaceURI !== '') { $tagName = $xml->namespaceURI . $this->separator . $xml->localName; } else { $tagName = $xml->localName; } $attributes = []; while ($xml->moveToNextAttribute()) { if ($xml->namespaceURI !== '') { $attrName = $xml->namespaceURI . $this->separator . $xml->localName; } else { $attrName = $xml->localName; } $attributes[$attrName] = $xml->value; } $this->tag_open(null, $tagName, $attributes); if ($empty) { $this->tag_close(null, $tagName); } break; case constant('XMLReader::TEXT'): case constant('XMLReader::CDATA'): $this->cdata(null, $xml->value); break; } } if ($error = libxml_get_last_error()) { $this->error_code = $error->code; $this->error_string = $error->message; $this->current_line = $error->line; $this->current_column = $error->column; return false; } return true; } public function get_error_code() { return $this->error_code; } public function get_error_string() { return $this->error_string; } public function get_current_line() { return $this->current_line; } public function get_current_column() { return $this->current_column; } public function get_current_byte() { return $this->current_byte; } public function get_data() { return $this->data; } public function tag_open($parser, $tag, $attributes) { [$this->namespace[], $this->element[]] = $this->split_ns($tag); $attribs = []; foreach ($attributes as $name => $value) { [$attrib_namespace, $attribute] = $this->split_ns($name); $attribs[$attrib_namespace][$attribute] = $value; } if (isset($attribs[\SimplePie\SimplePie::NAMESPACE_XML]['base'])) { $base = $this->registry->call(Misc::class, 'absolutize_url', [$attribs[\SimplePie\SimplePie::NAMESPACE_XML]['base'], end($this->xml_base)]); if ($base !== false) { $this->xml_base[] = $base; $this->xml_base_explicit[] = true; } } else { $this->xml_base[] = end($this->xml_base); $this->xml_base_explicit[] = end($this->xml_base_explicit); } if (isset($attribs[\SimplePie\SimplePie::NAMESPACE_XML]['lang'])) { $this->xml_lang[] = $attribs[\SimplePie\SimplePie::NAMESPACE_XML]['lang']; } else { $this->xml_lang[] = end($this->xml_lang); } if ($this->current_xhtml_construct >= 0) { $this->current_xhtml_construct++; if (end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_XHTML) { $this->data['data'] .= '<' . end($this->element); if (isset($attribs[''])) { foreach ($attribs[''] as $name => $value) { $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"'; } } $this->data['data'] .= '>'; } } else { $this->datas[] = &$this->data; $this->data = &$this->data['child'][end($this->namespace)][end($this->element)][]; $this->data = ['data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang)]; if ((end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_ATOM_03 && in_array(end($this->element), ['title', 'tagline', 'copyright', 'info', 'summary', 'content']) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml') || (end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_ATOM_10 && in_array(end($this->element), ['rights', 'subtitle', 'summary', 'info', 'title', 'content']) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml') || (end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_RSS_20 && in_array(end($this->element), ['title'])) || (end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_RSS_090 && in_array(end($this->element), ['title'])) || (end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_RSS_10 && in_array(end($this->element), ['title']))) { $this->current_xhtml_construct = 0; } } } public function cdata($parser, $cdata) { if ($this->current_xhtml_construct >= 0) { $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); } else { $this->data['data'] .= $cdata; } } public function tag_close($parser, $tag) { if ($this->current_xhtml_construct >= 0) { $this->current_xhtml_construct--; if (end($this->namespace) === \SimplePie\SimplePie::NAMESPACE_XHTML && !in_array(end($this->element), ['area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'])) { $this->data['data'] .= '</' . end($this->element) . '>'; } } if ($this->current_xhtml_construct === -1) { $this->data = &$this->datas[count($this->datas) - 1]; array_pop($this->datas); } array_pop($this->element); array_pop($this->namespace); array_pop($this->xml_base); array_pop($this->xml_base_explicit); array_pop($this->xml_lang); } public function split_ns($string) { static $cache = []; if (!isset($cache[$string])) { if ($pos = strpos($string, $this->separator)) { static $separator_length; if (!$separator_length) { $separator_length = strlen($this->separator); } $namespace = substr($string, 0, $pos); $local_name = substr($string, $pos + $separator_length); if (strtolower($namespace) === \SimplePie\SimplePie::NAMESPACE_ITUNES) { $namespace = \SimplePie\SimplePie::NAMESPACE_ITUNES; } // Normalize the Media RSS namespaces if ($namespace === \SimplePie\SimplePie::NAMESPACE_MEDIARSS_WRONG || $namespace === \SimplePie\SimplePie::NAMESPACE_MEDIARSS_WRONG2 || $namespace === \SimplePie\SimplePie::NAMESPACE_MEDIARSS_WRONG3 || $namespace === \SimplePie\SimplePie::NAMESPACE_MEDIARSS_WRONG4 || $namespace === \SimplePie\SimplePie::NAMESPACE_MEDIARSS_WRONG5) { $namespace = \SimplePie\SimplePie::NAMESPACE_MEDIARSS; } $cache[$string] = [$namespace, $local_name]; } else { $cache[$string] = ['', $string]; } } return $cache[$string]; } private function parse_hcard($data, $category = false) { $name = ''; $link = ''; // Check if h-card is set and pass that information on in the link. if (isset($data['type']) && in_array('h-card', $data['type'])) { if (isset($data['properties']['name'][0])) { $name = $data['properties']['name'][0]; } if (isset($data['properties']['url'][0])) { $link = $data['properties']['url'][0]; if ($name === '') { $name = $link; } else { // can't have commas in categories. $name = str_replace(',', '', $name); } $person_tag = $category ? '<span class="person-tag"></span>' : ''; return '<a class="h-card" href="'.$link.'">'.$person_tag.$name.'</a>'; } } return $data['value'] ?? ''; } private function parse_microformats(&$data, $url) { $feed_title = ''; $feed_author = null; $author_cache = []; $items = []; $entries = []; $mf = \Mf2\parse($data, $url); // First look for an h-feed. $h_feed = []; foreach ($mf['items'] as $mf_item) { if (in_array('h-feed', $mf_item['type'])) { $h_feed = $mf_item; break; } // Also look for h-feed or h-entry in the children of each top level item. if (!isset($mf_item['children'][0]['type'])) { continue; } if (in_array('h-feed', $mf_item['children'][0]['type'])) { $h_feed = $mf_item['children'][0]; // In this case the parent of the h-feed may be an h-card, so use it as // the feed_author. if (in_array('h-card', $mf_item['type'])) { $feed_author = $mf_item; } break; } elseif (in_array('h-entry', $mf_item['children'][0]['type'])) { $entries = $mf_item['children']; // In this case the parent of the h-entry list may be an h-card, so use // it as the feed_author. if (in_array('h-card', $mf_item['type'])) { $feed_author = $mf_item; } break; } } if (isset($h_feed['children'])) { $entries = $h_feed['children']; // Also set the feed title and store author from the h-feed if available. if (isset($mf['items'][0]['properties']['name'][0])) { $feed_title = $mf['items'][0]['properties']['name'][0]; } if (isset($mf['items'][0]['properties']['author'][0])) { $feed_author = $mf['items'][0]['properties']['author'][0]; } } elseif (count($entries) === 0) { $entries = $mf['items']; } for ($i = 0; $i < count($entries); $i++) { $entry = $entries[$i]; if (in_array('h-entry', $entry['type'])) { $item = []; $title = ''; $description = ''; if (isset($entry['properties']['url'][0])) { $link = $entry['properties']['url'][0]; if (isset($link['value'])) { $link = $link['value']; } $item['link'] = [['data' => $link]]; } if (isset($entry['properties']['uid'][0])) { $guid = $entry['properties']['uid'][0]; if (isset($guid['value'])) { $guid = $guid['value']; } $item['guid'] = [['data' => $guid]]; } if (isset($entry['properties']['name'][0])) { $title = $entry['properties']['name'][0]; if (isset($title['value'])) { $title = $title['value']; } $item['title'] = [['data' => $title]]; } if (isset($entry['properties']['author'][0]) || isset($feed_author)) { // author is a special case, it can be plain text or an h-card array. // If it's plain text it can also be a url that should be followed to // get the actual h-card. $author = $entry['properties']['author'][0] ?? $feed_author; if (!is_string($author)) { $author = $this->parse_hcard($author); } elseif (strpos($author, 'http') === 0) { if (isset($author_cache[$author])) { $author = $author_cache[$author]; } else { $mf = \Mf2\fetch($author); foreach ($mf['items'] as $hcard) { // Only interested in an h-card by itself in this case. if (!in_array('h-card', $hcard['type'])) { continue; } // It must have a url property matching what we fetched. if (!isset($hcard['properties']['url']) || !(in_array($author, $hcard['properties']['url']))) { continue; } // Save parse_hcard the trouble of finding the correct url. $hcard['properties']['url'][0] = $author; // Cache this h-card for the next h-entry to check. $author_cache[$author] = $this->parse_hcard($hcard); $author = $author_cache[$author]; break; } } } $item['author'] = [['data' => $author]]; } if (isset($entry['properties']['photo'][0])) { // If a photo is also in content, don't need to add it again here. $content = ''; if (isset($entry['properties']['content'][0]['html'])) { $content = $entry['properties']['content'][0]['html']; } $photo_list = []; for ($j = 0; $j < count($entry['properties']['photo']); $j++) { $photo = $entry['properties']['photo'][$j]; if (!empty($photo) && strpos($content, $photo) === false) { $photo_list[] = $photo; } } // When there's more than one photo show the first and use a lightbox. // Need a permanent, unique name for the image set, but don't have // anything unique except for the content itself, so use that. $count = count($photo_list); if ($count > 1) { $image_set_id = preg_replace('/[[:^alnum:]]/', '', $photo_list[0]); $description = '<p>'; for ($j = 0; $j < $count; $j++) { $hidden = $j === 0 ? '' : 'class="hidden" '; $description .= '<a href="'.$photo_list[$j].'" '.$hidden. 'data-lightbox="image-set-'.$image_set_id.'">'. '<img src="'.$photo_list[$j].'"></a>'; } $description .= '<br><b>'.$count.' photos</b></p>'; } elseif ($count == 1) { $description = '<p><img src="'.$photo_list[0].'"></p>'; } } if (isset($entry['properties']['content'][0]['html'])) { // e-content['value'] is the same as p-name when they are on the same // element. Use this to replace title with a strip_tags version so // that alt text from images is not included in the title. if ($entry['properties']['content'][0]['value'] === $title) { $title = strip_tags($entry['properties']['content'][0]['html']); $item['title'] = [['data' => $title]]; } $description .= $entry['properties']['content'][0]['html']; if (isset($entry['properties']['in-reply-to'][0])) { $in_reply_to = ''; if (is_string($entry['properties']['in-reply-to'][0])) { $in_reply_to = $entry['properties']['in-reply-to'][0]; } elseif (isset($entry['properties']['in-reply-to'][0]['value'])) { $in_reply_to = $entry['properties']['in-reply-to'][0]['value']; } if ($in_reply_to !== '') { $description .= '<p><span class="in-reply-to"></span> '. '<a href="'.$in_reply_to.'">'.$in_reply_to.'</a><p>'; } } $item['description'] = [['data' => $description]]; } if (isset($entry['properties']['category'])) { $category_csv = ''; // Categories can also contain h-cards. foreach ($entry['properties']['category'] as $category) { if ($category_csv !== '') { $category_csv .= ', '; } if (is_string($category)) { // Can't have commas in categories. $category_csv .= str_replace(',', '', $category); } else { $category_csv .= $this->parse_hcard($category, true); } } $item['category'] = [['data' => $category_csv]]; } if (isset($entry['properties']['published'][0])) { $timestamp = strtotime($entry['properties']['published'][0]); $pub_date = date('F j Y g:ia', $timestamp).' GMT'; $item['pubDate'] = [['data' => $pub_date]]; } // The title and description are set to the empty string to represent // a deleted item (which also makes it an invalid rss item). if (isset($entry['properties']['deleted'][0])) { $item['title'] = [['data' => '']]; $item['description'] = [['data' => '']]; } $items[] = ['child' => ['' => $item]]; } } // Mimic RSS data format when storing microformats. $link = [['data' => $url]]; $image = ''; if (!is_string($feed_author) && isset($feed_author['properties']['photo'][0])) { $image = [['child' => ['' => ['url' => [['data' => $feed_author['properties']['photo'][0]]]]]]]; } // Use the name given for the h-feed, or get the title from the html. if ($feed_title !== '') { $feed_title = [['data' => htmlspecialchars($feed_title)]]; } elseif ($position = strpos($data, '<title>')) { $start = $position < 200 ? 0 : $position - 200; $check = substr($data, $start, 400); $matches = []; if (preg_match('/<title>(.+)<\/title>/', $check, $matches)) { $feed_title = [['data' => htmlspecialchars($matches[1])]]; } } $channel = ['channel' => [['child' => ['' => ['link' => $link, 'image' => $image, 'title' => $feed_title, 'item' => $items]]]]]; $rss = [['attribs' => ['' => ['version' => '2.0']], 'child' => ['' => $channel]]]; $this->data = ['child' => ['' => ['rss' => $rss]]]; return true; } private function declare_html_entities() { // This is required because the RSS specification says that entity-encoded // html is allowed, but the xml specification says they must be declared. return '<!DOCTYPE html [ <!ENTITY nbsp " "> <!ENTITY iexcl "¡"> <!ENTITY cent "¢"> <!ENTITY pound "£"> <!ENTITY curren "¤"> <!ENTITY yen "¥"> <!ENTITY brvbar "¦"> <!ENTITY sect "§"> <!ENTITY uml "¨"> <!ENTITY copy "©"> <!ENTITY ordf "ª"> <!ENTITY laquo "«"> <!ENTITY not "¬"> <!ENTITY shy "­"> <!ENTITY reg "®"> <!ENTITY macr "¯"> <!ENTITY deg "°"> <!ENTITY plusmn "±"> <!ENTITY sup2 "²"> <!ENTITY sup3 "³"> <!ENTITY acute "´"> <!ENTITY micro "µ"> <!ENTITY para "¶"> <!ENTITY middot "·"> <!ENTITY cedil "¸"> <!ENTITY sup1 "¹"> <!ENTITY ordm "º"> <!ENTITY raquo "»"> <!ENTITY frac14 "¼"> <!ENTITY frac12 "½"> <!ENTITY frac34 "¾"> <!ENTITY iquest "¿"> <!ENTITY Agrave "À"> <!ENTITY Aacute "Á"> <!ENTITY Acirc "Â"> <!ENTITY Atilde "Ã"> <!ENTITY Auml "Ä"> <!ENTITY Aring "Å"> <!ENTITY AElig "Æ"> <!ENTITY Ccedil "Ç"> <!ENTITY Egrave "È"> <!ENTITY Eacute "É"> <!ENTITY Ecirc "Ê"> <!ENTITY Euml "Ë"> <!ENTITY Igrave "Ì"> <!ENTITY Iacute "Í"> <!ENTITY Icirc "Î"> <!ENTITY Iuml "Ï"> <!ENTITY ETH "Ð"> <!ENTITY Ntilde "Ñ"> <!ENTITY Ograve "Ò"> <!ENTITY Oacute "Ó"> <!ENTITY Ocirc "Ô"> <!ENTITY Otilde "Õ"> <!ENTITY Ouml "Ö"> <!ENTITY times "×"> <!ENTITY Oslash "Ø"> <!ENTITY Ugrave "Ù"> <!ENTITY Uacute "Ú"> <!ENTITY Ucirc "Û"> <!ENTITY Uuml "Ü"> <!ENTITY Yacute "Ý"> <!ENTITY THORN "Þ"> <!ENTITY szlig "ß"> <!ENTITY agrave "à"> <!ENTITY aacute "á"> <!ENTITY acirc "â"> <!ENTITY atilde "ã"> <!ENTITY auml "ä"> <!ENTITY aring "å"> <!ENTITY aelig "æ"> <!ENTITY ccedil "ç"> <!ENTITY egrave "è"> <!ENTITY eacute "é"> <!ENTITY ecirc "ê"> <!ENTITY euml "ë"> <!ENTITY igrave "ì"> <!ENTITY iacute "í"> <!ENTITY icirc "î"> <!ENTITY iuml "ï"> <!ENTITY eth "ð"> <!ENTITY ntilde "ñ"> <!ENTITY ograve "ò"> <!ENTITY oacute "ó"> <!ENTITY ocirc "ô"> <!ENTITY otilde "õ"> <!ENTITY ouml "ö"> <!ENTITY divide "÷"> <!ENTITY oslash "ø"> <!ENTITY ugrave "ù"> <!ENTITY uacute "ú"> <!ENTITY ucirc "û"> <!ENTITY uuml "ü"> <!ENTITY yacute "ý"> <!ENTITY thorn "þ"> <!ENTITY yuml "ÿ"> <!ENTITY OElig "Œ"> <!ENTITY oelig "œ"> <!ENTITY Scaron "Š"> <!ENTITY scaron "š"> <!ENTITY Yuml "Ÿ"> <!ENTITY fnof "ƒ"> <!ENTITY circ "ˆ"> <!ENTITY tilde "˜"> <!ENTITY Alpha "Α"> <!ENTITY Beta "Β"> <!ENTITY Gamma "Γ"> <!ENTITY Epsilon "Ε"> <!ENTITY Zeta "Ζ"> <!ENTITY Eta "Η"> <!ENTITY Theta "Θ"> <!ENTITY Iota "Ι"> <!ENTITY Kappa "Κ"> <!ENTITY Lambda "Λ"> <!ENTITY Mu "Μ"> <!ENTITY Nu "Ν"> <!ENTITY Xi "Ξ"> <!ENTITY Omicron "Ο"> <!ENTITY Pi "Π"> <!ENTITY Rho "Ρ"> <!ENTITY Sigma "Σ"> <!ENTITY Tau "Τ"> <!ENTITY Upsilon "Υ"> <!ENTITY Phi "Φ"> <!ENTITY Chi "Χ"> <!ENTITY Psi "Ψ"> <!ENTITY Omega "Ω"> <!ENTITY alpha "α"> <!ENTITY beta "β"> <!ENTITY gamma "γ"> <!ENTITY delta "δ"> <!ENTITY epsilon "ε"> <!ENTITY zeta "ζ"> <!ENTITY eta "η"> <!ENTITY theta "θ"> <!ENTITY iota "ι"> <!ENTITY kappa "κ"> <!ENTITY lambda "λ"> <!ENTITY mu "μ"> <!ENTITY nu "ν"> <!ENTITY xi "ξ"> <!ENTITY omicron "ο"> <!ENTITY pi "π"> <!ENTITY rho "ρ"> <!ENTITY sigmaf "ς"> <!ENTITY sigma "σ"> <!ENTITY tau "τ"> <!ENTITY upsilon "υ"> <!ENTITY phi "φ"> <!ENTITY chi "χ"> <!ENTITY psi "ψ"> <!ENTITY omega "ω"> <!ENTITY thetasym "ϑ"> <!ENTITY upsih "ϒ"> <!ENTITY piv "ϖ"> <!ENTITY ensp " "> <!ENTITY emsp " "> <!ENTITY thinsp " "> <!ENTITY zwnj "‌"> <!ENTITY zwj "‍"> <!ENTITY lrm "‎"> <!ENTITY rlm "‏"> <!ENTITY ndash "–"> <!ENTITY mdash "—"> <!ENTITY lsquo "‘"> <!ENTITY rsquo "’"> <!ENTITY sbquo "‚"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY bdquo "„"> <!ENTITY dagger "†"> <!ENTITY Dagger "‡"> <!ENTITY bull "•"> <!ENTITY hellip "…"> <!ENTITY permil "‰"> <!ENTITY prime "′"> <!ENTITY Prime "″"> <!ENTITY lsaquo "‹"> <!ENTITY rsaquo "›"> <!ENTITY oline "‾"> <!ENTITY frasl "⁄"> <!ENTITY euro "€"> <!ENTITY image "ℑ"> <!ENTITY weierp "℘"> <!ENTITY real "ℜ"> <!ENTITY trade "™"> <!ENTITY alefsym "ℵ"> <!ENTITY larr "←"> <!ENTITY uarr "↑"> <!ENTITY rarr "→"> <!ENTITY darr "↓"> <!ENTITY harr "↔"> <!ENTITY crarr "↵"> <!ENTITY lArr "⇐"> <!ENTITY uArr "⇑"> <!ENTITY rArr "⇒"> <!ENTITY dArr "⇓"> <!ENTITY hArr "⇔"> <!ENTITY forall "∀"> <!ENTITY part "∂"> <!ENTITY exist "∃"> <!ENTITY empty "∅"> <!ENTITY nabla "∇"> <!ENTITY isin "∈"> <!ENTITY notin "∉"> <!ENTITY ni "∋"> <!ENTITY prod "∏"> <!ENTITY sum "∑"> <!ENTITY minus "−"> <!ENTITY lowast "∗"> <!ENTITY radic "√"> <!ENTITY prop "∝"> <!ENTITY infin "∞"> <!ENTITY ang "∠"> <!ENTITY and "∧"> <!ENTITY or "∨"> <!ENTITY cap "∩"> <!ENTITY cup "∪"> <!ENTITY int "∫"> <!ENTITY there4 "∴"> <!ENTITY sim "∼"> <!ENTITY cong "≅"> <!ENTITY asymp "≈"> <!ENTITY ne "≠"> <!ENTITY equiv "≡"> <!ENTITY le "≤"> <!ENTITY ge "≥"> <!ENTITY sub "⊂"> <!ENTITY sup "⊃"> <!ENTITY nsub "⊄"> <!ENTITY sube "⊆"> <!ENTITY supe "⊇"> <!ENTITY oplus "⊕"> <!ENTITY otimes "⊗"> <!ENTITY perp "⊥"> <!ENTITY sdot "⋅"> <!ENTITY lceil "⌈"> <!ENTITY rceil "⌉"> <!ENTITY lfloor "⌊"> <!ENTITY rfloor "⌋"> <!ENTITY lang "〈"> <!ENTITY rang "〉"> <!ENTITY loz "◊"> <!ENTITY spades "♠"> <!ENTITY clubs "♣"> <!ENTITY hearts "♥"> <!ENTITY diams "♦"> ]>'; } } class_alias('SimplePie\Parser', 'SimplePie_Parser'); �������������������������������������������������������������������������������������������������������������������������������������������������������������Author.php������������������������������������������������������������������������������������������0000644�����������������00000007441�15021155231�0006520 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; /** * Manages all author-related data * * Used by {@see Item::get_author()} and {@see SimplePie::get_authors()} * * This class can be overloaded with {@see SimplePie::set_author_class()} * * @package SimplePie * @subpackage API */ class Author { /** * Author's name * * @var string * @see get_name() */ public $name; /** * Author's link * * @var string * @see get_link() */ public $link; /** * Author's email address * * @var string * @see get_email() */ public $email; /** * Constructor, used to input the data * * @param string $name * @param string $link * @param string $email */ public function __construct($name = null, $link = null, $email = null) { $this->name = $name; $this->link = $link; $this->email = $email; } /** * String-ified version * * @return string */ public function __toString() { // There is no $this->data here return md5(serialize($this)); } /** * Author's name * * @return string|null */ public function get_name() { if ($this->name !== null) { return $this->name; } return null; } /** * Author's link * * @return string|null */ public function get_link() { if ($this->link !== null) { return $this->link; } return null; } /** * Author's email address * * @return string|null */ public function get_email() { if ($this->email !== null) { return $this->email; } return null; } } class_alias('SimplePie\Author', 'SimplePie_Author'); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML/Declaration/Parser.php��������������������������������������������������������������������������0000644�����������������00000022353�15021155231�0011376 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie\XML\Declaration; /** * Parses the XML Declaration * * @package SimplePie * @subpackage Parsing */ class Parser { /** * XML Version * * @access public * @var string */ public $version = '1.0'; /** * Encoding * * @access public * @var string */ public $encoding = 'UTF-8'; /** * Standalone * * @access public * @var bool */ public $standalone = false; private const STATE_BEFORE_VERSION_NAME = 'before_version_name'; private const STATE_VERSION_NAME = 'version_name'; private const STATE_VERSION_EQUALS = 'version_equals'; private const STATE_VERSION_VALUE = 'version_value'; private const STATE_ENCODING_NAME = 'encoding_name'; private const STATE_EMIT = 'emit'; private const STATE_ENCODING_EQUALS = 'encoding_equals'; private const STATE_STANDALONE_NAME = 'standalone_name'; private const STATE_ENCODING_VALUE = 'encoding_value'; private const STATE_STANDALONE_EQUALS = 'standalone_equals'; private const STATE_STANDALONE_VALUE = 'standalone_value'; private const STATE_ERROR = false; /** * Current state of the state machine * * @access private * @var self::STATE_* */ public $state = self::STATE_BEFORE_VERSION_NAME; /** * Input data * * @access private * @var string */ public $data = ''; /** * Input data length (to avoid calling strlen() everytime this is needed) * * @access private * @var int */ public $data_length = 0; /** * Current position of the pointer * * @var int * @access private */ public $position = 0; /** * Create an instance of the class with the input data * * @access public * @param string $data Input data */ public function __construct($data) { $this->data = $data; $this->data_length = strlen($this->data); } /** * Parse the input data * * @access public * @return bool true on success, false on failure */ public function parse() { while ($this->state && $this->state !== self::STATE_EMIT && $this->has_data()) { $state = $this->state; $this->$state(); } $this->data = ''; if ($this->state === self::STATE_EMIT) { return true; } $this->version = ''; $this->encoding = ''; $this->standalone = ''; return false; } /** * Check whether there is data beyond the pointer * * @access private * @return bool true if there is further data, false if not */ public function has_data() { return (bool) ($this->position < $this->data_length); } /** * Advance past any whitespace * * @return int Number of whitespace characters passed */ public function skip_whitespace() { $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); $this->position += $whitespace; return $whitespace; } /** * Read value */ public function get_value() { $quote = substr($this->data, $this->position, 1); if ($quote === '"' || $quote === "'") { $this->position++; $len = strcspn($this->data, $quote, $this->position); if ($this->has_data()) { $value = substr($this->data, $this->position, $len); $this->position += $len + 1; return $value; } } return false; } public function before_version_name() { if ($this->skip_whitespace()) { $this->state = self::STATE_VERSION_NAME; } else { $this->state = self::STATE_ERROR; } } public function version_name() { if (substr($this->data, $this->position, 7) === 'version') { $this->position += 7; $this->skip_whitespace(); $this->state = self::STATE_VERSION_EQUALS; } else { $this->state = self::STATE_ERROR; } } public function version_equals() { if (substr($this->data, $this->position, 1) === '=') { $this->position++; $this->skip_whitespace(); $this->state = self::STATE_VERSION_VALUE; } else { $this->state = self::STATE_ERROR; } } public function version_value() { if ($this->version = $this->get_value()) { $this->skip_whitespace(); if ($this->has_data()) { $this->state = self::STATE_ENCODING_NAME; } else { $this->state = self::STATE_EMIT; } } else { $this->state = self::STATE_ERROR; } } public function encoding_name() { if (substr($this->data, $this->position, 8) === 'encoding') { $this->position += 8; $this->skip_whitespace(); $this->state = self::STATE_ENCODING_EQUALS; } else { $this->state = self::STATE_STANDALONE_NAME; } } public function encoding_equals() { if (substr($this->data, $this->position, 1) === '=') { $this->position++; $this->skip_whitespace(); $this->state = self::STATE_ENCODING_VALUE; } else { $this->state = self::STATE_ERROR; } } public function encoding_value() { if ($this->encoding = $this->get_value()) { $this->skip_whitespace(); if ($this->has_data()) { $this->state = self::STATE_STANDALONE_NAME; } else { $this->state = self::STATE_EMIT; } } else { $this->state = self::STATE_ERROR; } } public function standalone_name() { if (substr($this->data, $this->position, 10) === 'standalone') { $this->position += 10; $this->skip_whitespace(); $this->state = self::STATE_STANDALONE_EQUALS; } else { $this->state = self::STATE_ERROR; } } public function standalone_equals() { if (substr($this->data, $this->position, 1) === '=') { $this->position++; $this->skip_whitespace(); $this->state = self::STATE_STANDALONE_VALUE; } else { $this->state = self::STATE_ERROR; } } public function standalone_value() { if ($standalone = $this->get_value()) { switch ($standalone) { case 'yes': $this->standalone = true; break; case 'no': $this->standalone = false; break; default: $this->state = self::STATE_ERROR; return; } $this->skip_whitespace(); if ($this->has_data()) { $this->state = self::STATE_ERROR; } else { $this->state = self::STATE_EMIT; } } else { $this->state = self::STATE_ERROR; } } } class_alias('SimplePie\XML\Declaration\Parser', 'SimplePie_XML_Declaration_Parser'); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Locator.php�����������������������������������������������������������������������������������������0000644�����������������00000036455�15021155231�0006670 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; /** * Used for feed auto-discovery * * * This class can be overloaded with {@see \SimplePie\SimplePie::set_locator_class()} * * @package SimplePie */ class Locator implements RegistryAware { public $useragent; public $timeout; public $file; public $local = []; public $elsewhere = []; public $cached_entities = []; public $http_base; public $base; public $base_location = 0; public $checked_feeds = 0; public $max_checked_feeds = 10; public $force_fsockopen = false; public $curl_options = []; public $dom; protected $registry; public function __construct(\SimplePie\File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10, $force_fsockopen = false, $curl_options = []) { $this->file = $file; $this->useragent = $useragent; $this->timeout = $timeout; $this->max_checked_feeds = $max_checked_feeds; $this->force_fsockopen = $force_fsockopen; $this->curl_options = $curl_options; if (class_exists('DOMDocument') && $this->file->body != '') { $this->dom = new \DOMDocument(); set_error_handler(['SimplePie\Misc', 'silence_errors']); try { $this->dom->loadHTML($this->file->body); } catch (\Throwable $ex) { $this->dom = null; } restore_error_handler(); } else { $this->dom = null; } } public function set_registry(\SimplePie\Registry $registry)/* : void */ { $this->registry = $registry; } public function find($type = \SimplePie\SimplePie::LOCATOR_ALL, &$working = null) { if ($this->is_feed($this->file)) { return $this->file; } if ($this->file->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE) { $sniffer = $this->registry->create(Content\Type\Sniffer::class, [$this->file]); if ($sniffer->get_type() !== 'text/html') { return null; } } if ($type & ~\SimplePie\SimplePie::LOCATOR_NONE) { $this->get_base(); } if ($type & \SimplePie\SimplePie::LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) { return $working[0]; } if ($type & (\SimplePie\SimplePie::LOCATOR_LOCAL_EXTENSION | \SimplePie\SimplePie::LOCATOR_LOCAL_BODY | \SimplePie\SimplePie::LOCATOR_REMOTE_EXTENSION | \SimplePie\SimplePie::LOCATOR_REMOTE_BODY) && $this->get_links()) { if ($type & \SimplePie\SimplePie::LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) { return $working[0]; } if ($type & \SimplePie\SimplePie::LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) { return $working[0]; } if ($type & \SimplePie\SimplePie::LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) { return $working[0]; } if ($type & \SimplePie\SimplePie::LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) { return $working[0]; } } return null; } public function is_feed($file, $check_html = false) { if ($file->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE) { $sniffer = $this->registry->create(Content\Type\Sniffer::class, [$file]); $sniffed = $sniffer->get_type(); $mime_types = ['application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml', 'application/x-rss+xml']; if ($check_html) { $mime_types[] = 'text/html'; } return in_array($sniffed, $mime_types); } elseif ($file->method & \SimplePie\SimplePie::FILE_SOURCE_LOCAL) { return true; } else { return false; } } public function get_base() { if ($this->dom === null) { throw new \SimplePie\Exception('DOMDocument not found, unable to use locator'); } $this->http_base = $this->file->url; $this->base = $this->http_base; $elements = $this->dom->getElementsByTagName('base'); foreach ($elements as $element) { if ($element->hasAttribute('href')) { $base = $this->registry->call(Misc::class, 'absolutize_url', [trim($element->getAttribute('href')), $this->http_base]); if ($base === false) { continue; } $this->base = $base; $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0; break; } } } public function autodiscovery() { $done = []; $feeds = []; $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds)); $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds)); $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds)); if (!empty($feeds)) { return array_values($feeds); } return null; } protected function search_elements_by_tag($name, &$done, $feeds) { if ($this->dom === null) { throw new \SimplePie\Exception('DOMDocument not found, unable to use locator'); } $links = $this->dom->getElementsByTagName($name); foreach ($links as $link) { if ($this->checked_feeds === $this->max_checked_feeds) { break; } if ($link->hasAttribute('href') && $link->hasAttribute('rel')) { $rel = array_unique($this->registry->call(Misc::class, 'space_separated_tokens', [strtolower($link->getAttribute('rel'))])); $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1; if ($this->base_location < $line) { $href = $this->registry->call(Misc::class, 'absolutize_url', [trim($link->getAttribute('href')), $this->base]); } else { $href = $this->registry->call(Misc::class, 'absolutize_url', [trim($link->getAttribute('href')), $this->http_base]); } if ($href === false) { continue; } if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call(Misc::class, 'parse_mime', [$link->getAttribute('type')])), ['text/html', 'application/rss+xml', 'application/atom+xml'])) && !isset($feeds[$href])) { $this->checked_feeds++; $headers = [ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', ]; $feed = $this->registry->create(File::class, [$href, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options]); if ($feed->success && ($feed->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed, true)) { $feeds[$href] = $feed; } } $done[] = $href; } } return $feeds; } public function get_links() { if ($this->dom === null) { throw new \SimplePie\Exception('DOMDocument not found, unable to use locator'); } $links = $this->dom->getElementsByTagName('a'); foreach ($links as $link) { if ($link->hasAttribute('href')) { $href = trim($link->getAttribute('href')); $parsed = $this->registry->call(Misc::class, 'parse_url', [$href]); if ($parsed['scheme'] === '' || preg_match('/^(https?|feed)?$/i', $parsed['scheme'])) { if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo()) { $href = $this->registry->call(Misc::class, 'absolutize_url', [trim($link->getAttribute('href')), $this->base]); } else { $href = $this->registry->call(Misc::class, 'absolutize_url', [trim($link->getAttribute('href')), $this->http_base]); } if ($href === false) { continue; } $current = $this->registry->call(Misc::class, 'parse_url', [$this->file->url]); if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) { $this->local[] = $href; } else { $this->elsewhere[] = $href; } } } } $this->local = array_unique($this->local); $this->elsewhere = array_unique($this->elsewhere); if (!empty($this->local) || !empty($this->elsewhere)) { return true; } return null; } public function get_rel_link($rel) { if ($this->dom === null) { throw new \SimplePie\Exception('DOMDocument not found, unable to use '. 'locator'); } if (!class_exists('DOMXpath')) { throw new \SimplePie\Exception('DOMXpath not found, unable to use '. 'get_rel_link'); } $xpath = new \DOMXpath($this->dom); $query = '//a[@rel and @href] | //link[@rel and @href]'; foreach ($xpath->query($query) as $link) { $href = trim($link->getAttribute('href')); $parsed = $this->registry->call(Misc::class, 'parse_url', [$href]); if ($parsed['scheme'] === '' || preg_match('/^https?$/i', $parsed['scheme'])) { if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo()) { $href = $this->registry->call( Misc::class, 'absolutize_url', [trim($link->getAttribute('href')), $this->base] ); } else { $href = $this->registry->call( Misc::class, 'absolutize_url', [trim($link->getAttribute('href')), $this->http_base] ); } if ($href === false) { return null; } $rel_values = explode(' ', strtolower($link->getAttribute('rel'))); if (in_array($rel, $rel_values)) { return $href; } } } return null; } public function extension(&$array) { foreach ($array as $key => $value) { if ($this->checked_feeds === $this->max_checked_feeds) { break; } if (in_array(strtolower(strrchr($value, '.')), ['.rss', '.rdf', '.atom', '.xml'])) { $this->checked_feeds++; $headers = [ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', ]; $feed = $this->registry->create(File::class, [$value, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options]); if ($feed->success && ($feed->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) { return [$feed]; } else { unset($array[$key]); } } } return null; } public function body(&$array) { foreach ($array as $key => $value) { if ($this->checked_feeds === $this->max_checked_feeds) { break; } if (preg_match('/(feed|rss|rdf|atom|xml)/i', $value)) { $this->checked_feeds++; $headers = [ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', ]; $feed = $this->registry->create(File::class, [$value, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen, $this->curl_options]); if ($feed->success && ($feed->method & \SimplePie\SimplePie::FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) { return [$feed]; } else { unset($array[$key]); } } } return null; } } class_alias('SimplePie\Locator', 'SimplePie_Locator', false); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Misc.php��������������������������������������������������������������������������������������������0000644�����������������00000206032�15021155231�0006146 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; use SimplePie\XML\Declaration\Parser; /** * Miscellaneous utilities * * @package SimplePie */ class Misc { private static $SIMPLEPIE_BUILD = null; public static function time_hms($seconds) { $time = ''; $hours = floor($seconds / 3600); $remainder = $seconds % 3600; if ($hours > 0) { $time .= $hours.':'; } $minutes = floor($remainder / 60); $seconds = $remainder % 60; if ($minutes < 10 && $hours > 0) { $minutes = '0' . $minutes; } if ($seconds < 10) { $seconds = '0' . $seconds; } $time .= $minutes.':'; $time .= $seconds; return $time; } public static function absolutize_url($relative, $base) { $iri = \SimplePie\IRI::absolutize(new \SimplePie\IRI($base), $relative); if ($iri === false) { return false; } return $iri->get_uri(); } /** * Get a HTML/XML element from a HTML string * * @deprecated since SimplePie 1.3, use DOMDocument instead (parsing HTML with regex is bad!) * @param string $realname Element name (including namespace prefix if applicable) * @param string $string HTML document * @return array */ public static function get_element($realname, $string) { // trigger_error(sprintf('Using method "' . __METHOD__ . '" is deprecated since SimplePie 1.3, use "DOMDocument" instead.'), \E_USER_DEPRECATED); $return = []; $name = preg_quote($realname, '/'); if (preg_match_all("/<($name)" . \SimplePie\SimplePie::PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) { $return[$i]['tag'] = $realname; $return[$i]['full'] = $matches[$i][0][0]; $return[$i]['offset'] = $matches[$i][0][1]; if (strlen($matches[$i][3][0]) <= 2) { $return[$i]['self_closing'] = true; } else { $return[$i]['self_closing'] = false; $return[$i]['content'] = $matches[$i][4][0]; } $return[$i]['attribs'] = []; if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER)) { for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) { if (count($attribs[$j]) === 2) { $attribs[$j][2] = $attribs[$j][1]; } $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = Misc::entities_decode(end($attribs[$j])); } } } } return $return; } public static function element_implode($element) { $full = "<$element[tag]"; foreach ($element['attribs'] as $key => $value) { $key = strtolower($key); $full .= " $key=\"" . htmlspecialchars($value['data'], ENT_COMPAT, 'UTF-8') . '"'; } if ($element['self_closing']) { $full .= ' />'; } else { $full .= ">$element[content]</$element[tag]>"; } return $full; } public static function error($message, $level, $file, $line) { if ((error_reporting() & $level) > 0) { switch ($level) { case E_USER_ERROR: $note = 'PHP Error'; break; case E_USER_WARNING: $note = 'PHP Warning'; break; case E_USER_NOTICE: $note = 'PHP Notice'; break; default: $note = 'Unknown Error'; break; } $log_error = true; if (!function_exists('error_log')) { $log_error = false; } $log_file = @ini_get('error_log'); if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file)) { $log_error = false; } if ($log_error) { @error_log("$note: $message in $file on line $line", 0); } } return $message; } public static function fix_protocol($url, $http = 1) { $url = Misc::normalize_url($url); $parsed = Misc::parse_url($url); if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') { return Misc::fix_protocol(Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); } if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) { return Misc::fix_protocol(Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); } if ($http === 2 && $parsed['scheme'] !== '') { return "feed:$url"; } elseif ($http === 3 && strtolower($parsed['scheme']) === 'http') { return substr_replace($url, 'podcast', 0, 4); } elseif ($http === 4 && strtolower($parsed['scheme']) === 'http') { return substr_replace($url, 'itpc', 0, 4); } return $url; } /** * @deprecated since SimplePie 1.8.0, use PHP native array_replace_recursive() instead. */ public static function array_merge_recursive($array1, $array2) { foreach ($array2 as $key => $value) { if (is_array($value)) { $array1[$key] = Misc::array_merge_recursive($array1[$key], $value); } else { $array1[$key] = $value; } } return $array1; } public static function parse_url($url) { $iri = new \SimplePie\IRI($url); return [ 'scheme' => (string) $iri->scheme, 'authority' => (string) $iri->authority, 'path' => (string) $iri->path, 'query' => (string) $iri->query, 'fragment' => (string) $iri->fragment ]; } public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') { $iri = new \SimplePie\IRI(''); $iri->scheme = $scheme; $iri->authority = $authority; $iri->path = $path; $iri->query = $query; $iri->fragment = $fragment; return $iri->get_uri(); } public static function normalize_url($url) { $iri = new \SimplePie\IRI($url); return $iri->get_uri(); } public static function percent_encoding_normalization($match) { $integer = hexdec($match[1]); if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E) { return chr($integer); } return strtoupper($match[0]); } /** * Converts a Windows-1252 encoded string to a UTF-8 encoded string * * @static * @param string $string Windows-1252 encoded string * @return string UTF-8 encoded string */ public static function windows_1252_to_utf8($string) { static $convert_table = ["\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF"]; return strtr($string, $convert_table); } /** * Change a string from one encoding to another * * @param string $data Raw data in $input encoding * @param string $input Encoding of $data * @param string $output Encoding you want * @return string|boolean False if we can't convert it */ public static function change_encoding($data, $input, $output) { $input = Misc::encoding($input); $output = Misc::encoding($output); // We fail to fail on non US-ASCII bytes if ($input === 'US-ASCII') { static $non_ascii_octects = ''; if (!$non_ascii_octects) { for ($i = 0x80; $i <= 0xFF; $i++) { $non_ascii_octects .= chr($i); } } $data = substr($data, 0, strcspn($data, $non_ascii_octects)); } // This is first, as behaviour of this is completely predictable if ($input === 'windows-1252' && $output === 'UTF-8') { return Misc::windows_1252_to_utf8($data); } // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported). elseif (function_exists('mb_convert_encoding') && ($return = Misc::change_encoding_mbstring($data, $input, $output))) { return $return; } // This is third, as behaviour of this varies with OS userland and PHP version elseif (function_exists('iconv') && ($return = Misc::change_encoding_iconv($data, $input, $output))) { return $return; } // This is last, as behaviour of this varies with OS userland and PHP version elseif (class_exists('\UConverter') && ($return = Misc::change_encoding_uconverter($data, $input, $output))) { return $return; } // If we can't do anything, just fail return false; } protected static function change_encoding_mbstring($data, $input, $output) { if ($input === 'windows-949') { $input = 'EUC-KR'; } if ($output === 'windows-949') { $output = 'EUC-KR'; } if ($input === 'Windows-31J') { $input = 'SJIS'; } if ($output === 'Windows-31J') { $output = 'SJIS'; } // Check that the encoding is supported if (!in_array($input, mb_list_encodings())) { return false; } if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80") { return false; } // Let's do some conversion if ($return = @mb_convert_encoding($data, $output, $input)) { return $return; } return false; } protected static function change_encoding_iconv($data, $input, $output) { return @iconv($input, $output, $data); } /** * @param string $data * @param string $input * @param string $output * @return string|false */ protected static function change_encoding_uconverter($data, $input, $output) { return @\UConverter::transcode($data, $output, $input); } /** * Normalize an encoding name * * This is automatically generated by create.php * * To generate it, run `php create.php` on the command line, and copy the * output to replace this function. * * @param string $charset Character set to standardise * @return string Standardised name */ public static function encoding($charset) { // Normalization from UTS #22 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset))) { case 'adobestandardencoding': case 'csadobestandardencoding': return 'Adobe-Standard-Encoding'; case 'adobesymbolencoding': case 'cshppsmath': return 'Adobe-Symbol-Encoding'; case 'ami1251': case 'amiga1251': return 'Amiga-1251'; case 'ansix31101983': case 'csat5001983': case 'csiso99naplps': case 'isoir99': case 'naplps': return 'ANSI_X3.110-1983'; case 'arabic7': case 'asmo449': case 'csiso89asmo449': case 'iso9036': case 'isoir89': return 'ASMO_449'; case 'big5': case 'csbig5': return 'Big5'; case 'big5hkscs': return 'Big5-HKSCS'; case 'bocu1': case 'csbocu1': return 'BOCU-1'; case 'brf': case 'csbrf': return 'BRF'; case 'bs4730': case 'csiso4unitedkingdom': case 'gb': case 'iso646gb': case 'isoir4': case 'uk': return 'BS_4730'; case 'bsviewdata': case 'csiso47bsviewdata': case 'isoir47': return 'BS_viewdata'; case 'cesu8': case 'cscesu8': return 'CESU-8'; case 'ca': case 'csa71': case 'csaz243419851': case 'csiso121canadian1': case 'iso646ca': case 'isoir121': return 'CSA_Z243.4-1985-1'; case 'csa72': case 'csaz243419852': case 'csiso122canadian2': case 'iso646ca2': case 'isoir122': return 'CSA_Z243.4-1985-2'; case 'csaz24341985gr': case 'csiso123csaz24341985gr': case 'isoir123': return 'CSA_Z243.4-1985-gr'; case 'csiso139csn369103': case 'csn369103': case 'isoir139': return 'CSN_369103'; case 'csdecmcs': case 'dec': case 'decmcs': return 'DEC-MCS'; case 'csiso21german': case 'de': case 'din66003': case 'iso646de': case 'isoir21': return 'DIN_66003'; case 'csdkus': case 'dkus': return 'dk-us'; case 'csiso646danish': case 'dk': case 'ds2089': case 'iso646dk': return 'DS_2089'; case 'csibmebcdicatde': case 'ebcdicatde': return 'EBCDIC-AT-DE'; case 'csebcdicatdea': case 'ebcdicatdea': return 'EBCDIC-AT-DE-A'; case 'csebcdiccafr': case 'ebcdiccafr': return 'EBCDIC-CA-FR'; case 'csebcdicdkno': case 'ebcdicdkno': return 'EBCDIC-DK-NO'; case 'csebcdicdknoa': case 'ebcdicdknoa': return 'EBCDIC-DK-NO-A'; case 'csebcdices': case 'ebcdices': return 'EBCDIC-ES'; case 'csebcdicesa': case 'ebcdicesa': return 'EBCDIC-ES-A'; case 'csebcdicess': case 'ebcdicess': return 'EBCDIC-ES-S'; case 'csebcdicfise': case 'ebcdicfise': return 'EBCDIC-FI-SE'; case 'csebcdicfisea': case 'ebcdicfisea': return 'EBCDIC-FI-SE-A'; case 'csebcdicfr': case 'ebcdicfr': return 'EBCDIC-FR'; case 'csebcdicit': case 'ebcdicit': return 'EBCDIC-IT'; case 'csebcdicpt': case 'ebcdicpt': return 'EBCDIC-PT'; case 'csebcdicuk': case 'ebcdicuk': return 'EBCDIC-UK'; case 'csebcdicus': case 'ebcdicus': return 'EBCDIC-US'; case 'csiso111ecmacyrillic': case 'ecmacyrillic': case 'isoir111': case 'koi8e': return 'ECMA-cyrillic'; case 'csiso17spanish': case 'es': case 'iso646es': case 'isoir17': return 'ES'; case 'csiso85spanish2': case 'es2': case 'iso646es2': case 'isoir85': return 'ES2'; case 'cseucpkdfmtjapanese': case 'eucjp': case 'extendedunixcodepackedformatforjapanese': return 'EUC-JP'; case 'cseucfixwidjapanese': case 'extendedunixcodefixedwidthforjapanese': return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; case 'gb18030': return 'GB18030'; case 'chinese': case 'cp936': case 'csgb2312': case 'csiso58gb231280': case 'gb2312': case 'gb231280': case 'gbk': case 'isoir58': case 'ms936': case 'windows936': return 'GBK'; case 'cn': case 'csiso57gb1988': case 'gb198880': case 'iso646cn': case 'isoir57': return 'GB_1988-80'; case 'csiso153gost1976874': case 'gost1976874': case 'isoir153': case 'stsev35888': return 'GOST_19768-74'; case 'csiso150': case 'csiso150greekccitt': case 'greekccitt': case 'isoir150': return 'greek-ccitt'; case 'csiso88greek7': case 'greek7': case 'isoir88': return 'greek7'; case 'csiso18greek7old': case 'greek7old': case 'isoir18': return 'greek7-old'; case 'cshpdesktop': case 'hpdesktop': return 'HP-DeskTop'; case 'cshplegal': case 'hplegal': return 'HP-Legal'; case 'cshpmath8': case 'hpmath8': return 'HP-Math8'; case 'cshppifont': case 'hppifont': return 'HP-Pi-font'; case 'cshproman8': case 'hproman8': case 'r8': case 'roman8': return 'hp-roman8'; case 'hzgb2312': return 'HZ-GB-2312'; case 'csibmsymbols': case 'ibmsymbols': return 'IBM-Symbols'; case 'csibmthai': case 'ibmthai': return 'IBM-Thai'; case 'cp37': case 'csibm37': case 'ebcdiccpca': case 'ebcdiccpnl': case 'ebcdiccpus': case 'ebcdiccpwt': case 'ibm37': return 'IBM037'; case 'cp38': case 'csibm38': case 'ebcdicint': case 'ibm38': return 'IBM038'; case 'cp273': case 'csibm273': case 'ibm273': return 'IBM273'; case 'cp274': case 'csibm274': case 'ebcdicbe': case 'ibm274': return 'IBM274'; case 'cp275': case 'csibm275': case 'ebcdicbr': case 'ibm275': return 'IBM275'; case 'csibm277': case 'ebcdiccpdk': case 'ebcdiccpno': case 'ibm277': return 'IBM277'; case 'cp278': case 'csibm278': case 'ebcdiccpfi': case 'ebcdiccpse': case 'ibm278': return 'IBM278'; case 'cp280': case 'csibm280': case 'ebcdiccpit': case 'ibm280': return 'IBM280'; case 'cp281': case 'csibm281': case 'ebcdicjpe': case 'ibm281': return 'IBM281'; case 'cp284': case 'csibm284': case 'ebcdiccpes': case 'ibm284': return 'IBM284'; case 'cp285': case 'csibm285': case 'ebcdiccpgb': case 'ibm285': return 'IBM285'; case 'cp290': case 'csibm290': case 'ebcdicjpkana': case 'ibm290': return 'IBM290'; case 'cp297': case 'csibm297': case 'ebcdiccpfr': case 'ibm297': return 'IBM297'; case 'cp420': case 'csibm420': case 'ebcdiccpar1': case 'ibm420': return 'IBM420'; case 'cp423': case 'csibm423': case 'ebcdiccpgr': case 'ibm423': return 'IBM423'; case 'cp424': case 'csibm424': case 'ebcdiccphe': case 'ibm424': return 'IBM424'; case '437': case 'cp437': case 'cspc8codepage437': case 'ibm437': return 'IBM437'; case 'cp500': case 'csibm500': case 'ebcdiccpbe': case 'ebcdiccpch': case 'ibm500': return 'IBM500'; case 'cp775': case 'cspc775baltic': case 'ibm775': return 'IBM775'; case '850': case 'cp850': case 'cspc850multilingual': case 'ibm850': return 'IBM850'; case '851': case 'cp851': case 'csibm851': case 'ibm851': return 'IBM851'; case '852': case 'cp852': case 'cspcp852': case 'ibm852': return 'IBM852'; case '855': case 'cp855': case 'csibm855': case 'ibm855': return 'IBM855'; case '857': case 'cp857': case 'csibm857': case 'ibm857': return 'IBM857'; case 'ccsid858': case 'cp858': case 'ibm858': case 'pcmultilingual850euro': return 'IBM00858'; case '860': case 'cp860': case 'csibm860': case 'ibm860': return 'IBM860'; case '861': case 'cp861': case 'cpis': case 'csibm861': case 'ibm861': return 'IBM861'; case '862': case 'cp862': case 'cspc862latinhebrew': case 'ibm862': return 'IBM862'; case '863': case 'cp863': case 'csibm863': case 'ibm863': return 'IBM863'; case 'cp864': case 'csibm864': case 'ibm864': return 'IBM864'; case '865': case 'cp865': case 'csibm865': case 'ibm865': return 'IBM865'; case '866': case 'cp866': case 'csibm866': case 'ibm866': return 'IBM866'; case 'cp868': case 'cpar': case 'csibm868': case 'ibm868': return 'IBM868'; case '869': case 'cp869': case 'cpgr': case 'csibm869': case 'ibm869': return 'IBM869'; case 'cp870': case 'csibm870': case 'ebcdiccproece': case 'ebcdiccpyu': case 'ibm870': return 'IBM870'; case 'cp871': case 'csibm871': case 'ebcdiccpis': case 'ibm871': return 'IBM871'; case 'cp880': case 'csibm880': case 'ebcdiccyrillic': case 'ibm880': return 'IBM880'; case 'cp891': case 'csibm891': case 'ibm891': return 'IBM891'; case 'cp903': case 'csibm903': case 'ibm903': return 'IBM903'; case '904': case 'cp904': case 'csibbm904': case 'ibm904': return 'IBM904'; case 'cp905': case 'csibm905': case 'ebcdiccptr': case 'ibm905': return 'IBM905'; case 'cp918': case 'csibm918': case 'ebcdiccpar2': case 'ibm918': return 'IBM918'; case 'ccsid924': case 'cp924': case 'ebcdiclatin9euro': case 'ibm924': return 'IBM00924'; case 'cp1026': case 'csibm1026': case 'ibm1026': return 'IBM1026'; case 'ibm1047': return 'IBM1047'; case 'ccsid1140': case 'cp1140': case 'ebcdicus37euro': case 'ibm1140': return 'IBM01140'; case 'ccsid1141': case 'cp1141': case 'ebcdicde273euro': case 'ibm1141': return 'IBM01141'; case 'ccsid1142': case 'cp1142': case 'ebcdicdk277euro': case 'ebcdicno277euro': case 'ibm1142': return 'IBM01142'; case 'ccsid1143': case 'cp1143': case 'ebcdicfi278euro': case 'ebcdicse278euro': case 'ibm1143': return 'IBM01143'; case 'ccsid1144': case 'cp1144': case 'ebcdicit280euro': case 'ibm1144': return 'IBM01144'; case 'ccsid1145': case 'cp1145': case 'ebcdices284euro': case 'ibm1145': return 'IBM01145'; case 'ccsid1146': case 'cp1146': case 'ebcdicgb285euro': case 'ibm1146': return 'IBM01146'; case 'ccsid1147': case 'cp1147': case 'ebcdicfr297euro': case 'ibm1147': return 'IBM01147'; case 'ccsid1148': case 'cp1148': case 'ebcdicinternational500euro': case 'ibm1148': return 'IBM01148'; case 'ccsid1149': case 'cp1149': case 'ebcdicis871euro': case 'ibm1149': return 'IBM01149'; case 'csiso143iecp271': case 'iecp271': case 'isoir143': return 'IEC_P27-1'; case 'csiso49inis': case 'inis': case 'isoir49': return 'INIS'; case 'csiso50inis8': case 'inis8': case 'isoir50': return 'INIS-8'; case 'csiso51iniscyrillic': case 'iniscyrillic': case 'isoir51': return 'INIS-cyrillic'; case 'csinvariant': case 'invariant': return 'INVARIANT'; case 'iso2022cn': return 'ISO-2022-CN'; case 'iso2022cnext': return 'ISO-2022-CN-EXT'; case 'csiso2022jp': case 'iso2022jp': return 'ISO-2022-JP'; case 'csiso2022jp2': case 'iso2022jp2': return 'ISO-2022-JP-2'; case 'csiso2022kr': case 'iso2022kr': return 'ISO-2022-KR'; case 'cswindows30latin1': case 'iso88591windows30latin1': return 'ISO-8859-1-Windows-3.0-Latin-1'; case 'cswindows31latin1': case 'iso88591windows31latin1': return 'ISO-8859-1-Windows-3.1-Latin-1'; case 'csisolatin2': case 'iso88592': case 'iso885921987': case 'isoir101': case 'l2': case 'latin2': return 'ISO-8859-2'; case 'cswindows31latin2': case 'iso88592windowslatin2': return 'ISO-8859-2-Windows-Latin-2'; case 'csisolatin3': case 'iso88593': case 'iso885931988': case 'isoir109': case 'l3': case 'latin3': return 'ISO-8859-3'; case 'csisolatin4': case 'iso88594': case 'iso885941988': case 'isoir110': case 'l4': case 'latin4': return 'ISO-8859-4'; case 'csisolatincyrillic': case 'cyrillic': case 'iso88595': case 'iso885951988': case 'isoir144': return 'ISO-8859-5'; case 'arabic': case 'asmo708': case 'csisolatinarabic': case 'ecma114': case 'iso88596': case 'iso885961987': case 'isoir127': return 'ISO-8859-6'; case 'csiso88596e': case 'iso88596e': return 'ISO-8859-6-E'; case 'csiso88596i': case 'iso88596i': return 'ISO-8859-6-I'; case 'csisolatingreek': case 'ecma118': case 'elot928': case 'greek': case 'greek8': case 'iso88597': case 'iso885971987': case 'isoir126': return 'ISO-8859-7'; case 'csisolatinhebrew': case 'hebrew': case 'iso88598': case 'iso885981988': case 'isoir138': return 'ISO-8859-8'; case 'csiso88598e': case 'iso88598e': return 'ISO-8859-8-E'; case 'csiso88598i': case 'iso88598i': return 'ISO-8859-8-I'; case 'cswindows31latin5': case 'iso88599windowslatin5': return 'ISO-8859-9-Windows-Latin-5'; case 'csisolatin6': case 'iso885910': case 'iso8859101992': case 'isoir157': case 'l6': case 'latin6': return 'ISO-8859-10'; case 'iso885913': return 'ISO-8859-13'; case 'iso885914': case 'iso8859141998': case 'isoceltic': case 'isoir199': case 'l8': case 'latin8': return 'ISO-8859-14'; case 'iso885915': case 'latin9': return 'ISO-8859-15'; case 'iso885916': case 'iso8859162001': case 'isoir226': case 'l10': case 'latin10': return 'ISO-8859-16'; case 'iso10646j1': return 'ISO-10646-J-1'; case 'csunicode': case 'iso10646ucs2': return 'ISO-10646-UCS-2'; case 'csucs4': case 'iso10646ucs4': return 'ISO-10646-UCS-4'; case 'csunicodeascii': case 'iso10646ucsbasic': return 'ISO-10646-UCS-Basic'; case 'csunicodelatin1': case 'iso10646': case 'iso10646unicodelatin1': return 'ISO-10646-Unicode-Latin1'; case 'csiso10646utf1': case 'iso10646utf1': return 'ISO-10646-UTF-1'; case 'csiso115481': case 'iso115481': case 'isotr115481': return 'ISO-11548-1'; case 'csiso90': case 'isoir90': return 'iso-ir-90'; case 'csunicodeibm1261': case 'isounicodeibm1261': return 'ISO-Unicode-IBM-1261'; case 'csunicodeibm1264': case 'isounicodeibm1264': return 'ISO-Unicode-IBM-1264'; case 'csunicodeibm1265': case 'isounicodeibm1265': return 'ISO-Unicode-IBM-1265'; case 'csunicodeibm1268': case 'isounicodeibm1268': return 'ISO-Unicode-IBM-1268'; case 'csunicodeibm1276': case 'isounicodeibm1276': return 'ISO-Unicode-IBM-1276'; case 'csiso646basic1983': case 'iso646basic1983': case 'ref': return 'ISO_646.basic:1983'; case 'csiso2intlrefversion': case 'irv': case 'iso646irv1983': case 'isoir2': return 'ISO_646.irv:1983'; case 'csiso2033': case 'e13b': case 'iso20331983': case 'isoir98': return 'ISO_2033-1983'; case 'csiso5427cyrillic': case 'iso5427': case 'isoir37': return 'ISO_5427'; case 'iso5427cyrillic1981': case 'iso54271981': case 'isoir54': return 'ISO_5427:1981'; case 'csiso5428greek': case 'iso54281980': case 'isoir55': return 'ISO_5428:1980'; case 'csiso6937add': case 'iso6937225': case 'isoir152': return 'ISO_6937-2-25'; case 'csisotextcomm': case 'iso69372add': case 'isoir142': return 'ISO_6937-2-add'; case 'csiso8859supp': case 'iso8859supp': case 'isoir154': case 'latin125': return 'ISO_8859-supp'; case 'csiso10367box': case 'iso10367box': case 'isoir155': return 'ISO_10367-box'; case 'csiso15italian': case 'iso646it': case 'isoir15': case 'it': return 'IT'; case 'csiso13jisc6220jp': case 'isoir13': case 'jisc62201969': case 'jisc62201969jp': case 'katakana': case 'x2017': return 'JIS_C6220-1969-jp'; case 'csiso14jisc6220ro': case 'iso646jp': case 'isoir14': case 'jisc62201969ro': case 'jp': return 'JIS_C6220-1969-ro'; case 'csiso42jisc62261978': case 'isoir42': case 'jisc62261978': return 'JIS_C6226-1978'; case 'csiso87jisx208': case 'isoir87': case 'jisc62261983': case 'jisx2081983': case 'x208': return 'JIS_C6226-1983'; case 'csiso91jisc62291984a': case 'isoir91': case 'jisc62291984a': case 'jpocra': return 'JIS_C6229-1984-a'; case 'csiso92jisc62991984b': case 'iso646jpocrb': case 'isoir92': case 'jisc62291984b': case 'jpocrb': return 'JIS_C6229-1984-b'; case 'csiso93jis62291984badd': case 'isoir93': case 'jisc62291984badd': case 'jpocrbadd': return 'JIS_C6229-1984-b-add'; case 'csiso94jis62291984hand': case 'isoir94': case 'jisc62291984hand': case 'jpocrhand': return 'JIS_C6229-1984-hand'; case 'csiso95jis62291984handadd': case 'isoir95': case 'jisc62291984handadd': case 'jpocrhandadd': return 'JIS_C6229-1984-hand-add'; case 'csiso96jisc62291984kana': case 'isoir96': case 'jisc62291984kana': return 'JIS_C6229-1984-kana'; case 'csjisencoding': case 'jisencoding': return 'JIS_Encoding'; case 'cshalfwidthkatakana': case 'jisx201': case 'x201': return 'JIS_X0201'; case 'csiso159jisx2121990': case 'isoir159': case 'jisx2121990': case 'x212': return 'JIS_X0212-1990'; case 'csiso141jusib1002': case 'iso646yu': case 'isoir141': case 'js': case 'jusib1002': case 'yu': return 'JUS_I.B1.002'; case 'csiso147macedonian': case 'isoir147': case 'jusib1003mac': case 'macedonian': return 'JUS_I.B1.003-mac'; case 'csiso146serbian': case 'isoir146': case 'jusib1003serb': case 'serbian': return 'JUS_I.B1.003-serb'; case 'koi7switched': return 'KOI7-switched'; case 'cskoi8r': case 'koi8r': return 'KOI8-R'; case 'koi8u': return 'KOI8-U'; case 'csksc5636': case 'iso646kr': case 'ksc5636': return 'KSC5636'; case 'cskz1048': case 'kz1048': case 'rk1048': case 'strk10482002': return 'KZ-1048'; case 'csiso19latingreek': case 'isoir19': case 'latingreek': return 'latin-greek'; case 'csiso27latingreek1': case 'isoir27': case 'latingreek1': return 'Latin-greek-1'; case 'csiso158lap': case 'isoir158': case 'lap': case 'latinlap': return 'latin-lap'; case 'csmacintosh': case 'mac': case 'macintosh': return 'macintosh'; case 'csmicrosoftpublishing': case 'microsoftpublishing': return 'Microsoft-Publishing'; case 'csmnem': case 'mnem': return 'MNEM'; case 'csmnemonic': case 'mnemonic': return 'MNEMONIC'; case 'csiso86hungarian': case 'hu': case 'iso646hu': case 'isoir86': case 'msz77953': return 'MSZ_7795.3'; case 'csnatsdano': case 'isoir91': case 'natsdano': return 'NATS-DANO'; case 'csnatsdanoadd': case 'isoir92': case 'natsdanoadd': return 'NATS-DANO-ADD'; case 'csnatssefi': case 'isoir81': case 'natssefi': return 'NATS-SEFI'; case 'csnatssefiadd': case 'isoir82': case 'natssefiadd': return 'NATS-SEFI-ADD'; case 'csiso151cuba': case 'cuba': case 'iso646cu': case 'isoir151': case 'ncnc1081': return 'NC_NC00-10:81'; case 'csiso69french': case 'fr': case 'iso646fr': case 'isoir69': case 'nfz62010': return 'NF_Z_62-010'; case 'csiso25french': case 'iso646fr1': case 'isoir25': case 'nfz620101973': return 'NF_Z_62-010_(1973)'; case 'csiso60danishnorwegian': case 'csiso60norwegian1': case 'iso646no': case 'isoir60': case 'no': case 'ns45511': return 'NS_4551-1'; case 'csiso61norwegian2': case 'iso646no2': case 'isoir61': case 'no2': case 'ns45512': return 'NS_4551-2'; case 'osdebcdicdf3irv': return 'OSD_EBCDIC_DF03_IRV'; case 'osdebcdicdf41': return 'OSD_EBCDIC_DF04_1'; case 'osdebcdicdf415': return 'OSD_EBCDIC_DF04_15'; case 'cspc8danishnorwegian': case 'pc8danishnorwegian': return 'PC8-Danish-Norwegian'; case 'cspc8turkish': case 'pc8turkish': return 'PC8-Turkish'; case 'csiso16portuguese': case 'iso646pt': case 'isoir16': case 'pt': return 'PT'; case 'csiso84portuguese2': case 'iso646pt2': case 'isoir84': case 'pt2': return 'PT2'; case 'cp154': case 'csptcp154': case 'cyrillicasian': case 'pt154': case 'ptcp154': return 'PTCP154'; case 'scsu': return 'SCSU'; case 'csiso10swedish': case 'fi': case 'iso646fi': case 'iso646se': case 'isoir10': case 'se': case 'sen850200b': return 'SEN_850200_B'; case 'csiso11swedishfornames': case 'iso646se2': case 'isoir11': case 'se2': case 'sen850200c': return 'SEN_850200_C'; case 'csiso102t617bit': case 'isoir102': case 't617bit': return 'T.61-7bit'; case 'csiso103t618bit': case 'isoir103': case 't61': case 't618bit': return 'T.61-8bit'; case 'csiso128t101g2': case 'isoir128': case 't101g2': return 'T.101-G2'; case 'cstscii': case 'tscii': return 'TSCII'; case 'csunicode11': case 'unicode11': return 'UNICODE-1-1'; case 'csunicode11utf7': case 'unicode11utf7': return 'UNICODE-1-1-UTF-7'; case 'csunknown8bit': case 'unknown8bit': return 'UNKNOWN-8BIT'; case 'ansix341968': case 'ansix341986': case 'ascii': case 'cp367': case 'csascii': case 'ibm367': case 'iso646irv1991': case 'iso646us': case 'isoir6': case 'us': case 'usascii': return 'US-ASCII'; case 'csusdk': case 'usdk': return 'us-dk'; case 'utf7': return 'UTF-7'; case 'utf8': return 'UTF-8'; case 'utf16': return 'UTF-16'; case 'utf16be': return 'UTF-16BE'; case 'utf16le': return 'UTF-16LE'; case 'utf32': return 'UTF-32'; case 'utf32be': return 'UTF-32BE'; case 'utf32le': return 'UTF-32LE'; case 'csventurainternational': case 'venturainternational': return 'Ventura-International'; case 'csventuramath': case 'venturamath': return 'Ventura-Math'; case 'csventuraus': case 'venturaus': return 'Ventura-US'; case 'csiso70videotexsupp1': case 'isoir70': case 'videotexsuppl': return 'videotex-suppl'; case 'csviqr': case 'viqr': return 'VIQR'; case 'csviscii': case 'viscii': return 'VISCII'; case 'csshiftjis': case 'cswindows31j': case 'mskanji': case 'shiftjis': case 'windows31j': return 'Windows-31J'; case 'iso885911': case 'tis620': return 'windows-874'; case 'cseuckr': case 'csksc56011987': case 'euckr': case 'isoir149': case 'korean': case 'ksc5601': case 'ksc56011987': case 'ksc56011989': case 'windows949': return 'windows-949'; case 'windows1250': return 'windows-1250'; case 'windows1251': return 'windows-1251'; case 'cp819': case 'csisolatin1': case 'ibm819': case 'iso88591': case 'iso885911987': case 'isoir100': case 'l1': case 'latin1': case 'windows1252': return 'windows-1252'; case 'windows1253': return 'windows-1253'; case 'csisolatin5': case 'iso88599': case 'iso885991989': case 'isoir148': case 'l5': case 'latin5': case 'windows1254': return 'windows-1254'; case 'windows1255': return 'windows-1255'; case 'windows1256': return 'windows-1256'; case 'windows1257': return 'windows-1257'; case 'windows1258': return 'windows-1258'; default: return $charset; } } public static function get_curl_version() { if (is_array($curl = curl_version())) { $curl = $curl['version']; } elseif (substr($curl, 0, 5) === 'curl/') { $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); } elseif (substr($curl, 0, 8) === 'libcurl/') { $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); } else { $curl = 0; } return $curl; } /** * Strip HTML comments * * @param string $data Data to strip comments from * @return string Comment stripped string */ public static function strip_comments($data) { $output = ''; while (($start = strpos($data, '<!--')) !== false) { $output .= substr($data, 0, $start); if (($end = strpos($data, '-->', $start)) !== false) { $data = substr_replace($data, '', 0, $end + 3); } else { $data = ''; } } return $output . $data; } public static function parse_date($dt) { $parser = \SimplePie\Parse\Date::get(); return $parser->parse($dt); } /** * Decode HTML entities * * @deprecated since SimplePie 1.3, use DOMDocument instead * @param string $data Input data * @return string Output data */ public static function entities_decode($data) { // trigger_error(sprintf('Using method "' . __METHOD__ . '" is deprecated since SimplePie 1.3, use "DOMDocument" instead.'), \E_USER_DEPRECATED); $decoder = new \SimplePie_Decode_HTML_Entities($data); return $decoder->parse(); } /** * Remove RFC822 comments * * @param string $data Data to strip comments from * @return string Comment stripped string */ public static function uncomment_rfc822($string) { $string = (string) $string; $position = 0; $length = strlen($string); $depth = 0; $output = ''; while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) { $output .= substr($string, $position, $pos - $position); $position = $pos + 1; if ($string[$pos - 1] !== '\\') { $depth++; while ($depth && $position < $length) { $position += strcspn($string, '()', $position); if ($string[$position - 1] === '\\') { $position++; continue; } elseif (isset($string[$position])) { switch ($string[$position]) { case '(': $depth++; break; case ')': $depth--; break; } $position++; } else { break; } } } else { $output .= '('; } } $output .= substr($string, $position); return $output; } public static function parse_mime($mime) { if (($pos = strpos($mime, ';')) === false) { return trim($mime); } return trim(substr($mime, 0, $pos)); } public static function atom_03_construct_type($attribs) { if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode'])) === 'base64') { $mode = \SimplePie\SimplePie::CONSTRUCT_BASE64; } else { $mode = \SimplePie\SimplePie::CONSTRUCT_NONE; } if (isset($attribs['']['type'])) { switch (strtolower(trim($attribs['']['type']))) { case 'text': case 'text/plain': return \SimplePie\SimplePie::CONSTRUCT_TEXT | $mode; case 'html': case 'text/html': return \SimplePie\SimplePie::CONSTRUCT_HTML | $mode; case 'xhtml': case 'application/xhtml+xml': return \SimplePie\SimplePie::CONSTRUCT_XHTML | $mode; default: return \SimplePie\SimplePie::CONSTRUCT_NONE | $mode; } } return \SimplePie\SimplePie::CONSTRUCT_TEXT | $mode; } public static function atom_10_construct_type($attribs) { if (isset($attribs['']['type'])) { switch (strtolower(trim($attribs['']['type']))) { case 'text': return \SimplePie\SimplePie::CONSTRUCT_TEXT; case 'html': return \SimplePie\SimplePie::CONSTRUCT_HTML; case 'xhtml': return \SimplePie\SimplePie::CONSTRUCT_XHTML; default: return \SimplePie\SimplePie::CONSTRUCT_NONE; } } return \SimplePie\SimplePie::CONSTRUCT_TEXT; } public static function atom_10_content_construct_type($attribs) { if (isset($attribs['']['type'])) { $type = strtolower(trim($attribs['']['type'])); switch ($type) { case 'text': return \SimplePie\SimplePie::CONSTRUCT_TEXT; case 'html': return \SimplePie\SimplePie::CONSTRUCT_HTML; case 'xhtml': return \SimplePie\SimplePie::CONSTRUCT_XHTML; } if (in_array(substr($type, -4), ['+xml', '/xml']) || substr($type, 0, 5) === 'text/') { return \SimplePie\SimplePie::CONSTRUCT_NONE; } else { return \SimplePie\SimplePie::CONSTRUCT_BASE64; } } return \SimplePie\SimplePie::CONSTRUCT_TEXT; } public static function is_isegment_nz_nc($string) { return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string); } public static function space_separated_tokens($string) { $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; $string_length = strlen($string); $position = strspn($string, $space_characters); $tokens = []; while ($position < $string_length) { $len = strcspn($string, $space_characters, $position); $tokens[] = substr($string, $position, $len); $position += $len; $position += strspn($string, $space_characters, $position); } return $tokens; } /** * Converts a unicode codepoint to a UTF-8 character * * @static * @param int $codepoint Unicode codepoint * @return string UTF-8 character */ public static function codepoint_to_utf8($codepoint) { $codepoint = (int) $codepoint; if ($codepoint < 0) { return false; } elseif ($codepoint <= 0x7f) { return chr($codepoint); } elseif ($codepoint <= 0x7ff) { return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); } elseif ($codepoint <= 0xffff) { return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); } elseif ($codepoint <= 0x10ffff) { return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); } // U+FFFD REPLACEMENT CHARACTER return "\xEF\xBF\xBD"; } /** * Similar to parse_str() * * Returns an associative array of name/value pairs, where the value is an * array of values that have used the same name * * @static * @param string $str The input string. * @return array */ public static function parse_str($str) { $return = []; $str = explode('&', $str); foreach ($str as $section) { if (strpos($section, '=') !== false) { [$name, $value] = explode('=', $section, 2); $return[urldecode($name)][] = urldecode($value); } else { $return[urldecode($section)][] = null; } } return $return; } /** * Detect XML encoding, as per XML 1.0 Appendix F.1 * * @todo Add support for EBCDIC * @param string $data XML data * @param \SimplePie\Registry $registry Class registry * @return array Possible encodings */ public static function xml_encoding($data, $registry) { // UTF-32 Big Endian BOM if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") { $encoding[] = 'UTF-32BE'; } // UTF-32 Little Endian BOM elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") { $encoding[] = 'UTF-32LE'; } // UTF-16 Big Endian BOM elseif (substr($data, 0, 2) === "\xFE\xFF") { $encoding[] = 'UTF-16BE'; } // UTF-16 Little Endian BOM elseif (substr($data, 0, 2) === "\xFF\xFE") { $encoding[] = 'UTF-16LE'; } // UTF-8 BOM elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") { $encoding[] = 'UTF-8'; } // UTF-32 Big Endian Without BOM elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C") { if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E")) { $parser = $registry->create(Parser::class, [Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')]); if ($parser->parse()) { $encoding[] = $parser->encoding; } } $encoding[] = 'UTF-32BE'; } // UTF-32 Little Endian Without BOM elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00") { if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00")) { $parser = $registry->create(Parser::class, [Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')]); if ($parser->parse()) { $encoding[] = $parser->encoding; } } $encoding[] = 'UTF-32LE'; } // UTF-16 Big Endian Without BOM elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C") { if ($pos = strpos($data, "\x00\x3F\x00\x3E")) { $parser = $registry->create(Parser::class, [Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')]); if ($parser->parse()) { $encoding[] = $parser->encoding; } } $encoding[] = 'UTF-16BE'; } // UTF-16 Little Endian Without BOM elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00") { if ($pos = strpos($data, "\x3F\x00\x3E\x00")) { $parser = $registry->create(Parser::class, [Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')]); if ($parser->parse()) { $encoding[] = $parser->encoding; } } $encoding[] = 'UTF-16LE'; } // US-ASCII (or superset) elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C") { if ($pos = strpos($data, "\x3F\x3E")) { $parser = $registry->create(Parser::class, [substr($data, 5, $pos - 5)]); if ($parser->parse()) { $encoding[] = $parser->encoding; } } $encoding[] = 'UTF-8'; } // Fallback to UTF-8 else { $encoding[] = 'UTF-8'; } return $encoding; } public static function output_javascript() { if (function_exists('ob_gzhandler')) { ob_start('ob_gzhandler'); } header('Content-type: text/javascript; charset: UTF-8'); header('Cache-Control: must-revalidate'); header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days $body = <<<END function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { if (placeholder != '') { document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); } else { document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); } } function embed_flash(bgcolor, width, height, link, loop, type) { document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>'); } function embed_flv(width, height, link, placeholder, loop, player) { document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>'); } function embed_wmedia(width, height, link) { document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>'); } END; echo $body; } /** * Get the SimplePie build timestamp * * Uses the git index if it exists, otherwise uses the modification time * of the newest file. */ public static function get_build() { if (static::$SIMPLEPIE_BUILD !== null) { return static::$SIMPLEPIE_BUILD; } $root = dirname(__FILE__, 2); if (file_exists($root . '/.git/index')) { static::$SIMPLEPIE_BUILD = filemtime($root . '/.git/index'); return static::$SIMPLEPIE_BUILD; } elseif (file_exists($root . '/SimplePie')) { $time = 0; foreach (glob($root . '/SimplePie/*.php') as $file) { if (($mtime = filemtime($file)) > $time) { $time = $mtime; } } static::$SIMPLEPIE_BUILD = $time; return static::$SIMPLEPIE_BUILD; } elseif (file_exists(dirname(__FILE__) . '/Core.php')) { static::$SIMPLEPIE_BUILD = filemtime(dirname(__FILE__) . '/Core.php'); return static::$SIMPLEPIE_BUILD; } static::$SIMPLEPIE_BUILD = filemtime(__FILE__); return static::$SIMPLEPIE_BUILD; } /** * Get the default user agent string * * @return string */ public static function get_default_useragent() { return \SimplePie\SimplePie::NAME . '/' . \SimplePie\SimplePie::VERSION . ' (Feed Parser; ' . \SimplePie\SimplePie::URL . '; Allow like Gecko) Build/' . static::get_build(); } /** * Format debugging information */ public static function debug(&$sp) { $info = 'SimplePie ' . \SimplePie\SimplePie::VERSION . ' Build ' . static::get_build() . "\n"; $info .= 'PHP ' . PHP_VERSION . "\n"; if ($sp->error() !== null) { $info .= 'Error occurred: ' . $sp->error() . "\n"; } else { $info .= "No error found.\n"; } $info .= "Extensions:\n"; $extensions = ['pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml']; foreach ($extensions as $ext) { if (extension_loaded($ext)) { $info .= " $ext loaded\n"; switch ($ext) { case 'pcre': $info .= ' Version ' . PCRE_VERSION . "\n"; break; case 'curl': $version = curl_version(); $info .= ' Version ' . $version['version'] . "\n"; break; case 'mbstring': $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n"; break; case 'iconv': $info .= ' Version ' . ICONV_VERSION . "\n"; break; case 'xml': $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n"; break; } } else { $info .= " $ext not loaded\n"; } } return $info; } public static function silence_errors($num, $str) { // No-op } /** * Sanitize a URL by removing HTTP credentials. * @param string $url the URL to sanitize. * @return string the same URL without HTTP credentials. */ public static function url_remove_credentials($url) { return preg_replace('#^(https?://)[^/:@]+:[^/:@]+@#i', '$1', $url); } } class_alias('SimplePie\Misc', 'SimplePie_Misc', false); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RegistryAware.php�����������������������������������������������������������������������������������0000644�����������������00000004553�15021155231�0010047 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SimplePie * * A PHP-Based RSS and Atom Feed Framework. * Takes the hard work out of managing a complete RSS/Atom solution. * * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of the SimplePie Team nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package SimplePie * @copyright 2004-2022 Ryan Parman, Sam Sneddon, Ryan McCue * @author Ryan Parman * @author Sam Sneddon * @author Ryan McCue * @link http://simplepie.org/ SimplePie * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace SimplePie; /** * Handles the injection of Registry into other class * * {@see \SimplePie\SimplePie::get_registry()} * * @package SimplePie */ interface RegistryAware { /** * Set the Registry into the class * * @param Registry $registry * * @return void */ public function set_registry(Registry $registry)/* : void */; } �����������������������������������������������������������������������������������������������������������������������������������������������������Crypto32.php����������������������������������������������������������������������������������������0000644�����������������00000153517�15021200076�0006707 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Crypto32', false)) { return; } /** * Class ParagonIE_Sodium_Crypto * * ATTENTION! * * If you are using this library, you should be using * ParagonIE_Sodium_Compat in your code, not this class. */ abstract class ParagonIE_Sodium_Crypto32 { const aead_chacha20poly1305_KEYBYTES = 32; const aead_chacha20poly1305_NSECBYTES = 0; const aead_chacha20poly1305_NPUBBYTES = 8; const aead_chacha20poly1305_ABYTES = 16; const aead_chacha20poly1305_IETF_KEYBYTES = 32; const aead_chacha20poly1305_IETF_NSECBYTES = 0; const aead_chacha20poly1305_IETF_NPUBBYTES = 12; const aead_chacha20poly1305_IETF_ABYTES = 16; const aead_xchacha20poly1305_IETF_KEYBYTES = 32; const aead_xchacha20poly1305_IETF_NSECBYTES = 0; const aead_xchacha20poly1305_IETF_NPUBBYTES = 24; const aead_xchacha20poly1305_IETF_ABYTES = 16; const box_curve25519xsalsa20poly1305_SEEDBYTES = 32; const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32; const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32; const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32; const box_curve25519xsalsa20poly1305_NONCEBYTES = 24; const box_curve25519xsalsa20poly1305_MACBYTES = 16; const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16; const box_curve25519xsalsa20poly1305_ZEROBYTES = 32; const onetimeauth_poly1305_BYTES = 16; const onetimeauth_poly1305_KEYBYTES = 32; const secretbox_xsalsa20poly1305_KEYBYTES = 32; const secretbox_xsalsa20poly1305_NONCEBYTES = 24; const secretbox_xsalsa20poly1305_MACBYTES = 16; const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16; const secretbox_xsalsa20poly1305_ZEROBYTES = 32; const secretbox_xchacha20poly1305_KEYBYTES = 32; const secretbox_xchacha20poly1305_NONCEBYTES = 24; const secretbox_xchacha20poly1305_MACBYTES = 16; const secretbox_xchacha20poly1305_BOXZEROBYTES = 16; const secretbox_xchacha20poly1305_ZEROBYTES = 32; const stream_salsa20_KEYBYTES = 32; /** * AEAD Decryption with ChaCha20-Poly1305 * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_decrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $len - Length of message (ciphertext + MAC) */ $len = ParagonIE_Sodium_Core32_Util::strlen($message); /** @var int $clen - Length of ciphertext */ $clen = $len - self::aead_chacha20poly1305_ABYTES; /** @var int $adlen - Length of associated data */ $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); /** @var string $mac - Message authentication code */ $mac = ParagonIE_Sodium_Core32_Util::substr( $message, $clen, self::aead_chacha20poly1305_ABYTES ); /** @var string $ciphertext - The encrypted message (sans MAC) */ $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen); /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( 32, $nonce, $key ); /* Recalculate the Poly1305 authentication tag (MAC): */ $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } $state->update($ad); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); $state->update($ciphertext); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen)); $computed_mac = $state->finish(); /* Compare the given MAC with the recalculated MAC: */ if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) { throw new SodiumException('Invalid MAC'); } // Here, we know that the MAC is valid, so we decrypt and return the plaintext return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( $ciphertext, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1) ); } /** * AEAD Encryption with ChaCha20-Poly1305 * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_encrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $len - Length of the plaintext message */ $len = ParagonIE_Sodium_Core32_Util::strlen($message); /** @var int $adlen - Length of the associated data */ $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( 32, $nonce, $key ); $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } /** @var string $ciphertext - Raw encrypted data */ $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( $message, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1) ); $state->update($ad); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); $state->update($ciphertext); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len)); return $ciphertext . $state->finish(); } /** * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_ietf_decrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $adlen - Length of associated data */ $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); /** @var int $len - Length of message (ciphertext + MAC) */ $len = ParagonIE_Sodium_Core32_Util::strlen($message); /** @var int $clen - Length of ciphertext */ $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES; /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream( 32, $nonce, $key ); /** @var string $mac - Message authentication code */ $mac = ParagonIE_Sodium_Core32_Util::substr( $message, $len - self::aead_chacha20poly1305_IETF_ABYTES, self::aead_chacha20poly1305_IETF_ABYTES ); /** @var string $ciphertext - The encrypted message (sans MAC) */ $ciphertext = ParagonIE_Sodium_Core32_Util::substr( $message, 0, $len - self::aead_chacha20poly1305_IETF_ABYTES ); /* Recalculate the Poly1305 authentication tag (MAC): */ $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } $state->update($ad); $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); $state->update($ciphertext); $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf)); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen)); $computed_mac = $state->finish(); /* Compare the given MAC with the recalculated MAC: */ if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) { throw new SodiumException('Invalid MAC'); } // Here, we know that the MAC is valid, so we decrypt and return the plaintext return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( $ciphertext, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1) ); } /** * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_ietf_encrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $len - Length of the plaintext message */ $len = ParagonIE_Sodium_Core32_Util::strlen($message); /** @var int $adlen - Length of the associated data */ $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream( 32, $nonce, $key ); $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } /** @var string $ciphertext - Raw encrypted data */ $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( $message, $nonce, $key, ParagonIE_Sodium_Core32_Util::store64_le(1) ); $state->update($ad); $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); $state->update($ciphertext); $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf))); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len)); return $ciphertext . $state->finish(); } /** * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_xchacha20poly1305_ietf_decrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), $key ); $nonceLast = "\x00\x00\x00\x00" . ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey); } /** * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_xchacha20poly1305_ietf_encrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), $key ); $nonceLast = "\x00\x00\x00\x00" . ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey); } /** * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $key * @return string * @throws TypeError */ public static function auth($message, $key) { return ParagonIE_Sodium_Core32_Util::substr( hash_hmac('sha512', $message, $key, true), 0, 32 ); } /** * HMAC-SHA-512-256 validation. Constant-time via hash_equals(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $mac * @param string $message * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ public static function auth_verify($mac, $message, $key) { return ParagonIE_Sodium_Core32_Util::hashEquals( $mac, self::auth($message, $key) ); } /** * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $plaintext * @param string $nonce * @param string $keypair * @return string * @throws SodiumException * @throws TypeError */ public static function box($plaintext, $nonce, $keypair) { return self::secretbox( $plaintext, $nonce, self::box_beforenm( self::box_secretkey($keypair), self::box_publickey($keypair) ) ); } /** * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $publicKey * @return string * @throws SodiumException * @throws TypeError */ public static function box_seal($message, $publicKey) { /** @var string $ephemeralKeypair */ $ephemeralKeypair = self::box_keypair(); /** @var string $ephemeralSK */ $ephemeralSK = self::box_secretkey($ephemeralKeypair); /** @var string $ephemeralPK */ $ephemeralPK = self::box_publickey($ephemeralKeypair); /** @var string $nonce */ $nonce = self::generichash( $ephemeralPK . $publicKey, '', 24 ); /** @var string $keypair - The combined keypair used in crypto_box() */ $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey); /** @var string $ciphertext Ciphertext + MAC from crypto_box */ $ciphertext = self::box($message, $nonce, $keypair); try { ParagonIE_Sodium_Compat::memzero($ephemeralKeypair); ParagonIE_Sodium_Compat::memzero($ephemeralSK); ParagonIE_Sodium_Compat::memzero($nonce); } catch (SodiumException $ex) { $ephemeralKeypair = null; $ephemeralSK = null; $nonce = null; } return $ephemeralPK . $ciphertext; } /** * Opens a message encrypted via box_seal(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $keypair * @return string * @throws SodiumException * @throws TypeError */ public static function box_seal_open($message, $keypair) { /** @var string $ephemeralPK */ $ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32); /** @var string $ciphertext (ciphertext + MAC) */ $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32); /** @var string $secretKey */ $secretKey = self::box_secretkey($keypair); /** @var string $publicKey */ $publicKey = self::box_publickey($keypair); /** @var string $nonce */ $nonce = self::generichash( $ephemeralPK . $publicKey, '', 24 ); /** @var string $keypair */ $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK); /** @var string $m */ $m = self::box_open($ciphertext, $nonce, $keypair); try { ParagonIE_Sodium_Compat::memzero($secretKey); ParagonIE_Sodium_Compat::memzero($ephemeralPK); ParagonIE_Sodium_Compat::memzero($nonce); } catch (SodiumException $ex) { $secretKey = null; $ephemeralPK = null; $nonce = null; } return $m; } /** * Used by crypto_box() to get the crypto_secretbox() key. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sk * @param string $pk * @return string * @throws SodiumException * @throws TypeError */ public static function box_beforenm($sk, $pk) { return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20( str_repeat("\x00", 16), self::scalarmult($sk, $pk) ); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @return string * @throws Exception * @throws SodiumException * @throws TypeError */ public static function box_keypair() { $sKey = random_bytes(32); $pKey = self::scalarmult_base($sKey); return $sKey . $pKey; } /** * @param string $seed * @return string * @throws SodiumException * @throws TypeError */ public static function box_seed_keypair($seed) { $sKey = ParagonIE_Sodium_Core32_Util::substr( hash('sha512', $seed, true), 0, 32 ); $pKey = self::scalarmult_base($sKey); return $sKey . $pKey; } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sKey * @param string $pKey * @return string * @throws TypeError */ public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey) { return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) . ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $keypair * @return string * @throws RangeException * @throws TypeError */ public static function box_secretkey($keypair) { if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) { throw new RangeException( 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' ); } return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $keypair * @return string * @throws RangeException * @throws TypeError */ public static function box_publickey($keypair) { if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { throw new RangeException( 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' ); } return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sKey * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function box_publickey_from_secretkey($sKey) { if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) { throw new RangeException( 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.' ); } return self::scalarmult_base($sKey); } /** * Decrypt a message encrypted with box(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ciphertext * @param string $nonce * @param string $keypair * @return string * @throws SodiumException * @throws TypeError */ public static function box_open($ciphertext, $nonce, $keypair) { return self::secretbox_open( $ciphertext, $nonce, self::box_beforenm( self::box_secretkey($keypair), self::box_publickey($keypair) ) ); } /** * Calculate a BLAKE2b hash. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string|null $key * @param int $outlen * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function generichash($message, $key = '', $outlen = 32) { // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); $k = null; if (!empty($key)) { /** @var SplFixedArray $k */ $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { throw new RangeException('Invalid key size'); } } /** @var SplFixedArray $in */ $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); /** @var SplFixedArray $ctx */ $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen); ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count()); /** @var SplFixedArray $out */ $out = new SplFixedArray($outlen); $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out); /** @var array<int, int> */ $outArray = $out->toArray(); return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray); } /** * Finalize a BLAKE2b hashing context, returning the hash. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ctx * @param int $outlen * @return string * @throws SodiumException * @throws TypeError */ public static function generichash_final($ctx, $outlen = 32) { if (!is_string($ctx)) { throw new TypeError('Context must be a string'); } $out = new SplFixedArray($outlen); /** @var SplFixedArray $context */ $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); /** @var SplFixedArray $out */ $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out); /** @var array<int, int> */ $outArray = $out->toArray(); return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray); } /** * Initialize a hashing context for BLAKE2b. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $key * @param int $outputLength * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function generichash_init($key = '', $outputLength = 32) { // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); $k = null; if (!empty($key)) { $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { throw new RangeException('Invalid key size'); } } /** @var SplFixedArray $ctx */ $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength); return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); } /** * Initialize a hashing context for BLAKE2b. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $key * @param int $outputLength * @param string $salt * @param string $personal * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function generichash_init_salt_personal( $key = '', $outputLength = 32, $salt = '', $personal = '' ) { // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); $k = null; if (!empty($key)) { $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { throw new RangeException('Invalid key size'); } } if (!empty($salt)) { $s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt); } else { $s = null; } if (!empty($salt)) { $p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal); } else { $p = null; } /** @var SplFixedArray $ctx */ $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p); return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); } /** * Update a hashing context for BLAKE2b with $message * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ctx * @param string $message * @return string * @throws SodiumException * @throws TypeError */ public static function generichash_update($ctx, $message) { // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); /** @var SplFixedArray $context */ $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); /** @var SplFixedArray $in */ $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count()); return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context); } /** * Libsodium's crypto_kx(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $my_sk * @param string $their_pk * @param string $client_pk * @param string $server_pk * @return string * @throws SodiumException * @throws TypeError */ public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) { return self::generichash( self::scalarmult($my_sk, $their_pk) . $client_pk . $server_pk ); } /** * ECDH over Curve25519 * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sKey * @param string $pKey * @return string * * @throws SodiumException * @throws TypeError */ public static function scalarmult($sKey, $pKey) { $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); self::scalarmult_throw_if_zero($q); return $q; } /** * ECDH over Curve25519, using the basepoint. * Used to get a secret key from a public key. * * @param string $secret * @return string * * @throws SodiumException * @throws TypeError */ public static function scalarmult_base($secret) { $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret); self::scalarmult_throw_if_zero($q); return $q; } /** * This throws an Error if a zero public key was passed to the function. * * @param string $q * @return void * @throws SodiumException * @throws TypeError */ protected static function scalarmult_throw_if_zero($q) { $d = 0; for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { $d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]); } /* branch-free variant of === 0 */ if (-(1 & (($d - 1) >> 8))) { throw new SodiumException('Zero public key is not allowed'); } } /** * XSalsa20-Poly1305 authenticated symmetric-key encryption. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $plaintext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox($plaintext, $nonce, $key) { /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); /** @var string $block0 */ $block0 = str_repeat("\x00", 32); /** @var int $mlen - Length of the plaintext message */ $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); $mlen0 = $mlen; if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) { $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES; } $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor( $block0, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey ); /** @var string $c */ $c = ParagonIE_Sodium_Core32_Util::substr( $block0, self::secretbox_xsalsa20poly1305_ZEROBYTES ); if ($mlen > $mlen0) { $c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( ParagonIE_Sodium_Core32_Util::substr( $plaintext, self::secretbox_xsalsa20poly1305_ZEROBYTES ), ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1, $subkey ); } $state = new ParagonIE_Sodium_Core32_Poly1305_State( ParagonIE_Sodium_Core32_Util::substr( $block0, 0, self::onetimeauth_poly1305_KEYBYTES ) ); try { ParagonIE_Sodium_Compat::memzero($block0); ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $block0 = null; $subkey = null; } $state->update($c); /** @var string $c - MAC || ciphertext */ $c = $state->finish() . $c; unset($state); return $c; } /** * Decrypt a ciphertext generated via secretbox(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ciphertext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox_open($ciphertext, $nonce, $key) { /** @var string $mac */ $mac = ParagonIE_Sodium_Core32_Util::substr( $ciphertext, 0, self::secretbox_xsalsa20poly1305_MACBYTES ); /** @var string $c */ $c = ParagonIE_Sodium_Core32_Util::substr( $ciphertext, self::secretbox_xsalsa20poly1305_MACBYTES ); /** @var int $clen */ $clen = ParagonIE_Sodium_Core32_Util::strlen($c); /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20( 64, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey ); $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( $mac, $c, ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) ); if (!$verified) { try { ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $subkey = null; } throw new SodiumException('Invalid MAC'); } /** @var string $m - Decrypted message */ $m = ParagonIE_Sodium_Core32_Util::xorStrings( ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) ); if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { // We had more than 1 block, so let's continue to decrypt the rest. $m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( ParagonIE_Sodium_Core32_Util::substr( $c, self::secretbox_xsalsa20poly1305_ZEROBYTES ), ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1, (string) $subkey ); } return $m; } /** * XChaCha20-Poly1305 authenticated symmetric-key encryption. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $plaintext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) { /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), $key ); $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); /** @var string $block0 */ $block0 = str_repeat("\x00", 32); /** @var int $mlen - Length of the plaintext message */ $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); $mlen0 = $mlen; if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; } $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( $block0, $nonceLast, $subkey ); /** @var string $c */ $c = ParagonIE_Sodium_Core32_Util::substr( $block0, self::secretbox_xchacha20poly1305_ZEROBYTES ); if ($mlen > $mlen0) { $c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( ParagonIE_Sodium_Core32_Util::substr( $plaintext, self::secretbox_xchacha20poly1305_ZEROBYTES ), $nonceLast, $subkey, ParagonIE_Sodium_Core32_Util::store64_le(1) ); } $state = new ParagonIE_Sodium_Core32_Poly1305_State( ParagonIE_Sodium_Core32_Util::substr( $block0, 0, self::onetimeauth_poly1305_KEYBYTES ) ); try { ParagonIE_Sodium_Compat::memzero($block0); ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $block0 = null; $subkey = null; } $state->update($c); /** @var string $c - MAC || ciphertext */ $c = $state->finish() . $c; unset($state); return $c; } /** * Decrypt a ciphertext generated via secretbox_xchacha20poly1305(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ciphertext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) { /** @var string $mac */ $mac = ParagonIE_Sodium_Core32_Util::substr( $ciphertext, 0, self::secretbox_xchacha20poly1305_MACBYTES ); /** @var string $c */ $c = ParagonIE_Sodium_Core32_Util::substr( $ciphertext, self::secretbox_xchacha20poly1305_MACBYTES ); /** @var int $clen */ $clen = ParagonIE_Sodium_Core32_Util::strlen($c); /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( 64, ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), $subkey ); $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( $mac, $c, ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) ); if (!$verified) { try { ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $subkey = null; } throw new SodiumException('Invalid MAC'); } /** @var string $m - Decrypted message */ $m = ParagonIE_Sodium_Core32_Util::xorStrings( ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) ); if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { // We had more than 1 block, so let's continue to decrypt the rest. $m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( ParagonIE_Sodium_Core32_Util::substr( $c, self::secretbox_xchacha20poly1305_ZEROBYTES ), ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), (string) $subkey, ParagonIE_Sodium_Core32_Util::store64_le(1) ); } return $m; } /** * @param string $key * @return array<int, string> Returns a state and a header. * @throws Exception * @throws SodiumException */ public static function secretstream_xchacha20poly1305_init_push($key) { # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES); $out = random_bytes(24); # crypto_core_hchacha20(state->k, out, k, NULL); $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key); $state = new ParagonIE_Sodium_Core32_SecretStream_State( $subkey, ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4) ); # _crypto_secretstream_xchacha20poly1305_counter_reset(state); $state->counterReset(); # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); # memset(state->_pad, 0, sizeof state->_pad); return array( $state->toString(), $out ); } /** * @param string $key * @param string $header * @return string Returns a state. * @throws Exception */ public static function secretstream_xchacha20poly1305_init_pull($key, $header) { # crypto_core_hchacha20(state->k, in, k, NULL); $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( ParagonIE_Sodium_Core32_Util::substr($header, 0, 16), $key ); $state = new ParagonIE_Sodium_Core32_SecretStream_State( $subkey, ParagonIE_Sodium_Core32_Util::substr($header, 16) ); $state->counterReset(); # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); # memset(state->_pad, 0, sizeof state->_pad); # return 0; return $state->toString(); } /** * @param string $state * @param string $msg * @param string $aad * @param int $tag * @return string * @throws SodiumException */ public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) { $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); # crypto_onetimeauth_poly1305_state poly1305_state; # unsigned char block[64U]; # unsigned char slen[8U]; # unsigned char *c; # unsigned char *mac; $msglen = ParagonIE_Sodium_Core32_Util::strlen($msg); $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); if ((($msglen + 63) >> 6) > 0xfffffffe) { throw new SodiumException( 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' ); } # if (outlen_p != NULL) { # *outlen_p = 0U; # } # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { # sodium_misuse(); # } # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); # crypto_onetimeauth_poly1305_init(&poly1305_state, block); # sodium_memzero(block, sizeof block); $auth = new ParagonIE_Sodium_Core32_Poly1305_State( ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); $auth->update($aad); # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, # (0x10 - adlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); # memset(block, 0, sizeof block); # block[0] = tag; # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, # state->nonce, 1U, state->k); $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63), $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(1) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); $auth->update($block); # out[0] = block[0]; $out = $block[0]; # c = out + (sizeof tag); # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); $cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( $msg, $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(2) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); $auth->update($cipher); $out .= $cipher; unset($cipher); # crypto_onetimeauth_poly1305_update # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); # STORE64_LE(slen, (uint64_t) adlen); $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $auth->update($slen); # STORE64_LE(slen, (sizeof block) + mlen); $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $auth->update($slen); # mac = c + mlen; # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); $mac = $auth->finish(); $out .= $mac; # sodium_memzero(&poly1305_state, sizeof poly1305_state); unset($auth); # XOR_BUF(STATE_INONCE(state), mac, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); $st->xorNonce($mac); # sodium_increment(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); $st->incrementCounter(); // Overwrite by reference: $state = $st->toString(); /** @var bool $rekey */ $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || # sodium_is_zero(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { # crypto_secretstream_xchacha20poly1305_rekey(state); # } if ($rekey || $st->needsRekey()) { // DO REKEY self::secretstream_xchacha20poly1305_rekey($state); } # if (outlen_p != NULL) { # *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; # } return $out; } /** * @param string $state * @param string $cipher * @param string $aad * @return bool|array{0: string, 1: int} * @throws SodiumException */ public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '') { $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); $cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher); # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { # sodium_misuse(); # } if ((($msglen + 63) >> 6) > 0xfffffffe) { throw new SodiumException( 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' ); } # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); # crypto_onetimeauth_poly1305_init(&poly1305_state, block); # sodium_memzero(block, sizeof block); $auth = new ParagonIE_Sodium_Core32_Poly1305_State( ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); $auth->update($aad); # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, # (0x10 - adlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); # memset(block, 0, sizeof block); # block[0] = in[0]; # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, # state->nonce, 1U, state->k); $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( $cipher[0] . str_repeat("\0", 63), $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(1) ); # tag = block[0]; # block[0] = in[0]; # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); $tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]); $block[0] = $cipher[0]; $auth->update($block); # c = in + (sizeof tag); # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); $auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen)); # crypto_onetimeauth_poly1305_update # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); # STORE64_LE(slen, (uint64_t) adlen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); $auth->update($slen); # STORE64_LE(slen, (sizeof block) + mlen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); $auth->update($slen); # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); # sodium_memzero(&poly1305_state, sizeof poly1305_state); $mac = $auth->finish(); # stored_mac = c + mlen; # if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { # sodium_memzero(mac, sizeof mac); # return -1; # } $stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16); if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) { return false; } # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); $out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen), $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(2) ); # XOR_BUF(STATE_INONCE(state), mac, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); $st->xorNonce($mac); # sodium_increment(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); $st->incrementCounter(); # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || # sodium_is_zero(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { # crypto_secretstream_xchacha20poly1305_rekey(state); # } // Overwrite by reference: $state = $st->toString(); /** @var bool $rekey */ $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; if ($rekey || $st->needsRekey()) { // DO REKEY self::secretstream_xchacha20poly1305_rekey($state); } return array($out, $tag); } /** * @param string $state * @return void * @throws SodiumException */ public static function secretstream_xchacha20poly1305_rekey(&$state) { $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + # crypto_secretstream_xchacha20poly1305_INONCEBYTES]; # size_t i; # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { # new_key_and_inonce[i] = state->k[i]; # } $new_key_and_inonce = $st->getKey(); # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = # STATE_INONCE(state)[i]; # } $new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8); # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, # sizeof new_key_and_inonce, # state->nonce, state->k); $st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( $new_key_and_inonce, $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core32_Util::store64_le(0) )); # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { # state->k[i] = new_key_and_inonce[i]; # } # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { # STATE_INONCE(state)[i] = # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]; # } # _crypto_secretstream_xchacha20poly1305_counter_reset(state); $st->counterReset(); $state = $st->toString(); } /** * Detached Ed25519 signature. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign_detached($message, $sk) { return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk); } /** * Attached Ed25519 signature. (Returns a signed message.) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign($message, $sk) { return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk); } /** * Opens a signed message. If valid, returns the message. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $signedMessage * @param string $pk * @return string * @throws SodiumException * @throws TypeError */ public static function sign_open($signedMessage, $pk) { return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk); } /** * Verify a detached signature of a given message and public key. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $signature * @param string $message * @param string $pk * @return bool * @throws SodiumException * @throws TypeError */ public static function sign_verify_detached($signature, $message, $pk) { return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SodiumException.php���������������������������������������������������������������������������������0000644�����������������00000000236�15021200076�0010366 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (!class_exists('SodiumException', false)) { /** * Class SodiumException */ class SodiumException extends Exception { } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PHP52/SplFixedArray.php�����������������������������������������������������������������������������0000644�����������������00000010024�15021200076�0010556 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('SplFixedArray')) { return; } /** * The SplFixedArray class provides the main functionalities of array. The * main differences between a SplFixedArray and a normal PHP array is that * the SplFixedArray is of fixed length and allows only integers within * the range as indexes. The advantage is that it allows a faster array * implementation. */ class SplFixedArray implements Iterator, ArrayAccess, Countable { /** @var array<int, mixed> */ private $internalArray = array(); /** @var int $size */ private $size = 0; /** * SplFixedArray constructor. * @param int $size */ public function __construct($size = 0) { $this->size = $size; $this->internalArray = array(); } /** * @return int */ public function count() { return count($this->internalArray); } /** * @return array */ public function toArray() { ksort($this->internalArray); return (array) $this->internalArray; } /** * @param array $array * @param bool $save_indexes * @return SplFixedArray * @psalm-suppress MixedAssignment */ public static function fromArray(array $array, $save_indexes = true) { $self = new SplFixedArray(count($array)); if($save_indexes) { foreach($array as $key => $value) { $self[(int) $key] = $value; } } else { $i = 0; foreach (array_values($array) as $value) { $self[$i] = $value; $i++; } } return $self; } /** * @return int */ public function getSize() { return $this->size; } /** * @param int $size * @return bool */ public function setSize($size) { $this->size = $size; return true; } /** * @param string|int $index * @return bool */ public function offsetExists($index) { return array_key_exists((int) $index, $this->internalArray); } /** * @param string|int $index * @return mixed */ public function offsetGet($index) { /** @psalm-suppress MixedReturnStatement */ return $this->internalArray[(int) $index]; } /** * @param string|int $index * @param mixed $newval * @psalm-suppress MixedAssignment */ public function offsetSet($index, $newval) { $this->internalArray[(int) $index] = $newval; } /** * @param string|int $index */ public function offsetUnset($index) { unset($this->internalArray[(int) $index]); } /** * Rewind iterator back to the start * @link https://php.net/manual/en/splfixedarray.rewind.php * @return void * @since 5.3.0 */ public function rewind() { reset($this->internalArray); } /** * Return current array entry * @link https://php.net/manual/en/splfixedarray.current.php * @return mixed The current element value. * @since 5.3.0 */ public function current() { /** @psalm-suppress MixedReturnStatement */ return current($this->internalArray); } /** * Return current array index * @return int The current array index. */ public function key() { return key($this->internalArray); } /** * @return void */ public function next() { next($this->internalArray); } /** * Check whether the array contains more elements * @link https://php.net/manual/en/splfixedarray.valid.php * @return bool true if the array contains any more elements, false otherwise. */ public function valid() { if (empty($this->internalArray)) { return false; } $result = next($this->internalArray) !== false; prev($this->internalArray); return $result; } /** * Do nothing. */ public function __wakeup() { // NOP } }������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/SecretStream/State.php�������������������������������������������������������������������������0000644�����������������00000007050�15021200076�0011621 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core_SecretStream_State */ class ParagonIE_Sodium_Core_SecretStream_State { /** @var string $key */ protected $key; /** @var int $counter */ protected $counter; /** @var string $nonce */ protected $nonce; /** @var string $_pad */ protected $_pad; /** * ParagonIE_Sodium_Core_SecretStream_State constructor. * @param string $key * @param string|null $nonce */ public function __construct($key, $nonce = null) { $this->key = $key; $this->counter = 1; if (is_null($nonce)) { $nonce = str_repeat("\0", 12); } $this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);; $this->_pad = str_repeat("\0", 4); } /** * @return self */ public function counterReset() { $this->counter = 1; $this->_pad = str_repeat("\0", 4); return $this; } /** * @return string */ public function getKey() { return $this->key; } /** * @return string */ public function getCounter() { return ParagonIE_Sodium_Core_Util::store32_le($this->counter); } /** * @return string */ public function getNonce() { if (!is_string($this->nonce)) { $this->nonce = str_repeat("\0", 12); } if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) { $this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT); } return $this->nonce; } /** * @return string */ public function getCombinedNonce() { return $this->getCounter() . ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8); } /** * @return self */ public function incrementCounter() { ++$this->counter; return $this; } /** * @return bool */ public function needsRekey() { return ($this->counter & 0xffff) === 0; } /** * @param string $newKeyAndNonce * @return self */ public function rekey($newKeyAndNonce) { $this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32); $this->nonce = str_pad( ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32), 12, "\0", STR_PAD_RIGHT ); return $this; } /** * @param string $str * @return self */ public function xorNonce($str) { $this->nonce = ParagonIE_Sodium_Core_Util::xorStrings( $this->getNonce(), str_pad( ParagonIE_Sodium_Core_Util::substr($str, 0, 8), 12, "\0", STR_PAD_RIGHT ) ); return $this; } /** * @param string $string * @return self */ public static function fromString($string) { $state = new ParagonIE_Sodium_Core_SecretStream_State( ParagonIE_Sodium_Core_Util::substr($string, 0, 32) ); $state->counter = ParagonIE_Sodium_Core_Util::load_4( ParagonIE_Sodium_Core_Util::substr($string, 32, 4) ); $state->nonce = ParagonIE_Sodium_Core_Util::substr($string, 36, 12); $state->_pad = ParagonIE_Sodium_Core_Util::substr($string, 48, 8); return $state; } /** * @return string */ public function toString() { return $this->key . $this->getCounter() . $this->nonce . $this->_pad; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/SipHash.php������������������������������������������������������������������������������������0000644�����������������00000020051�15021200076�0007473 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_SipHash', false)) { return; } /** * Class ParagonIE_SodiumCompat_Core_SipHash * * Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers */ class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util { /** * @internal You should not use this directly from another application * * @param int[] $v * @return int[] * */ public static function sipRound(array $v) { # v0 += v1; list($v[0], $v[1]) = self::add( array($v[0], $v[1]), array($v[2], $v[3]) ); # v1=ROTL(v1,13); list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 13); # v1 ^= v0; $v[2] = (int) $v[2] ^ (int) $v[0]; $v[3] = (int) $v[3] ^ (int) $v[1]; # v0=ROTL(v0,32); list($v[0], $v[1]) = self::rotl_64((int) $v[0], (int) $v[1], 32); # v2 += v3; list($v[4], $v[5]) = self::add( array((int) $v[4], (int) $v[5]), array((int) $v[6], (int) $v[7]) ); # v3=ROTL(v3,16); list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 16); # v3 ^= v2; $v[6] = (int) $v[6] ^ (int) $v[4]; $v[7] = (int) $v[7] ^ (int) $v[5]; # v0 += v3; list($v[0], $v[1]) = self::add( array((int) $v[0], (int) $v[1]), array((int) $v[6], (int) $v[7]) ); # v3=ROTL(v3,21); list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 21); # v3 ^= v0; $v[6] = (int) $v[6] ^ (int) $v[0]; $v[7] = (int) $v[7] ^ (int) $v[1]; # v2 += v1; list($v[4], $v[5]) = self::add( array((int) $v[4], (int) $v[5]), array((int) $v[2], (int) $v[3]) ); # v1=ROTL(v1,17); list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 17); # v1 ^= v2;; $v[2] = (int) $v[2] ^ (int) $v[4]; $v[3] = (int) $v[3] ^ (int) $v[5]; # v2=ROTL(v2,32) list($v[4], $v[5]) = self::rotl_64((int) $v[4], (int) $v[5], 32); return $v; } /** * Add two 32 bit integers representing a 64-bit integer. * * @internal You should not use this directly from another application * * @param int[] $a * @param int[] $b * @return array<int, mixed> */ public static function add(array $a, array $b) { /** @var int $x1 */ $x1 = $a[1] + $b[1]; /** @var int $c */ $c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff /** @var int $x0 */ $x0 = $a[0] + $b[0] + $c; return array( $x0 & 0xffffffff, $x1 & 0xffffffff ); } /** * @internal You should not use this directly from another application * * @param int $int0 * @param int $int1 * @param int $c * @return array<int, mixed> */ public static function rotl_64($int0, $int1, $c) { $int0 &= 0xffffffff; $int1 &= 0xffffffff; $c &= 63; if ($c === 32) { return array($int1, $int0); } if ($c > 31) { $tmp = $int1; $int1 = $int0; $int0 = $tmp; $c &= 31; } if ($c === 0) { return array($int0, $int1); } return array( 0xffffffff & ( ($int0 << $c) | ($int1 >> (32 - $c)) ), 0xffffffff & ( ($int1 << $c) | ($int0 >> (32 - $c)) ), ); } /** * Implements Siphash-2-4 using only 32-bit numbers. * * When we split an int into two, the higher bits go to the lower index. * e.g. 0xDEADBEEFAB10C92D becomes [ * 0 => 0xDEADBEEF, * 1 => 0xAB10C92D * ]. * * @internal You should not use this directly from another application * * @param string $in * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function sipHash24($in, $key) { $inlen = self::strlen($in); # /* "somepseudorandomlygeneratedbytes" */ # u64 v0 = 0x736f6d6570736575ULL; # u64 v1 = 0x646f72616e646f6dULL; # u64 v2 = 0x6c7967656e657261ULL; # u64 v3 = 0x7465646279746573ULL; $v = array( 0x736f6d65, // 0 0x70736575, // 1 0x646f7261, // 2 0x6e646f6d, // 3 0x6c796765, // 4 0x6e657261, // 5 0x74656462, // 6 0x79746573 // 7 ); // v0 => $v[0], $v[1] // v1 => $v[2], $v[3] // v2 => $v[4], $v[5] // v3 => $v[6], $v[7] # u64 k0 = LOAD64_LE( k ); # u64 k1 = LOAD64_LE( k + 8 ); $k = array( self::load_4(self::substr($key, 4, 4)), self::load_4(self::substr($key, 0, 4)), self::load_4(self::substr($key, 12, 4)), self::load_4(self::substr($key, 8, 4)) ); // k0 => $k[0], $k[1] // k1 => $k[2], $k[3] # b = ( ( u64 )inlen ) << 56; $b = array( $inlen << 24, 0 ); // See docblock for why the 0th index gets the higher bits. # v3 ^= k1; $v[6] ^= $k[2]; $v[7] ^= $k[3]; # v2 ^= k0; $v[4] ^= $k[0]; $v[5] ^= $k[1]; # v1 ^= k1; $v[2] ^= $k[2]; $v[3] ^= $k[3]; # v0 ^= k0; $v[0] ^= $k[0]; $v[1] ^= $k[1]; $left = $inlen; # for ( ; in != end; in += 8 ) while ($left >= 8) { # m = LOAD64_LE( in ); $m = array( self::load_4(self::substr($in, 4, 4)), self::load_4(self::substr($in, 0, 4)) ); # v3 ^= m; $v[6] ^= $m[0]; $v[7] ^= $m[1]; # SIPROUND; # SIPROUND; $v = self::sipRound($v); $v = self::sipRound($v); # v0 ^= m; $v[0] ^= $m[0]; $v[1] ^= $m[1]; $in = self::substr($in, 8); $left -= 8; } # switch( left ) # { # case 7: b |= ( ( u64 )in[ 6] ) << 48; # case 6: b |= ( ( u64 )in[ 5] ) << 40; # case 5: b |= ( ( u64 )in[ 4] ) << 32; # case 4: b |= ( ( u64 )in[ 3] ) << 24; # case 3: b |= ( ( u64 )in[ 2] ) << 16; # case 2: b |= ( ( u64 )in[ 1] ) << 8; # case 1: b |= ( ( u64 )in[ 0] ); break; # case 0: break; # } switch ($left) { case 7: $b[0] |= self::chrToInt($in[6]) << 16; case 6: $b[0] |= self::chrToInt($in[5]) << 8; case 5: $b[0] |= self::chrToInt($in[4]); case 4: $b[1] |= self::chrToInt($in[3]) << 24; case 3: $b[1] |= self::chrToInt($in[2]) << 16; case 2: $b[1] |= self::chrToInt($in[1]) << 8; case 1: $b[1] |= self::chrToInt($in[0]); case 0: break; } // See docblock for why the 0th index gets the higher bits. # v3 ^= b; $v[6] ^= $b[0]; $v[7] ^= $b[1]; # SIPROUND; # SIPROUND; $v = self::sipRound($v); $v = self::sipRound($v); # v0 ^= b; $v[0] ^= $b[0]; $v[1] ^= $b[1]; // Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation # v2 ^= 0xff; $v[5] ^= 0xff; # SIPROUND; # SIPROUND; # SIPROUND; # SIPROUND; $v = self::sipRound($v); $v = self::sipRound($v); $v = self::sipRound($v); $v = self::sipRound($v); # b = v0 ^ v1 ^ v2 ^ v3; # STORE64_LE( out, b ); return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) . self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Poly1305/State.php�����������������������������������������������������������������������������0000644�����������������00000031160�15021200076�0010453 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Poly1305_State', false)) { return; } /** * Class ParagonIE_Sodium_Core_Poly1305_State */ class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util { /** * @var array<int, int> */ protected $buffer = array(); /** * @var bool */ protected $final = false; /** * @var array<int, int> */ public $h; /** * @var int */ protected $leftover = 0; /** * @var int[] */ public $r; /** * @var int[] */ public $pad; /** * ParagonIE_Sodium_Core_Poly1305_State constructor. * * @internal You should not use this directly from another application * * @param string $key * @throws InvalidArgumentException * @throws TypeError */ public function __construct($key = '') { if (self::strlen($key) < 32) { throw new InvalidArgumentException( 'Poly1305 requires a 32-byte key' ); } /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ $this->r = array( (int) ((self::load_4(self::substr($key, 0, 4))) & 0x3ffffff), (int) ((self::load_4(self::substr($key, 3, 4)) >> 2) & 0x3ffff03), (int) ((self::load_4(self::substr($key, 6, 4)) >> 4) & 0x3ffc0ff), (int) ((self::load_4(self::substr($key, 9, 4)) >> 6) & 0x3f03fff), (int) ((self::load_4(self::substr($key, 12, 4)) >> 8) & 0x00fffff) ); /* h = 0 */ $this->h = array(0, 0, 0, 0, 0); /* save pad for later */ $this->pad = array( self::load_4(self::substr($key, 16, 4)), self::load_4(self::substr($key, 20, 4)), self::load_4(self::substr($key, 24, 4)), self::load_4(self::substr($key, 28, 4)), ); $this->leftover = 0; $this->final = false; } /** * Zero internal buffer upon destruction */ public function __destruct() { $this->r[0] ^= $this->r[0]; $this->r[1] ^= $this->r[1]; $this->r[2] ^= $this->r[2]; $this->r[3] ^= $this->r[3]; $this->r[4] ^= $this->r[4]; $this->h[0] ^= $this->h[0]; $this->h[1] ^= $this->h[1]; $this->h[2] ^= $this->h[2]; $this->h[3] ^= $this->h[3]; $this->h[4] ^= $this->h[4]; $this->pad[0] ^= $this->pad[0]; $this->pad[1] ^= $this->pad[1]; $this->pad[2] ^= $this->pad[2]; $this->pad[3] ^= $this->pad[3]; $this->leftover = 0; $this->final = true; } /** * @internal You should not use this directly from another application * * @param string $message * @return self * @throws SodiumException * @throws TypeError */ public function update($message = '') { $bytes = self::strlen($message); if ($bytes < 1) { return $this; } /* handle leftover */ if ($this->leftover) { $want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover; if ($want > $bytes) { $want = $bytes; } for ($i = 0; $i < $want; ++$i) { $mi = self::chrToInt($message[$i]); $this->buffer[$this->leftover + $i] = $mi; } // We snip off the leftmost bytes. $message = self::substr($message, $want); $bytes = self::strlen($message); $this->leftover += $want; if ($this->leftover < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { // We still don't have enough to run $this->blocks() return $this; } $this->blocks( self::intArrayToString($this->buffer), ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE ); $this->leftover = 0; } /* process full blocks */ if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { /** @var int $want */ $want = $bytes & ~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1); if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { $block = self::substr($message, 0, $want); if (self::strlen($block) >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { $this->blocks($block, $want); $message = self::substr($message, $want); $bytes = self::strlen($message); } } } /* store leftover */ if ($bytes) { for ($i = 0; $i < $bytes; ++$i) { $mi = self::chrToInt($message[$i]); $this->buffer[$this->leftover + $i] = $mi; } $this->leftover = (int) $this->leftover + $bytes; } return $this; } /** * @internal You should not use this directly from another application * * @param string $message * @param int $bytes * @return self * @throws TypeError */ public function blocks($message, $bytes) { if (self::strlen($message) < 16) { $message = str_pad($message, 16, "\x00", STR_PAD_RIGHT); } /** @var int $hibit */ $hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */ $r0 = (int) $this->r[0]; $r1 = (int) $this->r[1]; $r2 = (int) $this->r[2]; $r3 = (int) $this->r[3]; $r4 = (int) $this->r[4]; $s1 = self::mul($r1, 5, 3); $s2 = self::mul($r2, 5, 3); $s3 = self::mul($r3, 5, 3); $s4 = self::mul($r4, 5, 3); $h0 = $this->h[0]; $h1 = $this->h[1]; $h2 = $this->h[2]; $h3 = $this->h[3]; $h4 = $this->h[4]; while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { /* h += m[i] */ $h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff; $h1 += (self::load_4(self::substr($message, 3, 4)) >> 2) & 0x3ffffff; $h2 += (self::load_4(self::substr($message, 6, 4)) >> 4) & 0x3ffffff; $h3 += (self::load_4(self::substr($message, 9, 4)) >> 6) & 0x3ffffff; $h4 += (self::load_4(self::substr($message, 12, 4)) >> 8) | $hibit; /* h *= r */ $d0 = ( self::mul($h0, $r0, 27) + self::mul($s4, $h1, 27) + self::mul($s3, $h2, 27) + self::mul($s2, $h3, 27) + self::mul($s1, $h4, 27) ); $d1 = ( self::mul($h0, $r1, 27) + self::mul($h1, $r0, 27) + self::mul($s4, $h2, 27) + self::mul($s3, $h3, 27) + self::mul($s2, $h4, 27) ); $d2 = ( self::mul($h0, $r2, 27) + self::mul($h1, $r1, 27) + self::mul($h2, $r0, 27) + self::mul($s4, $h3, 27) + self::mul($s3, $h4, 27) ); $d3 = ( self::mul($h0, $r3, 27) + self::mul($h1, $r2, 27) + self::mul($h2, $r1, 27) + self::mul($h3, $r0, 27) + self::mul($s4, $h4, 27) ); $d4 = ( self::mul($h0, $r4, 27) + self::mul($h1, $r3, 27) + self::mul($h2, $r2, 27) + self::mul($h3, $r1, 27) + self::mul($h4, $r0, 27) ); /* (partial) h %= p */ /** @var int $c */ $c = $d0 >> 26; /** @var int $h0 */ $h0 = $d0 & 0x3ffffff; $d1 += $c; /** @var int $c */ $c = $d1 >> 26; /** @var int $h1 */ $h1 = $d1 & 0x3ffffff; $d2 += $c; /** @var int $c */ $c = $d2 >> 26; /** @var int $h2 */ $h2 = $d2 & 0x3ffffff; $d3 += $c; /** @var int $c */ $c = $d3 >> 26; /** @var int $h3 */ $h3 = $d3 & 0x3ffffff; $d4 += $c; /** @var int $c */ $c = $d4 >> 26; /** @var int $h4 */ $h4 = $d4 & 0x3ffffff; $h0 += (int) self::mul($c, 5, 3); /** @var int $c */ $c = $h0 >> 26; /** @var int $h0 */ $h0 &= 0x3ffffff; $h1 += $c; // Chop off the left 32 bytes. $message = self::substr( $message, ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE ); $bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; } $this->h = array( (int) ($h0 & 0xffffffff), (int) ($h1 & 0xffffffff), (int) ($h2 & 0xffffffff), (int) ($h3 & 0xffffffff), (int) ($h4 & 0xffffffff) ); return $this; } /** * @internal You should not use this directly from another application * * @return string * @throws TypeError */ public function finish() { /* process the remaining block */ if ($this->leftover) { $i = $this->leftover; $this->buffer[$i++] = 1; for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) { $this->buffer[$i] = 0; } $this->final = true; $this->blocks( self::substr( self::intArrayToString($this->buffer), 0, ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE ), ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE ); } $h0 = (int) $this->h[0]; $h1 = (int) $this->h[1]; $h2 = (int) $this->h[2]; $h3 = (int) $this->h[3]; $h4 = (int) $this->h[4]; /** @var int $c */ $c = $h1 >> 26; /** @var int $h1 */ $h1 &= 0x3ffffff; /** @var int $h2 */ $h2 += $c; /** @var int $c */ $c = $h2 >> 26; /** @var int $h2 */ $h2 &= 0x3ffffff; $h3 += $c; /** @var int $c */ $c = $h3 >> 26; $h3 &= 0x3ffffff; $h4 += $c; /** @var int $c */ $c = $h4 >> 26; $h4 &= 0x3ffffff; /** @var int $h0 */ $h0 += self::mul($c, 5, 3); /** @var int $c */ $c = $h0 >> 26; /** @var int $h0 */ $h0 &= 0x3ffffff; /** @var int $h1 */ $h1 += $c; /* compute h + -p */ /** @var int $g0 */ $g0 = $h0 + 5; /** @var int $c */ $c = $g0 >> 26; /** @var int $g0 */ $g0 &= 0x3ffffff; /** @var int $g1 */ $g1 = $h1 + $c; /** @var int $c */ $c = $g1 >> 26; $g1 &= 0x3ffffff; /** @var int $g2 */ $g2 = $h2 + $c; /** @var int $c */ $c = $g2 >> 26; /** @var int $g2 */ $g2 &= 0x3ffffff; /** @var int $g3 */ $g3 = $h3 + $c; /** @var int $c */ $c = $g3 >> 26; /** @var int $g3 */ $g3 &= 0x3ffffff; /** @var int $g4 */ $g4 = ($h4 + $c - (1 << 26)) & 0xffffffff; /* select h if h < p, or h + -p if h >= p */ /** @var int $mask */ $mask = ($g4 >> 31) - 1; $g0 &= $mask; $g1 &= $mask; $g2 &= $mask; $g3 &= $mask; $g4 &= $mask; /** @var int $mask */ $mask = ~$mask & 0xffffffff; /** @var int $h0 */ $h0 = ($h0 & $mask) | $g0; /** @var int $h1 */ $h1 = ($h1 & $mask) | $g1; /** @var int $h2 */ $h2 = ($h2 & $mask) | $g2; /** @var int $h3 */ $h3 = ($h3 & $mask) | $g3; /** @var int $h4 */ $h4 = ($h4 & $mask) | $g4; /* h = h % (2^128) */ /** @var int $h0 */ $h0 = (($h0) | ($h1 << 26)) & 0xffffffff; /** @var int $h1 */ $h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff; /** @var int $h2 */ $h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff; /** @var int $h3 */ $h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff; /* mac = (h + pad) % (2^128) */ $f = (int) ($h0 + $this->pad[0]); $h0 = (int) $f; $f = (int) ($h1 + $this->pad[1] + ($f >> 32)); $h1 = (int) $f; $f = (int) ($h2 + $this->pad[2] + ($f >> 32)); $h2 = (int) $f; $f = (int) ($h3 + $this->pad[3] + ($f >> 32)); $h3 = (int) $f; return self::store32_le($h0 & 0xffffffff) . self::store32_le($h1 & 0xffffffff) . self::store32_le($h2 & 0xffffffff) . self::store32_le($h3 & 0xffffffff); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519.php���������������������������������������������������������������������������������0000644�����������������00000426446�15021200076�0007650 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519 * * Implements Curve25519 core functions * * Based on the ref10 curve25519 code provided by libsodium * * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c */ abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Curve25519_H { /** * Get a field element of size 10 with a value of 0 * * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_0() { return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ); } /** * Get a field element of size 10 with a value of 1 * * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_1() { return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0) ); } /** * Add two field elements. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @param ParagonIE_Sodium_Core_Curve25519_Fe $g * @return ParagonIE_Sodium_Core_Curve25519_Fe * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand */ public static function fe_add( ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g ) { /** @var array<int, int> $arr */ $arr = array(); for ($i = 0; $i < 10; ++$i) { $arr[$i] = (int) ($f[$i] + $g[$i]); } return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr); } /** * Constant-time conditional move. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @param ParagonIE_Sodium_Core_Curve25519_Fe $g * @param int $b * @return ParagonIE_Sodium_Core_Curve25519_Fe * @psalm-suppress MixedAssignment */ public static function fe_cmov( ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g, $b = 0 ) { /** @var array<int, int> $h */ $h = array(); $b *= -1; for ($i = 0; $i < 10; ++$i) { $x = (($f[$i] ^ $g[$i]) & $b); $h[$i] = ($f[$i]) ^ $x; } return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); } /** * Create a copy of a field element. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $h = clone $f; return $h; } /** * Give: 32-byte string. * Receive: A field element object to use for internal calculations. * * @internal You should not use this directly from another application * * @param string $s * @return ParagonIE_Sodium_Core_Curve25519_Fe * @throws RangeException * @throws TypeError */ public static function fe_frombytes($s) { if (self::strlen($s) !== 32) { throw new RangeException('Expected a 32-byte string.'); } $h0 = self::load_4($s); $h1 = self::load_3(self::substr($s, 4, 3)) << 6; $h2 = self::load_3(self::substr($s, 7, 3)) << 5; $h3 = self::load_3(self::substr($s, 10, 3)) << 3; $h4 = self::load_3(self::substr($s, 13, 3)) << 2; $h5 = self::load_4(self::substr($s, 16, 4)); $h6 = self::load_3(self::substr($s, 20, 3)) << 7; $h7 = self::load_3(self::substr($s, 23, 3)) << 5; $h8 = self::load_3(self::substr($s, 26, 3)) << 4; $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2; $carry9 = ($h9 + (1 << 24)) >> 25; $h0 += self::mul($carry9, 19, 5); $h9 -= $carry9 << 25; $carry1 = ($h1 + (1 << 24)) >> 25; $h2 += $carry1; $h1 -= $carry1 << 25; $carry3 = ($h3 + (1 << 24)) >> 25; $h4 += $carry3; $h3 -= $carry3 << 25; $carry5 = ($h5 + (1 << 24)) >> 25; $h6 += $carry5; $h5 -= $carry5 << 25; $carry7 = ($h7 + (1 << 24)) >> 25; $h8 += $carry7; $h7 -= $carry7 << 25; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; $carry2 = ($h2 + (1 << 25)) >> 26; $h3 += $carry2; $h2 -= $carry2 << 26; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry6 = ($h6 + (1 << 25)) >> 26; $h7 += $carry6; $h6 -= $carry6 << 26; $carry8 = ($h8 + (1 << 25)) >> 26; $h9 += $carry8; $h8 -= $carry8 << 26; return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array( (int) $h0, (int) $h1, (int) $h2, (int) $h3, (int) $h4, (int) $h5, (int) $h6, (int) $h7, (int) $h8, (int) $h9 ) ); } /** * Convert a field element to a byte string. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $h * @return string */ public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h) { $h0 = (int) $h[0]; $h1 = (int) $h[1]; $h2 = (int) $h[2]; $h3 = (int) $h[3]; $h4 = (int) $h[4]; $h5 = (int) $h[5]; $h6 = (int) $h[6]; $h7 = (int) $h[7]; $h8 = (int) $h[8]; $h9 = (int) $h[9]; $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25; $q = ($h0 + $q) >> 26; $q = ($h1 + $q) >> 25; $q = ($h2 + $q) >> 26; $q = ($h3 + $q) >> 25; $q = ($h4 + $q) >> 26; $q = ($h5 + $q) >> 25; $q = ($h6 + $q) >> 26; $q = ($h7 + $q) >> 25; $q = ($h8 + $q) >> 26; $q = ($h9 + $q) >> 25; $h0 += self::mul($q, 19, 5); $carry0 = $h0 >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; $carry1 = $h1 >> 25; $h2 += $carry1; $h1 -= $carry1 << 25; $carry2 = $h2 >> 26; $h3 += $carry2; $h2 -= $carry2 << 26; $carry3 = $h3 >> 25; $h4 += $carry3; $h3 -= $carry3 << 25; $carry4 = $h4 >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry5 = $h5 >> 25; $h6 += $carry5; $h5 -= $carry5 << 25; $carry6 = $h6 >> 26; $h7 += $carry6; $h6 -= $carry6 << 26; $carry7 = $h7 >> 25; $h8 += $carry7; $h7 -= $carry7 << 25; $carry8 = $h8 >> 26; $h9 += $carry8; $h8 -= $carry8 << 26; $carry9 = $h9 >> 25; $h9 -= $carry9 << 25; /** * @var array<int, int> */ $s = array( (int) (($h0 >> 0) & 0xff), (int) (($h0 >> 8) & 0xff), (int) (($h0 >> 16) & 0xff), (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff), (int) (($h1 >> 6) & 0xff), (int) (($h1 >> 14) & 0xff), (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff), (int) (($h2 >> 5) & 0xff), (int) (($h2 >> 13) & 0xff), (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff), (int) (($h3 >> 3) & 0xff), (int) (($h3 >> 11) & 0xff), (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff), (int) (($h4 >> 2) & 0xff), (int) (($h4 >> 10) & 0xff), (int) (($h4 >> 18) & 0xff), (int) (($h5 >> 0) & 0xff), (int) (($h5 >> 8) & 0xff), (int) (($h5 >> 16) & 0xff), (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff), (int) (($h6 >> 7) & 0xff), (int) (($h6 >> 15) & 0xff), (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff), (int) (($h7 >> 5) & 0xff), (int) (($h7 >> 13) & 0xff), (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff), (int) (($h8 >> 4) & 0xff), (int) (($h8 >> 12) & 0xff), (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff), (int) (($h9 >> 2) & 0xff), (int) (($h9 >> 10) & 0xff), (int) (($h9 >> 18) & 0xff) ); return self::intArrayToString($s); } /** * Is a field element negative? (1 = yes, 0 = no. Used in calculations.) * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return int * @throws SodiumException * @throws TypeError */ public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $str = self::fe_tobytes($f); return (int) (self::chrToInt($str[0]) & 1); } /** * Returns 0 if this field element results in all NUL bytes. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return bool * @throws SodiumException * @throws TypeError */ public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f) { static $zero; if ($zero === null) { $zero = str_repeat("\x00", 32); } /** @var string $zero */ /** @var string $str */ $str = self::fe_tobytes($f); return !self::verify_32($str, (string) $zero); } /** * Multiply two field elements * * h = f * g * * @internal You should not use this directly from another application * * @security Is multiplication a source of timing leaks? If so, can we do * anything to prevent that from happening? * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @param ParagonIE_Sodium_Core_Curve25519_Fe $g * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_mul( ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g ) { // Ensure limbs aren't oversized. $f = self::fe_normalize($f); $g = self::fe_normalize($g); $f0 = $f[0]; $f1 = $f[1]; $f2 = $f[2]; $f3 = $f[3]; $f4 = $f[4]; $f5 = $f[5]; $f6 = $f[6]; $f7 = $f[7]; $f8 = $f[8]; $f9 = $f[9]; $g0 = $g[0]; $g1 = $g[1]; $g2 = $g[2]; $g3 = $g[3]; $g4 = $g[4]; $g5 = $g[5]; $g6 = $g[6]; $g7 = $g[7]; $g8 = $g[8]; $g9 = $g[9]; $g1_19 = self::mul($g1, 19, 5); $g2_19 = self::mul($g2, 19, 5); $g3_19 = self::mul($g3, 19, 5); $g4_19 = self::mul($g4, 19, 5); $g5_19 = self::mul($g5, 19, 5); $g6_19 = self::mul($g6, 19, 5); $g7_19 = self::mul($g7, 19, 5); $g8_19 = self::mul($g8, 19, 5); $g9_19 = self::mul($g9, 19, 5); $f1_2 = $f1 << 1; $f3_2 = $f3 << 1; $f5_2 = $f5 << 1; $f7_2 = $f7 << 1; $f9_2 = $f9 << 1; $f0g0 = self::mul($f0, $g0, 26); $f0g1 = self::mul($f0, $g1, 25); $f0g2 = self::mul($f0, $g2, 26); $f0g3 = self::mul($f0, $g3, 25); $f0g4 = self::mul($f0, $g4, 26); $f0g5 = self::mul($f0, $g5, 25); $f0g6 = self::mul($f0, $g6, 26); $f0g7 = self::mul($f0, $g7, 25); $f0g8 = self::mul($f0, $g8, 26); $f0g9 = self::mul($f0, $g9, 26); $f1g0 = self::mul($f1, $g0, 26); $f1g1_2 = self::mul($f1_2, $g1, 25); $f1g2 = self::mul($f1, $g2, 26); $f1g3_2 = self::mul($f1_2, $g3, 25); $f1g4 = self::mul($f1, $g4, 26); $f1g5_2 = self::mul($f1_2, $g5, 25); $f1g6 = self::mul($f1, $g6, 26); $f1g7_2 = self::mul($f1_2, $g7, 25); $f1g8 = self::mul($f1, $g8, 26); $f1g9_38 = self::mul($g9_19, $f1_2, 26); $f2g0 = self::mul($f2, $g0, 26); $f2g1 = self::mul($f2, $g1, 25); $f2g2 = self::mul($f2, $g2, 26); $f2g3 = self::mul($f2, $g3, 25); $f2g4 = self::mul($f2, $g4, 26); $f2g5 = self::mul($f2, $g5, 25); $f2g6 = self::mul($f2, $g6, 26); $f2g7 = self::mul($f2, $g7, 25); $f2g8_19 = self::mul($g8_19, $f2, 26); $f2g9_19 = self::mul($g9_19, $f2, 26); $f3g0 = self::mul($f3, $g0, 26); $f3g1_2 = self::mul($f3_2, $g1, 25); $f3g2 = self::mul($f3, $g2, 26); $f3g3_2 = self::mul($f3_2, $g3, 25); $f3g4 = self::mul($f3, $g4, 26); $f3g5_2 = self::mul($f3_2, $g5, 25); $f3g6 = self::mul($f3, $g6, 26); $f3g7_38 = self::mul($g7_19, $f3_2, 26); $f3g8_19 = self::mul($g8_19, $f3, 25); $f3g9_38 = self::mul($g9_19, $f3_2, 26); $f4g0 = self::mul($f4, $g0, 26); $f4g1 = self::mul($f4, $g1, 25); $f4g2 = self::mul($f4, $g2, 26); $f4g3 = self::mul($f4, $g3, 25); $f4g4 = self::mul($f4, $g4, 26); $f4g5 = self::mul($f4, $g5, 25); $f4g6_19 = self::mul($g6_19, $f4, 26); $f4g7_19 = self::mul($g7_19, $f4, 26); $f4g8_19 = self::mul($g8_19, $f4, 26); $f4g9_19 = self::mul($g9_19, $f4, 26); $f5g0 = self::mul($f5, $g0, 26); $f5g1_2 = self::mul($f5_2, $g1, 25); $f5g2 = self::mul($f5, $g2, 26); $f5g3_2 = self::mul($f5_2, $g3, 25); $f5g4 = self::mul($f5, $g4, 26); $f5g5_38 = self::mul($g5_19, $f5_2, 26); $f5g6_19 = self::mul($g6_19, $f5, 25); $f5g7_38 = self::mul($g7_19, $f5_2, 26); $f5g8_19 = self::mul($g8_19, $f5, 25); $f5g9_38 = self::mul($g9_19, $f5_2, 26); $f6g0 = self::mul($f6, $g0, 26); $f6g1 = self::mul($f6, $g1, 25); $f6g2 = self::mul($f6, $g2, 26); $f6g3 = self::mul($f6, $g3, 25); $f6g4_19 = self::mul($g4_19, $f6, 26); $f6g5_19 = self::mul($g5_19, $f6, 26); $f6g6_19 = self::mul($g6_19, $f6, 26); $f6g7_19 = self::mul($g7_19, $f6, 26); $f6g8_19 = self::mul($g8_19, $f6, 26); $f6g9_19 = self::mul($g9_19, $f6, 26); $f7g0 = self::mul($f7, $g0, 26); $f7g1_2 = self::mul($f7_2, $g1, 25); $f7g2 = self::mul($f7, $g2, 26); $f7g3_38 = self::mul($g3_19, $f7_2, 26); $f7g4_19 = self::mul($g4_19, $f7, 26); $f7g5_38 = self::mul($g5_19, $f7_2, 26); $f7g6_19 = self::mul($g6_19, $f7, 25); $f7g7_38 = self::mul($g7_19, $f7_2, 26); $f7g8_19 = self::mul($g8_19, $f7, 25); $f7g9_38 = self::mul($g9_19,$f7_2, 26); $f8g0 = self::mul($f8, $g0, 26); $f8g1 = self::mul($f8, $g1, 25); $f8g2_19 = self::mul($g2_19, $f8, 26); $f8g3_19 = self::mul($g3_19, $f8, 26); $f8g4_19 = self::mul($g4_19, $f8, 26); $f8g5_19 = self::mul($g5_19, $f8, 26); $f8g6_19 = self::mul($g6_19, $f8, 26); $f8g7_19 = self::mul($g7_19, $f8, 26); $f8g8_19 = self::mul($g8_19, $f8, 26); $f8g9_19 = self::mul($g9_19, $f8, 26); $f9g0 = self::mul($f9, $g0, 26); $f9g1_38 = self::mul($g1_19, $f9_2, 26); $f9g2_19 = self::mul($g2_19, $f9, 25); $f9g3_38 = self::mul($g3_19, $f9_2, 26); $f9g4_19 = self::mul($g4_19, $f9, 25); $f9g5_38 = self::mul($g5_19, $f9_2, 26); $f9g6_19 = self::mul($g6_19, $f9, 25); $f9g7_38 = self::mul($g7_19, $f9_2, 26); $f9g8_19 = self::mul($g8_19, $f9, 25); $f9g9_38 = self::mul($g9_19, $f9_2, 26); $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38; $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19; $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38; $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19; $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38; $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19; $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38; $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19; $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38; $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry1 = ($h1 + (1 << 24)) >> 25; $h2 += $carry1; $h1 -= $carry1 << 25; $carry5 = ($h5 + (1 << 24)) >> 25; $h6 += $carry5; $h5 -= $carry5 << 25; $carry2 = ($h2 + (1 << 25)) >> 26; $h3 += $carry2; $h2 -= $carry2 << 26; $carry6 = ($h6 + (1 << 25)) >> 26; $h7 += $carry6; $h6 -= $carry6 << 26; $carry3 = ($h3 + (1 << 24)) >> 25; $h4 += $carry3; $h3 -= $carry3 << 25; $carry7 = ($h7 + (1 << 24)) >> 25; $h8 += $carry7; $h7 -= $carry7 << 25; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry8 = ($h8 + (1 << 25)) >> 26; $h9 += $carry8; $h8 -= $carry8 << 26; $carry9 = ($h9 + (1 << 24)) >> 25; $h0 += self::mul($carry9, 19, 5); $h9 -= $carry9 << 25; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; return self::fe_normalize( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array( (int) $h0, (int) $h1, (int) $h2, (int) $h3, (int) $h4, (int) $h5, (int) $h6, (int) $h7, (int) $h8, (int) $h9 ) ) ); } /** * Get the negative values for each piece of the field element. * * h = -f * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe * @psalm-suppress MixedAssignment */ public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $h = new ParagonIE_Sodium_Core_Curve25519_Fe(); for ($i = 0; $i < 10; ++$i) { $h[$i] = -$f[$i]; } return self::fe_normalize($h); } /** * Square a field element * * h = f * f * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $f = self::fe_normalize($f); $f0 = (int) $f[0]; $f1 = (int) $f[1]; $f2 = (int) $f[2]; $f3 = (int) $f[3]; $f4 = (int) $f[4]; $f5 = (int) $f[5]; $f6 = (int) $f[6]; $f7 = (int) $f[7]; $f8 = (int) $f[8]; $f9 = (int) $f[9]; $f0_2 = $f0 << 1; $f1_2 = $f1 << 1; $f2_2 = $f2 << 1; $f3_2 = $f3 << 1; $f4_2 = $f4 << 1; $f5_2 = $f5 << 1; $f6_2 = $f6 << 1; $f7_2 = $f7 << 1; $f5_38 = self::mul($f5, 38, 6); $f6_19 = self::mul($f6, 19, 5); $f7_38 = self::mul($f7, 38, 6); $f8_19 = self::mul($f8, 19, 5); $f9_38 = self::mul($f9, 38, 6); $f0f0 = self::mul($f0, $f0, 26); $f0f1_2 = self::mul($f0_2, $f1, 26); $f0f2_2 = self::mul($f0_2, $f2, 26); $f0f3_2 = self::mul($f0_2, $f3, 26); $f0f4_2 = self::mul($f0_2, $f4, 26); $f0f5_2 = self::mul($f0_2, $f5, 26); $f0f6_2 = self::mul($f0_2, $f6, 26); $f0f7_2 = self::mul($f0_2, $f7, 26); $f0f8_2 = self::mul($f0_2, $f8, 26); $f0f9_2 = self::mul($f0_2, $f9, 26); $f1f1_2 = self::mul($f1_2, $f1, 26); $f1f2_2 = self::mul($f1_2, $f2, 26); $f1f3_4 = self::mul($f1_2, $f3_2, 26); $f1f4_2 = self::mul($f1_2, $f4, 26); $f1f5_4 = self::mul($f1_2, $f5_2, 26); $f1f6_2 = self::mul($f1_2, $f6, 26); $f1f7_4 = self::mul($f1_2, $f7_2, 26); $f1f8_2 = self::mul($f1_2, $f8, 26); $f1f9_76 = self::mul($f9_38, $f1_2, 27); $f2f2 = self::mul($f2, $f2, 27); $f2f3_2 = self::mul($f2_2, $f3, 27); $f2f4_2 = self::mul($f2_2, $f4, 27); $f2f5_2 = self::mul($f2_2, $f5, 27); $f2f6_2 = self::mul($f2_2, $f6, 27); $f2f7_2 = self::mul($f2_2, $f7, 27); $f2f8_38 = self::mul($f8_19, $f2_2, 27); $f2f9_38 = self::mul($f9_38, $f2, 26); $f3f3_2 = self::mul($f3_2, $f3, 26); $f3f4_2 = self::mul($f3_2, $f4, 26); $f3f5_4 = self::mul($f3_2, $f5_2, 26); $f3f6_2 = self::mul($f3_2, $f6, 26); $f3f7_76 = self::mul($f7_38, $f3_2, 26); $f3f8_38 = self::mul($f8_19, $f3_2, 26); $f3f9_76 = self::mul($f9_38, $f3_2, 26); $f4f4 = self::mul($f4, $f4, 26); $f4f5_2 = self::mul($f4_2, $f5, 26); $f4f6_38 = self::mul($f6_19, $f4_2, 27); $f4f7_38 = self::mul($f7_38, $f4, 26); $f4f8_38 = self::mul($f8_19, $f4_2, 27); $f4f9_38 = self::mul($f9_38, $f4, 26); $f5f5_38 = self::mul($f5_38, $f5, 26); $f5f6_38 = self::mul($f6_19, $f5_2, 26); $f5f7_76 = self::mul($f7_38, $f5_2, 26); $f5f8_38 = self::mul($f8_19, $f5_2, 26); $f5f9_76 = self::mul($f9_38, $f5_2, 26); $f6f6_19 = self::mul($f6_19, $f6, 26); $f6f7_38 = self::mul($f7_38, $f6, 26); $f6f8_38 = self::mul($f8_19, $f6_2, 27); $f6f9_38 = self::mul($f9_38, $f6, 26); $f7f7_38 = self::mul($f7_38, $f7, 26); $f7f8_38 = self::mul($f8_19, $f7_2, 26); $f7f9_76 = self::mul($f9_38, $f7_2, 26); $f8f8_19 = self::mul($f8_19, $f8, 26); $f8f9_38 = self::mul($f9_38, $f8, 26); $f9f9_38 = self::mul($f9_38, $f9, 26); $h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38; $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38; $h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19; $h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38; $h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38; $h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38; $h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19; $h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38; $h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38; $h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry1 = ($h1 + (1 << 24)) >> 25; $h2 += $carry1; $h1 -= $carry1 << 25; $carry5 = ($h5 + (1 << 24)) >> 25; $h6 += $carry5; $h5 -= $carry5 << 25; $carry2 = ($h2 + (1 << 25)) >> 26; $h3 += $carry2; $h2 -= $carry2 << 26; $carry6 = ($h6 + (1 << 25)) >> 26; $h7 += $carry6; $h6 -= $carry6 << 26; $carry3 = ($h3 + (1 << 24)) >> 25; $h4 += $carry3; $h3 -= $carry3 << 25; $carry7 = ($h7 + (1 << 24)) >> 25; $h8 += $carry7; $h7 -= $carry7 << 25; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry8 = ($h8 + (1 << 25)) >> 26; $h9 += $carry8; $h8 -= $carry8 << 26; $carry9 = ($h9 + (1 << 24)) >> 25; $h0 += self::mul($carry9, 19, 5); $h9 -= $carry9 << 25; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; return self::fe_normalize( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array( (int) $h0, (int) $h1, (int) $h2, (int) $h3, (int) $h4, (int) $h5, (int) $h6, (int) $h7, (int) $h8, (int) $h9 ) ) ); } /** * Square and double a field element * * h = 2 * f * f * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $f = self::fe_normalize($f); $f0 = (int) $f[0]; $f1 = (int) $f[1]; $f2 = (int) $f[2]; $f3 = (int) $f[3]; $f4 = (int) $f[4]; $f5 = (int) $f[5]; $f6 = (int) $f[6]; $f7 = (int) $f[7]; $f8 = (int) $f[8]; $f9 = (int) $f[9]; $f0_2 = $f0 << 1; $f1_2 = $f1 << 1; $f2_2 = $f2 << 1; $f3_2 = $f3 << 1; $f4_2 = $f4 << 1; $f5_2 = $f5 << 1; $f6_2 = $f6 << 1; $f7_2 = $f7 << 1; $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */ $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */ $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */ $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */ $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */ $f0f0 = self::mul($f0, $f0, 24); $f0f1_2 = self::mul($f0_2, $f1, 24); $f0f2_2 = self::mul($f0_2, $f2, 24); $f0f3_2 = self::mul($f0_2, $f3, 24); $f0f4_2 = self::mul($f0_2, $f4, 24); $f0f5_2 = self::mul($f0_2, $f5, 24); $f0f6_2 = self::mul($f0_2, $f6, 24); $f0f7_2 = self::mul($f0_2, $f7, 24); $f0f8_2 = self::mul($f0_2, $f8, 24); $f0f9_2 = self::mul($f0_2, $f9, 24); $f1f1_2 = self::mul($f1_2, $f1, 24); $f1f2_2 = self::mul($f1_2, $f2, 24); $f1f3_4 = self::mul($f1_2, $f3_2, 24); $f1f4_2 = self::mul($f1_2, $f4, 24); $f1f5_4 = self::mul($f1_2, $f5_2, 24); $f1f6_2 = self::mul($f1_2, $f6, 24); $f1f7_4 = self::mul($f1_2, $f7_2, 24); $f1f8_2 = self::mul($f1_2, $f8, 24); $f1f9_76 = self::mul($f9_38, $f1_2, 24); $f2f2 = self::mul($f2, $f2, 24); $f2f3_2 = self::mul($f2_2, $f3, 24); $f2f4_2 = self::mul($f2_2, $f4, 24); $f2f5_2 = self::mul($f2_2, $f5, 24); $f2f6_2 = self::mul($f2_2, $f6, 24); $f2f7_2 = self::mul($f2_2, $f7, 24); $f2f8_38 = self::mul($f8_19, $f2_2, 25); $f2f9_38 = self::mul($f9_38, $f2, 24); $f3f3_2 = self::mul($f3_2, $f3, 24); $f3f4_2 = self::mul($f3_2, $f4, 24); $f3f5_4 = self::mul($f3_2, $f5_2, 24); $f3f6_2 = self::mul($f3_2, $f6, 24); $f3f7_76 = self::mul($f7_38, $f3_2, 24); $f3f8_38 = self::mul($f8_19, $f3_2, 24); $f3f9_76 = self::mul($f9_38, $f3_2, 24); $f4f4 = self::mul($f4, $f4, 24); $f4f5_2 = self::mul($f4_2, $f5, 24); $f4f6_38 = self::mul($f6_19, $f4_2, 25); $f4f7_38 = self::mul($f7_38, $f4, 24); $f4f8_38 = self::mul($f8_19, $f4_2, 25); $f4f9_38 = self::mul($f9_38, $f4, 24); $f5f5_38 = self::mul($f5_38, $f5, 24); $f5f6_38 = self::mul($f6_19, $f5_2, 24); $f5f7_76 = self::mul($f7_38, $f5_2, 24); $f5f8_38 = self::mul($f8_19, $f5_2, 24); $f5f9_76 = self::mul($f9_38, $f5_2, 24); $f6f6_19 = self::mul($f6_19, $f6, 24); $f6f7_38 = self::mul($f7_38, $f6, 24); $f6f8_38 = self::mul($f8_19, $f6_2, 25); $f6f9_38 = self::mul($f9_38, $f6, 24); $f7f7_38 = self::mul($f7_38, $f7, 24); $f7f8_38 = self::mul($f8_19, $f7_2, 24); $f7f9_76 = self::mul($f9_38, $f7_2, 24); $f8f8_19 = self::mul($f8_19, $f8, 24); $f8f9_38 = self::mul($f9_38, $f8, 24); $f9f9_38 = self::mul($f9_38, $f9, 24); $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1; $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1; $h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1; $h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1; $h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1; $h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38) << 1; $h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19) << 1; $h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38) << 1; $h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38) << 1; $h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2) << 1; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry1 = ($h1 + (1 << 24)) >> 25; $h2 += $carry1; $h1 -= $carry1 << 25; $carry5 = ($h5 + (1 << 24)) >> 25; $h6 += $carry5; $h5 -= $carry5 << 25; $carry2 = ($h2 + (1 << 25)) >> 26; $h3 += $carry2; $h2 -= $carry2 << 26; $carry6 = ($h6 + (1 << 25)) >> 26; $h7 += $carry6; $h6 -= $carry6 << 26; $carry3 = ($h3 + (1 << 24)) >> 25; $h4 += $carry3; $h3 -= $carry3 << 25; $carry7 = ($h7 + (1 << 24)) >> 25; $h8 += $carry7; $h7 -= $carry7 << 25; $carry4 = ($h4 + (1 << 25)) >> 26; $h5 += $carry4; $h4 -= $carry4 << 26; $carry8 = ($h8 + (1 << 25)) >> 26; $h9 += $carry8; $h8 -= $carry8 << 26; $carry9 = ($h9 + (1 << 24)) >> 25; $h0 += self::mul($carry9, 19, 5); $h9 -= $carry9 << 25; $carry0 = ($h0 + (1 << 25)) >> 26; $h1 += $carry0; $h0 -= $carry0 << 26; return self::fe_normalize( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array( (int) $h0, (int) $h1, (int) $h2, (int) $h3, (int) $h4, (int) $h5, (int) $h6, (int) $h7, (int) $h8, (int) $h9 ) ) ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z) { $z = clone $Z; $t0 = self::fe_sq($z); $t1 = self::fe_sq($t0); $t1 = self::fe_sq($t1); $t1 = self::fe_mul($z, $t1); $t0 = self::fe_mul($t0, $t1); $t2 = self::fe_sq($t0); $t1 = self::fe_mul($t1, $t2); $t2 = self::fe_sq($t1); for ($i = 1; $i < 5; ++$i) { $t2 = self::fe_sq($t2); } $t1 = self::fe_mul($t2, $t1); $t2 = self::fe_sq($t1); for ($i = 1; $i < 10; ++$i) { $t2 = self::fe_sq($t2); } $t2 = self::fe_mul($t2, $t1); $t3 = self::fe_sq($t2); for ($i = 1; $i < 20; ++$i) { $t3 = self::fe_sq($t3); } $t2 = self::fe_mul($t3, $t2); $t2 = self::fe_sq($t2); for ($i = 1; $i < 10; ++$i) { $t2 = self::fe_sq($t2); } $t1 = self::fe_mul($t2, $t1); $t2 = self::fe_sq($t1); for ($i = 1; $i < 50; ++$i) { $t2 = self::fe_sq($t2); } $t2 = self::fe_mul($t2, $t1); $t3 = self::fe_sq($t2); for ($i = 1; $i < 100; ++$i) { $t3 = self::fe_sq($t3); } $t2 = self::fe_mul($t3, $t2); $t2 = self::fe_sq($t2); for ($i = 1; $i < 50; ++$i) { $t2 = self::fe_sq($t2); } $t1 = self::fe_mul($t2, $t1); $t1 = self::fe_sq($t1); for ($i = 1; $i < 5; ++$i) { $t1 = self::fe_sq($t1); } return self::fe_mul($t1, $t0); } /** * @internal You should not use this directly from another application * * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106 * * @param ParagonIE_Sodium_Core_Curve25519_Fe $z * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z) { $z = self::fe_normalize($z); # fe_sq(t0, z); # fe_sq(t1, t0); # fe_sq(t1, t1); # fe_mul(t1, z, t1); # fe_mul(t0, t0, t1); # fe_sq(t0, t0); # fe_mul(t0, t1, t0); # fe_sq(t1, t0); $t0 = self::fe_sq($z); $t1 = self::fe_sq($t0); $t1 = self::fe_sq($t1); $t1 = self::fe_mul($z, $t1); $t0 = self::fe_mul($t0, $t1); $t0 = self::fe_sq($t0); $t0 = self::fe_mul($t1, $t0); $t1 = self::fe_sq($t0); # for (i = 1; i < 5; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 5; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t0, t1, t0); # fe_sq(t1, t0); $t0 = self::fe_mul($t1, $t0); $t1 = self::fe_sq($t0); # for (i = 1; i < 10; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 10; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t1, t1, t0); # fe_sq(t2, t1); $t1 = self::fe_mul($t1, $t0); $t2 = self::fe_sq($t1); # for (i = 1; i < 20; ++i) { # fe_sq(t2, t2); # } for ($i = 1; $i < 20; ++$i) { $t2 = self::fe_sq($t2); } # fe_mul(t1, t2, t1); # fe_sq(t1, t1); $t1 = self::fe_mul($t2, $t1); $t1 = self::fe_sq($t1); # for (i = 1; i < 10; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 10; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t0, t1, t0); # fe_sq(t1, t0); $t0 = self::fe_mul($t1, $t0); $t1 = self::fe_sq($t0); # for (i = 1; i < 50; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 50; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t1, t1, t0); # fe_sq(t2, t1); $t1 = self::fe_mul($t1, $t0); $t2 = self::fe_sq($t1); # for (i = 1; i < 100; ++i) { # fe_sq(t2, t2); # } for ($i = 1; $i < 100; ++$i) { $t2 = self::fe_sq($t2); } # fe_mul(t1, t2, t1); # fe_sq(t1, t1); $t1 = self::fe_mul($t2, $t1); $t1 = self::fe_sq($t1); # for (i = 1; i < 50; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 50; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t0, t1, t0); # fe_sq(t0, t0); # fe_sq(t0, t0); # fe_mul(out, t0, z); $t0 = self::fe_mul($t1, $t0); $t0 = self::fe_sq($t0); $t0 = self::fe_sq($t0); return self::fe_mul($t0, $z); } /** * Subtract two field elements. * * h = f - g * * Preconditions: * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * * Postconditions: * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @param ParagonIE_Sodium_Core_Curve25519_Fe $g * @return ParagonIE_Sodium_Core_Curve25519_Fe * @psalm-suppress MixedOperand */ public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g) { return self::fe_normalize( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( array( (int) ($f[0] - $g[0]), (int) ($f[1] - $g[1]), (int) ($f[2] - $g[2]), (int) ($f[3] - $g[3]), (int) ($f[4] - $g[4]), (int) ($f[5] - $g[5]), (int) ($f[6] - $g[6]), (int) ($f[7] - $g[7]), (int) ($f[8] - $g[8]), (int) ($f[9] - $g[9]) ) ) ); } /** * Add two group elements. * * r = p + q * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ public static function ge_add( ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q ) { $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->YplusX); $r->Y = self::fe_mul($r->Y, $q->YminusX); $r->T = self::fe_mul($q->T2d, $p->T); $r->X = self::fe_mul($p->Z, $q->Z); $t0 = self::fe_add($r->X, $r->X); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_add($t0, $r->T); $r->T = self::fe_sub($t0, $r->T); return $r; } /** * @internal You should not use this directly from another application * * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215 * @param string $a * @return array<int, mixed> * @throws SodiumException * @throws TypeError */ public static function slide($a) { if (self::strlen($a) < 256) { if (self::strlen($a) < 16) { $a = str_pad($a, 256, '0', STR_PAD_RIGHT); } } /** @var array<int, int> $r */ $r = array(); /** @var int $i */ for ($i = 0; $i < 256; ++$i) { $r[$i] = (int) ( 1 & ( self::chrToInt($a[(int) ($i >> 3)]) >> ($i & 7) ) ); } for ($i = 0;$i < 256;++$i) { if ($r[$i]) { for ($b = 1;$b <= 6 && $i + $b < 256;++$b) { if ($r[$i + $b]) { if ($r[$i] + ($r[$i + $b] << $b) <= 15) { $r[$i] += $r[$i + $b] << $b; $r[$i + $b] = 0; } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) { $r[$i] -= $r[$i + $b] << $b; for ($k = $i + $b; $k < 256; ++$k) { if (!$r[$k]) { $r[$k] = 1; break; } $r[$k] = 0; } } else { break; } } } } } return $r; } /** * @internal You should not use this directly from another application * * @param string $s * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError */ public static function ge_frombytes_negate_vartime($s) { static $d = null; if (!$d) { $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d); } # fe_frombytes(h->Y,s); # fe_1(h->Z); $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3( self::fe_0(), self::fe_frombytes($s), self::fe_1() ); # fe_sq(u,h->Y); # fe_mul(v,u,d); # fe_sub(u,u,h->Z); /* u = y^2-1 */ # fe_add(v,v,h->Z); /* v = dy^2+1 */ $u = self::fe_sq($h->Y); /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */ $v = self::fe_mul($u, $d); $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */ $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */ # fe_sq(v3,v); # fe_mul(v3,v3,v); /* v3 = v^3 */ # fe_sq(h->X,v3); # fe_mul(h->X,h->X,v); # fe_mul(h->X,h->X,u); /* x = uv^7 */ $v3 = self::fe_sq($v); $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */ $h->X = self::fe_sq($v3); $h->X = self::fe_mul($h->X, $v); $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */ # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ # fe_mul(h->X,h->X,v3); # fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */ $h->X = self::fe_mul($h->X, $v3); $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */ # fe_sq(vxx,h->X); # fe_mul(vxx,vxx,v); # fe_sub(check,vxx,u); /* vx^2-u */ $vxx = self::fe_sq($h->X); $vxx = self::fe_mul($vxx, $v); $check = self::fe_sub($vxx, $u); /* vx^2 - u */ # if (fe_isnonzero(check)) { # fe_add(check,vxx,u); /* vx^2+u */ # if (fe_isnonzero(check)) { # return -1; # } # fe_mul(h->X,h->X,sqrtm1); # } if (self::fe_isnonzero($check)) { $check = self::fe_add($vxx, $u); /* vx^2 + u */ if (self::fe_isnonzero($check)) { throw new RangeException('Internal check failed.'); } $h->X = self::fe_mul( $h->X, ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1) ); } # if (fe_isnegative(h->X) == (s[31] >> 7)) { # fe_neg(h->X,h->X); # } $i = self::chrToInt($s[31]); if (self::fe_isnegative($h->X) === ($i >> 7)) { $h->X = self::fe_neg($h->X); } # fe_mul(h->T,h->X,h->Y); $h->T = self::fe_mul($h->X, $h->Y); return $h; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ public static function ge_madd( ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q ) { $r = clone $R; $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->yplusx); $r->Y = self::fe_mul($r->Y, $q->yminusx); $r->T = self::fe_mul($q->xy2d, $p->T); $t0 = self::fe_add(clone $p->Z, clone $p->Z); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_add($t0, $r->T); $r->T = self::fe_sub($t0, $r->T); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ public static function ge_msub( ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q ) { $r = clone $R; $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->yminusx); $r->Y = self::fe_mul($r->Y, $q->yplusx); $r->T = self::fe_mul($q->xy2d, $p->T); $t0 = self::fe_add($p->Z, $p->Z); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_sub($t0, $r->T); $r->T = self::fe_add($t0, $r->T); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 */ public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p) { $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2(); $r->X = self::fe_mul($p->X, $p->T); $r->Y = self::fe_mul($p->Y, $p->Z); $r->Z = self::fe_mul($p->Z, $p->T); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 */ public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p) { $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); $r->X = self::fe_mul($p->X, $p->T); $r->Y = self::fe_mul($p->Y, $p->Z); $r->Z = self::fe_mul($p->Z, $p->T); $r->T = self::fe_mul($p->X, $p->Y); return $r; } /** * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 */ public static function ge_p2_0() { return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( self::fe_0(), self::fe_1(), self::fe_1() ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p) { $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); $r->X = self::fe_sq($p->X); $r->Z = self::fe_sq($p->Y); $r->T = self::fe_sq2($p->Z); $r->Y = self::fe_add($p->X, $p->Y); $t0 = self::fe_sq($r->Y); $r->Y = self::fe_add($r->Z, $r->X); $r->Z = self::fe_sub($r->Z, $r->X); $r->X = self::fe_sub($t0, $r->Y); $r->T = self::fe_sub($r->T, $r->Z); return $r; } /** * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 */ public static function ge_p3_0() { return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( self::fe_0(), self::fe_1(), self::fe_1(), self::fe_0() ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached */ public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) { static $d2 = null; if ($d2 === null) { $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2); } /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */ $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); $r->YplusX = self::fe_add($p->Y, $p->X); $r->YminusX = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_copy($p->Z); $r->T2d = self::fe_mul($p->T, $d2); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 */ public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) { return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( self::fe_copy($p->X), self::fe_copy($p->Y), self::fe_copy($p->Z) ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h * @return string * @throws SodiumException * @throws TypeError */ public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h) { $recip = self::fe_invert($h->Z); $x = self::fe_mul($h->X, $recip); $y = self::fe_mul($h->Y, $recip); $s = self::fe_tobytes($y); $s[31] = self::intToChr( self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) ); return $s; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) { $q = self::ge_p3_to_p2($p); return self::ge_p2_dbl($q); } /** * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp */ public static function ge_precomp_0() { return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( self::fe_1(), self::fe_1(), self::fe_0() ); } /** * @internal You should not use this directly from another application * * @param int $b * @param int $c * @return int */ public static function equal($b, $c) { return (int) ((($b ^ $c) - 1) >> 31) & 1; } /** * @internal You should not use this directly from another application * * @param int|string $char * @return int (1 = yes, 0 = no) * @throws SodiumException * @throws TypeError */ public static function negative($char) { if (is_int($char)) { return ($char >> 63) & 1; } $x = self::chrToInt(self::substr($char, 0, 1)); return (int) ($x >> 63); } /** * Conditional move * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u * @param int $b * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp */ public static function cmov( ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u, $b ) { if (!is_int($b)) { throw new InvalidArgumentException('Expected an integer.'); } return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( self::fe_cmov($t->yplusx, $u->yplusx, $b), self::fe_cmov($t->yminusx, $u->yminusx, $b), self::fe_cmov($t->xy2d, $u->xy2d, $b) ); } /** * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u * @param int $b * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached */ public static function ge_cmov_cached( ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t, ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u, $b ) { $b &= 1; $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); $ret->YplusX = self::fe_cmov($t->YplusX, $u->YplusX, $b); $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b); $ret->Z = self::fe_cmov($t->Z, $u->Z, $b); $ret->T2d = self::fe_cmov($t->T2d, $u->T2d, $b); return $ret; } /** * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached * @param int $b * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached * @throws SodiumException */ public static function ge_cmov8_cached(array $cached, $b) { // const unsigned char bnegative = negative(b); // const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1)); $bnegative = self::negative($b); $babs = $b - (((-$bnegative) & $b) << 1); // ge25519_cached_0(t); $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( self::fe_1(), self::fe_1(), self::fe_1(), self::fe_0() ); // ge25519_cmov_cached(t, &cached[0], equal(babs, 1)); // ge25519_cmov_cached(t, &cached[1], equal(babs, 2)); // ge25519_cmov_cached(t, &cached[2], equal(babs, 3)); // ge25519_cmov_cached(t, &cached[3], equal(babs, 4)); // ge25519_cmov_cached(t, &cached[4], equal(babs, 5)); // ge25519_cmov_cached(t, &cached[5], equal(babs, 6)); // ge25519_cmov_cached(t, &cached[6], equal(babs, 7)); // ge25519_cmov_cached(t, &cached[7], equal(babs, 8)); for ($x = 0; $x < 8; ++$x) { $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1)); } // fe25519_copy(minust.YplusX, t->YminusX); // fe25519_copy(minust.YminusX, t->YplusX); // fe25519_copy(minust.Z, t->Z); // fe25519_neg(minust.T2d, t->T2d); $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( self::fe_copy($t->YminusX), self::fe_copy($t->YplusX), self::fe_copy($t->Z), self::fe_neg($t->T2d) ); return self::ge_cmov_cached($t, $minust, $bnegative); } /** * @internal You should not use this directly from another application * * @param int $pos * @param int $b * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayOffset */ public static function ge_select($pos = 0, $b = 0) { static $base = null; if ($base === null) { $base = array(); /** @var int $i */ foreach (self::$base as $i => $bas) { for ($j = 0; $j < 8; ++$j) { $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]), ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]), ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2]) ); } } } /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */ if (!is_int($pos)) { throw new InvalidArgumentException('Position must be an integer'); } if ($pos < 0 || $pos > 31) { throw new RangeException('Position is out of range [0, 31]'); } $bnegative = self::negative($b); $babs = $b - (((-$bnegative) & $b) << 1); $t = self::ge_precomp_0(); for ($i = 0; $i < 8; ++$i) { $t = self::cmov( $t, $base[$pos][$i], self::equal($babs, $i + 1) ); } $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( self::fe_copy($t->yminusx), self::fe_copy($t->yplusx), self::fe_neg($t->xy2d) ); return self::cmov($t, $minusT, $bnegative); } /** * Subtract two group elements. * * r = p - q * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ public static function ge_sub( ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q ) { $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->YminusX); $r->Y = self::fe_mul($r->Y, $q->YplusX); $r->T = self::fe_mul($q->T2d, $p->T); $r->X = self::fe_mul($p->Z, $q->Z); $t0 = self::fe_add($r->X, $r->X); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_sub($t0, $r->T); $r->T = self::fe_add($t0, $r->T); return $r; } /** * Convert a group element to a byte string. * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h * @return string * @throws SodiumException * @throws TypeError */ public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h) { $recip = self::fe_invert($h->Z); $x = self::fe_mul($h->X, $recip); $y = self::fe_mul($h->Y, $recip); $s = self::fe_tobytes($y); $s[31] = self::intToChr( self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) ); return $s; } /** * @internal You should not use this directly from another application * * @param string $a * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A * @param string $b * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess */ public static function ge_double_scalarmult_vartime( $a, ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A, $b ) { /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */ $Ai = array(); /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */ static $Bi = array(); if (!$Bi) { for ($i = 0; $i < 8; ++$i) { $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]), ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]), ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2]) ); } } for ($i = 0; $i < 8; ++$i) { $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( self::fe_0(), self::fe_0(), self::fe_0(), self::fe_0() ); } # slide(aslide,a); # slide(bslide,b); /** @var array<int, int> $aslide */ $aslide = self::slide($a); /** @var array<int, int> $bslide */ $bslide = self::slide($b); # ge_p3_to_cached(&Ai[0],A); # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); $Ai[0] = self::ge_p3_to_cached($A); $t = self::ge_p3_dbl($A); $A2 = self::ge_p1p1_to_p3($t); # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); for ($i = 0; $i < 7; ++$i) { $t = self::ge_add($A2, $Ai[$i]); $u = self::ge_p1p1_to_p3($t); $Ai[$i + 1] = self::ge_p3_to_cached($u); } # ge_p2_0(r); $r = self::ge_p2_0(); # for (i = 255;i >= 0;--i) { # if (aslide[i] || bslide[i]) break; # } $i = 255; for (; $i >= 0; --$i) { if ($aslide[$i] || $bslide[$i]) { break; } } # for (;i >= 0;--i) { for (; $i >= 0; --$i) { # ge_p2_dbl(&t,r); $t = self::ge_p2_dbl($r); # if (aslide[i] > 0) { if ($aslide[$i] > 0) { # ge_p1p1_to_p3(&u,&t); # ge_add(&t,&u,&Ai[aslide[i]/2]); $u = self::ge_p1p1_to_p3($t); $t = self::ge_add( $u, $Ai[(int) floor($aslide[$i] / 2)] ); # } else if (aslide[i] < 0) { } elseif ($aslide[$i] < 0) { # ge_p1p1_to_p3(&u,&t); # ge_sub(&t,&u,&Ai[(-aslide[i])/2]); $u = self::ge_p1p1_to_p3($t); $t = self::ge_sub( $u, $Ai[(int) floor(-$aslide[$i] / 2)] ); } # if (bslide[i] > 0) { if ($bslide[$i] > 0) { /** @var int $index */ $index = (int) floor($bslide[$i] / 2); # ge_p1p1_to_p3(&u,&t); # ge_madd(&t,&u,&Bi[bslide[i]/2]); $u = self::ge_p1p1_to_p3($t); $t = self::ge_madd($t, $u, $Bi[$index]); # } else if (bslide[i] < 0) { } elseif ($bslide[$i] < 0) { /** @var int $index */ $index = (int) floor(-$bslide[$i] / 2); # ge_p1p1_to_p3(&u,&t); # ge_msub(&t,&u,&Bi[(-bslide[i])/2]); $u = self::ge_p1p1_to_p3($t); $t = self::ge_msub($t, $u, $Bi[$index]); } # ge_p1p1_to_p2(r,&t); $r = self::ge_p1p1_to_p2($t); } return $r; } /** * @internal You should not use this directly from another application * * @param string $a * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand */ public static function ge_scalarmult($a, $p) { $e = array_fill(0, 64, 0); /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */ $pi = array(); // ge25519_p3_to_cached(&pi[1 - 1], p); /* p */ $pi[0] = self::ge_p3_to_cached($p); // ge25519_p3_dbl(&t2, p); // ge25519_p1p1_to_p3(&p2, &t2); // ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */ $t2 = self::ge_p3_dbl($p); $p2 = self::ge_p1p1_to_p3($t2); $pi[1] = self::ge_p3_to_cached($p2); // ge25519_add_cached(&t3, p, &pi[2 - 1]); // ge25519_p1p1_to_p3(&p3, &t3); // ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */ $t3 = self::ge_add($p, $pi[1]); $p3 = self::ge_p1p1_to_p3($t3); $pi[2] = self::ge_p3_to_cached($p3); // ge25519_p3_dbl(&t4, &p2); // ge25519_p1p1_to_p3(&p4, &t4); // ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */ $t4 = self::ge_p3_dbl($p2); $p4 = self::ge_p1p1_to_p3($t4); $pi[3] = self::ge_p3_to_cached($p4); // ge25519_add_cached(&t5, p, &pi[4 - 1]); // ge25519_p1p1_to_p3(&p5, &t5); // ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */ $t5 = self::ge_add($p, $pi[3]); $p5 = self::ge_p1p1_to_p3($t5); $pi[4] = self::ge_p3_to_cached($p5); // ge25519_p3_dbl(&t6, &p3); // ge25519_p1p1_to_p3(&p6, &t6); // ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */ $t6 = self::ge_p3_dbl($p3); $p6 = self::ge_p1p1_to_p3($t6); $pi[5] = self::ge_p3_to_cached($p6); // ge25519_add_cached(&t7, p, &pi[6 - 1]); // ge25519_p1p1_to_p3(&p7, &t7); // ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */ $t7 = self::ge_add($p, $pi[5]); $p7 = self::ge_p1p1_to_p3($t7); $pi[6] = self::ge_p3_to_cached($p7); // ge25519_p3_dbl(&t8, &p4); // ge25519_p1p1_to_p3(&p8, &t8); // ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */ $t8 = self::ge_p3_dbl($p4); $p8 = self::ge_p1p1_to_p3($t8); $pi[7] = self::ge_p3_to_cached($p8); // for (i = 0; i < 32; ++i) { // e[2 * i + 0] = (a[i] >> 0) & 15; // e[2 * i + 1] = (a[i] >> 4) & 15; // } for ($i = 0; $i < 32; ++$i) { $e[($i << 1) ] = self::chrToInt($a[$i]) & 15; $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15; } // /* each e[i] is between 0 and 15 */ // /* e[63] is between 0 and 7 */ // carry = 0; // for (i = 0; i < 63; ++i) { // e[i] += carry; // carry = e[i] + 8; // carry >>= 4; // e[i] -= carry * ((signed char) 1 << 4); // } $carry = 0; for ($i = 0; $i < 63; ++$i) { $e[$i] += $carry; $carry = $e[$i] + 8; $carry >>= 4; $e[$i] -= $carry << 4; } // e[63] += carry; // /* each e[i] is between -8 and 8 */ $e[63] += $carry; // ge25519_p3_0(h); $h = self::ge_p3_0(); // for (i = 63; i != 0; i--) { for ($i = 63; $i != 0; --$i) { // ge25519_cmov8_cached(&t, pi, e[i]); $t = self::ge_cmov8_cached($pi, $e[$i]); // ge25519_add_cached(&r, h, &t); $r = self::ge_add($h, $t); // ge25519_p1p1_to_p2(&s, &r); // ge25519_p2_dbl(&r, &s); // ge25519_p1p1_to_p2(&s, &r); // ge25519_p2_dbl(&r, &s); // ge25519_p1p1_to_p2(&s, &r); // ge25519_p2_dbl(&r, &s); // ge25519_p1p1_to_p2(&s, &r); // ge25519_p2_dbl(&r, &s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); // ge25519_p1p1_to_p3(h, &r); /* *16 */ $h = self::ge_p1p1_to_p3($r); /* *16 */ } // ge25519_cmov8_cached(&t, pi, e[i]); // ge25519_add_cached(&r, h, &t); // ge25519_p1p1_to_p3(h, &r); $t = self::ge_cmov8_cached($pi, $e[0]); $r = self::ge_add($h, $t); return self::ge_p1p1_to_p3($r); } /** * @internal You should not use this directly from another application * * @param string $a * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand */ public static function ge_scalarmult_base($a) { /** @var array<int, int> $e */ $e = array(); $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); for ($i = 0; $i < 32; ++$i) { $dbl = (int) $i << 1; $e[$dbl] = (int) self::chrToInt($a[$i]) & 15; $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15; } $carry = 0; for ($i = 0; $i < 63; ++$i) { $e[$i] += $carry; $carry = $e[$i] + 8; $carry >>= 4; $e[$i] -= $carry << 4; } $e[63] += (int) $carry; $h = self::ge_p3_0(); for ($i = 1; $i < 64; $i += 2) { $t = self::ge_select((int) floor($i / 2), (int) $e[$i]); $r = self::ge_madd($r, $h, $t); $h = self::ge_p1p1_to_p3($r); } $r = self::ge_p3_dbl($h); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $h = self::ge_p1p1_to_p3($r); for ($i = 0; $i < 64; $i += 2) { $t = self::ge_select($i >> 1, (int) $e[$i]); $r = self::ge_madd($r, $h, $t); $h = self::ge_p1p1_to_p3($r); } return $h; } /** * Calculates (ab + c) mod l * where l = 2^252 + 27742317777372353535851937790883648493 * * @internal You should not use this directly from another application * * @param string $a * @param string $b * @param string $c * @return string * @throws TypeError */ public static function sc_muladd($a, $b, $c) { $a0 = 2097151 & self::load_3(self::substr($a, 0, 3)); $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5); $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2); $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7); $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4); $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1); $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6); $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3); $a8 = 2097151 & self::load_3(self::substr($a, 21, 3)); $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5); $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2); $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7); $b0 = 2097151 & self::load_3(self::substr($b, 0, 3)); $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5); $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2); $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7); $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4); $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1); $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6); $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3); $b8 = 2097151 & self::load_3(self::substr($b, 21, 3)); $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5); $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2); $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7); $c0 = 2097151 & self::load_3(self::substr($c, 0, 3)); $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5); $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2); $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7); $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4); $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1); $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6); $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3); $c8 = 2097151 & self::load_3(self::substr($c, 21, 3)); $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5); $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2); $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7); /* Can't really avoid the pyramid here: */ $s0 = $c0 + self::mul($a0, $b0, 24); $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24); $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24); $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24); $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) + self::mul($a4, $b0, 24); $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) + self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24); $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) + self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24); $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) + self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24); $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) + self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) + self::mul($a8, $b0, 24); $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) + self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) + self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24); $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) + self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) + self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24); $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) + self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) + self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24); $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) + self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) + self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24); $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) + self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) + self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24); $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) + self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) + self::mul($a11, $b3, 24); $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) + self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24); $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) + self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24); $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) + self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24); $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) + self::mul($a11, $b7, 24); $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24); $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24); $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24); $s22 = self::mul($a11, $b11, 24); $s23 = 0; $carry0 = ($s0 + (1 << 20)) >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry2 = ($s2 + (1 << 20)) >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry4 = ($s4 + (1 << 20)) >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry12 = ($s12 + (1 << 20)) >> 21; $s13 += $carry12; $s12 -= $carry12 << 21; $carry14 = ($s14 + (1 << 20)) >> 21; $s15 += $carry14; $s14 -= $carry14 << 21; $carry16 = ($s16 + (1 << 20)) >> 21; $s17 += $carry16; $s16 -= $carry16 << 21; $carry18 = ($s18 + (1 << 20)) >> 21; $s19 += $carry18; $s18 -= $carry18 << 21; $carry20 = ($s20 + (1 << 20)) >> 21; $s21 += $carry20; $s20 -= $carry20 << 21; $carry22 = ($s22 + (1 << 20)) >> 21; $s23 += $carry22; $s22 -= $carry22 << 21; $carry1 = ($s1 + (1 << 20)) >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry3 = ($s3 + (1 << 20)) >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry5 = ($s5 + (1 << 20)) >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $carry13 = ($s13 + (1 << 20)) >> 21; $s14 += $carry13; $s13 -= $carry13 << 21; $carry15 = ($s15 + (1 << 20)) >> 21; $s16 += $carry15; $s15 -= $carry15 << 21; $carry17 = ($s17 + (1 << 20)) >> 21; $s18 += $carry17; $s17 -= $carry17 << 21; $carry19 = ($s19 + (1 << 20)) >> 21; $s20 += $carry19; $s19 -= $carry19 << 21; $carry21 = ($s21 + (1 << 20)) >> 21; $s22 += $carry21; $s21 -= $carry21 << 21; $s11 += self::mul($s23, 666643, 20); $s12 += self::mul($s23, 470296, 19); $s13 += self::mul($s23, 654183, 20); $s14 -= self::mul($s23, 997805, 20); $s15 += self::mul($s23, 136657, 18); $s16 -= self::mul($s23, 683901, 20); $s10 += self::mul($s22, 666643, 20); $s11 += self::mul($s22, 470296, 19); $s12 += self::mul($s22, 654183, 20); $s13 -= self::mul($s22, 997805, 20); $s14 += self::mul($s22, 136657, 18); $s15 -= self::mul($s22, 683901, 20); $s9 += self::mul($s21, 666643, 20); $s10 += self::mul($s21, 470296, 19); $s11 += self::mul($s21, 654183, 20); $s12 -= self::mul($s21, 997805, 20); $s13 += self::mul($s21, 136657, 18); $s14 -= self::mul($s21, 683901, 20); $s8 += self::mul($s20, 666643, 20); $s9 += self::mul($s20, 470296, 19); $s10 += self::mul($s20, 654183, 20); $s11 -= self::mul($s20, 997805, 20); $s12 += self::mul($s20, 136657, 18); $s13 -= self::mul($s20, 683901, 20); $s7 += self::mul($s19, 666643, 20); $s8 += self::mul($s19, 470296, 19); $s9 += self::mul($s19, 654183, 20); $s10 -= self::mul($s19, 997805, 20); $s11 += self::mul($s19, 136657, 18); $s12 -= self::mul($s19, 683901, 20); $s6 += self::mul($s18, 666643, 20); $s7 += self::mul($s18, 470296, 19); $s8 += self::mul($s18, 654183, 20); $s9 -= self::mul($s18, 997805, 20); $s10 += self::mul($s18, 136657, 18); $s11 -= self::mul($s18, 683901, 20); $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry12 = ($s12 + (1 << 20)) >> 21; $s13 += $carry12; $s12 -= $carry12 << 21; $carry14 = ($s14 + (1 << 20)) >> 21; $s15 += $carry14; $s14 -= $carry14 << 21; $carry16 = ($s16 + (1 << 20)) >> 21; $s17 += $carry16; $s16 -= $carry16 << 21; $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $carry13 = ($s13 + (1 << 20)) >> 21; $s14 += $carry13; $s13 -= $carry13 << 21; $carry15 = ($s15 + (1 << 20)) >> 21; $s16 += $carry15; $s15 -= $carry15 << 21; $s5 += self::mul($s17, 666643, 20); $s6 += self::mul($s17, 470296, 19); $s7 += self::mul($s17, 654183, 20); $s8 -= self::mul($s17, 997805, 20); $s9 += self::mul($s17, 136657, 18); $s10 -= self::mul($s17, 683901, 20); $s4 += self::mul($s16, 666643, 20); $s5 += self::mul($s16, 470296, 19); $s6 += self::mul($s16, 654183, 20); $s7 -= self::mul($s16, 997805, 20); $s8 += self::mul($s16, 136657, 18); $s9 -= self::mul($s16, 683901, 20); $s3 += self::mul($s15, 666643, 20); $s4 += self::mul($s15, 470296, 19); $s5 += self::mul($s15, 654183, 20); $s6 -= self::mul($s15, 997805, 20); $s7 += self::mul($s15, 136657, 18); $s8 -= self::mul($s15, 683901, 20); $s2 += self::mul($s14, 666643, 20); $s3 += self::mul($s14, 470296, 19); $s4 += self::mul($s14, 654183, 20); $s5 -= self::mul($s14, 997805, 20); $s6 += self::mul($s14, 136657, 18); $s7 -= self::mul($s14, 683901, 20); $s1 += self::mul($s13, 666643, 20); $s2 += self::mul($s13, 470296, 19); $s3 += self::mul($s13, 654183, 20); $s4 -= self::mul($s13, 997805, 20); $s5 += self::mul($s13, 136657, 18); $s6 -= self::mul($s13, 683901, 20); $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $s12 = 0; $carry0 = ($s0 + (1 << 20)) >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry2 = ($s2 + (1 << 20)) >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry4 = ($s4 + (1 << 20)) >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry1 = ($s1 + (1 << 20)) >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry3 = ($s3 + (1 << 20)) >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry5 = ($s5 + (1 << 20)) >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $s12 = 0; $carry0 = $s0 >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry1 = $s1 >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry2 = $s2 >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry3 = $s3 >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry4 = $s4 >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry5 = $s5 >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry6 = $s6 >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry7 = $s7 >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry8 = $s8 >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry9 = $s9 >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry10 = $s10 >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry11 = $s11 >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $carry0 = $s0 >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry1 = $s1 >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry2 = $s2 >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry3 = $s3 >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry4 = $s4 >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry5 = $s5 >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry6 = $s6 >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry7 = $s7 >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry8 = $s8 >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry9 = $s9 >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry10 = $s10 >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; /** * @var array<int, int> */ $arr = array( (int) (0xff & ($s0 >> 0)), (int) (0xff & ($s0 >> 8)), (int) (0xff & (($s0 >> 16) | $s1 << 5)), (int) (0xff & ($s1 >> 3)), (int) (0xff & ($s1 >> 11)), (int) (0xff & (($s1 >> 19) | $s2 << 2)), (int) (0xff & ($s2 >> 6)), (int) (0xff & (($s2 >> 14) | $s3 << 7)), (int) (0xff & ($s3 >> 1)), (int) (0xff & ($s3 >> 9)), (int) (0xff & (($s3 >> 17) | $s4 << 4)), (int) (0xff & ($s4 >> 4)), (int) (0xff & ($s4 >> 12)), (int) (0xff & (($s4 >> 20) | $s5 << 1)), (int) (0xff & ($s5 >> 7)), (int) (0xff & (($s5 >> 15) | $s6 << 6)), (int) (0xff & ($s6 >> 2)), (int) (0xff & ($s6 >> 10)), (int) (0xff & (($s6 >> 18) | $s7 << 3)), (int) (0xff & ($s7 >> 5)), (int) (0xff & ($s7 >> 13)), (int) (0xff & ($s8 >> 0)), (int) (0xff & ($s8 >> 8)), (int) (0xff & (($s8 >> 16) | $s9 << 5)), (int) (0xff & ($s9 >> 3)), (int) (0xff & ($s9 >> 11)), (int) (0xff & (($s9 >> 19) | $s10 << 2)), (int) (0xff & ($s10 >> 6)), (int) (0xff & (($s10 >> 14) | $s11 << 7)), (int) (0xff & ($s11 >> 1)), (int) (0xff & ($s11 >> 9)), 0xff & ($s11 >> 17) ); return self::intArrayToString($arr); } /** * @internal You should not use this directly from another application * * @param string $s * @return string * @throws TypeError */ public static function sc_reduce($s) { $s0 = 2097151 & self::load_3(self::substr($s, 0, 3)); $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5); $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2); $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7); $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4); $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1); $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6); $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3); $s8 = 2097151 & self::load_3(self::substr($s, 21, 3)); $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5); $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2); $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7); $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4); $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1); $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6); $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3); $s16 = 2097151 & self::load_3(self::substr($s, 42, 3)); $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5); $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2); $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7); $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4); $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1); $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6); $s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3); $s11 += self::mul($s23, 666643, 20); $s12 += self::mul($s23, 470296, 19); $s13 += self::mul($s23, 654183, 20); $s14 -= self::mul($s23, 997805, 20); $s15 += self::mul($s23, 136657, 18); $s16 -= self::mul($s23, 683901, 20); $s10 += self::mul($s22, 666643, 20); $s11 += self::mul($s22, 470296, 19); $s12 += self::mul($s22, 654183, 20); $s13 -= self::mul($s22, 997805, 20); $s14 += self::mul($s22, 136657, 18); $s15 -= self::mul($s22, 683901, 20); $s9 += self::mul($s21, 666643, 20); $s10 += self::mul($s21, 470296, 19); $s11 += self::mul($s21, 654183, 20); $s12 -= self::mul($s21, 997805, 20); $s13 += self::mul($s21, 136657, 18); $s14 -= self::mul($s21, 683901, 20); $s8 += self::mul($s20, 666643, 20); $s9 += self::mul($s20, 470296, 19); $s10 += self::mul($s20, 654183, 20); $s11 -= self::mul($s20, 997805, 20); $s12 += self::mul($s20, 136657, 18); $s13 -= self::mul($s20, 683901, 20); $s7 += self::mul($s19, 666643, 20); $s8 += self::mul($s19, 470296, 19); $s9 += self::mul($s19, 654183, 20); $s10 -= self::mul($s19, 997805, 20); $s11 += self::mul($s19, 136657, 18); $s12 -= self::mul($s19, 683901, 20); $s6 += self::mul($s18, 666643, 20); $s7 += self::mul($s18, 470296, 19); $s8 += self::mul($s18, 654183, 20); $s9 -= self::mul($s18, 997805, 20); $s10 += self::mul($s18, 136657, 18); $s11 -= self::mul($s18, 683901, 20); $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry12 = ($s12 + (1 << 20)) >> 21; $s13 += $carry12; $s12 -= $carry12 << 21; $carry14 = ($s14 + (1 << 20)) >> 21; $s15 += $carry14; $s14 -= $carry14 << 21; $carry16 = ($s16 + (1 << 20)) >> 21; $s17 += $carry16; $s16 -= $carry16 << 21; $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $carry13 = ($s13 + (1 << 20)) >> 21; $s14 += $carry13; $s13 -= $carry13 << 21; $carry15 = ($s15 + (1 << 20)) >> 21; $s16 += $carry15; $s15 -= $carry15 << 21; $s5 += self::mul($s17, 666643, 20); $s6 += self::mul($s17, 470296, 19); $s7 += self::mul($s17, 654183, 20); $s8 -= self::mul($s17, 997805, 20); $s9 += self::mul($s17, 136657, 18); $s10 -= self::mul($s17, 683901, 20); $s4 += self::mul($s16, 666643, 20); $s5 += self::mul($s16, 470296, 19); $s6 += self::mul($s16, 654183, 20); $s7 -= self::mul($s16, 997805, 20); $s8 += self::mul($s16, 136657, 18); $s9 -= self::mul($s16, 683901, 20); $s3 += self::mul($s15, 666643, 20); $s4 += self::mul($s15, 470296, 19); $s5 += self::mul($s15, 654183, 20); $s6 -= self::mul($s15, 997805, 20); $s7 += self::mul($s15, 136657, 18); $s8 -= self::mul($s15, 683901, 20); $s2 += self::mul($s14, 666643, 20); $s3 += self::mul($s14, 470296, 19); $s4 += self::mul($s14, 654183, 20); $s5 -= self::mul($s14, 997805, 20); $s6 += self::mul($s14, 136657, 18); $s7 -= self::mul($s14, 683901, 20); $s1 += self::mul($s13, 666643, 20); $s2 += self::mul($s13, 470296, 19); $s3 += self::mul($s13, 654183, 20); $s4 -= self::mul($s13, 997805, 20); $s5 += self::mul($s13, 136657, 18); $s6 -= self::mul($s13, 683901, 20); $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $s12 = 0; $carry0 = ($s0 + (1 << 20)) >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry2 = ($s2 + (1 << 20)) >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry4 = ($s4 + (1 << 20)) >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry1 = ($s1 + (1 << 20)) >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry3 = ($s3 + (1 << 20)) >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry5 = ($s5 + (1 << 20)) >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $s12 = 0; $carry0 = $s0 >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry1 = $s1 >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry2 = $s2 >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry3 = $s3 >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry4 = $s4 >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry5 = $s5 >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry6 = $s6 >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry7 = $s7 >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry8 = $s8 >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry9 = $s9 >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry10 = $s10 >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $carry11 = $s11 >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $carry0 = $s0 >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; $carry1 = $s1 >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; $carry2 = $s2 >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; $carry3 = $s3 >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; $carry4 = $s4 >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; $carry5 = $s5 >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; $carry6 = $s6 >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; $carry7 = $s7 >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; $carry8 = $s8 >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; $carry9 = $s9 >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; $carry10 = $s10 >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; /** * @var array<int, int> */ $arr = array( (int) ($s0 >> 0), (int) ($s0 >> 8), (int) (($s0 >> 16) | $s1 << 5), (int) ($s1 >> 3), (int) ($s1 >> 11), (int) (($s1 >> 19) | $s2 << 2), (int) ($s2 >> 6), (int) (($s2 >> 14) | $s3 << 7), (int) ($s3 >> 1), (int) ($s3 >> 9), (int) (($s3 >> 17) | $s4 << 4), (int) ($s4 >> 4), (int) ($s4 >> 12), (int) (($s4 >> 20) | $s5 << 1), (int) ($s5 >> 7), (int) (($s5 >> 15) | $s6 << 6), (int) ($s6 >> 2), (int) ($s6 >> 10), (int) (($s6 >> 18) | $s7 << 3), (int) ($s7 >> 5), (int) ($s7 >> 13), (int) ($s8 >> 0), (int) ($s8 >> 8), (int) (($s8 >> 16) | $s9 << 5), (int) ($s9 >> 3), (int) ($s9 >> 11), (int) (($s9 >> 19) | $s10 << 2), (int) ($s10 >> 6), (int) (($s10 >> 14) | $s11 << 7), (int) ($s11 >> 1), (int) ($s11 >> 9), (int) $s11 >> 17 ); return self::intArrayToString($arr); } /** * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 * * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 */ public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A) { $aslide = array( 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ); /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */ $Ai = array(); # ge_p3_to_cached(&Ai[0], A); $Ai[0] = self::ge_p3_to_cached($A); # ge_p3_dbl(&t, A); $t = self::ge_p3_dbl($A); # ge_p1p1_to_p3(&A2, &t); $A2 = self::ge_p1p1_to_p3($t); for ($i = 1; $i < 8; ++$i) { # ge_add(&t, &A2, &Ai[0]); $t = self::ge_add($A2, $Ai[$i - 1]); # ge_p1p1_to_p3(&u, &t); $u = self::ge_p1p1_to_p3($t); # ge_p3_to_cached(&Ai[i], &u); $Ai[$i] = self::ge_p3_to_cached($u); } $r = self::ge_p3_0(); for ($i = 252; $i >= 0; --$i) { $t = self::ge_p3_dbl($r); if ($aslide[$i] > 0) { # ge_p1p1_to_p3(&u, &t); $u = self::ge_p1p1_to_p3($t); # ge_add(&t, &u, &Ai[aslide[i] / 2]); $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]); } elseif ($aslide[$i] < 0) { # ge_p1p1_to_p3(&u, &t); $u = self::ge_p1p1_to_p3($t); # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]); } } # ge_p1p1_to_p3(r, &t); return self::ge_p1p1_to_p3($t); } /** * @param string $a * @param string $b * @return string */ public static function sc25519_mul($a, $b) { // int64_t a0 = 2097151 & load_3(a); // int64_t a1 = 2097151 & (load_4(a + 2) >> 5); // int64_t a2 = 2097151 & (load_3(a + 5) >> 2); // int64_t a3 = 2097151 & (load_4(a + 7) >> 7); // int64_t a4 = 2097151 & (load_4(a + 10) >> 4); // int64_t a5 = 2097151 & (load_3(a + 13) >> 1); // int64_t a6 = 2097151 & (load_4(a + 15) >> 6); // int64_t a7 = 2097151 & (load_3(a + 18) >> 3); // int64_t a8 = 2097151 & load_3(a + 21); // int64_t a9 = 2097151 & (load_4(a + 23) >> 5); // int64_t a10 = 2097151 & (load_3(a + 26) >> 2); // int64_t a11 = (load_4(a + 28) >> 7); $a0 = 2097151 & self::load_3(self::substr($a, 0, 3)); $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5); $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2); $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7); $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4); $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1); $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6); $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3); $a8 = 2097151 & self::load_3(self::substr($a, 21, 3)); $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5); $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2); $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7); // int64_t b0 = 2097151 & load_3(b); // int64_t b1 = 2097151 & (load_4(b + 2) >> 5); // int64_t b2 = 2097151 & (load_3(b + 5) >> 2); // int64_t b3 = 2097151 & (load_4(b + 7) >> 7); // int64_t b4 = 2097151 & (load_4(b + 10) >> 4); // int64_t b5 = 2097151 & (load_3(b + 13) >> 1); // int64_t b6 = 2097151 & (load_4(b + 15) >> 6); // int64_t b7 = 2097151 & (load_3(b + 18) >> 3); // int64_t b8 = 2097151 & load_3(b + 21); // int64_t b9 = 2097151 & (load_4(b + 23) >> 5); // int64_t b10 = 2097151 & (load_3(b + 26) >> 2); // int64_t b11 = (load_4(b + 28) >> 7); $b0 = 2097151 & self::load_3(self::substr($b, 0, 3)); $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5); $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2); $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7); $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4); $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1); $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6); $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3); $b8 = 2097151 & self::load_3(self::substr($b, 21, 3)); $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5); $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2); $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7); // s0 = a0 * b0; // s1 = a0 * b1 + a1 * b0; // s2 = a0 * b2 + a1 * b1 + a2 * b0; // s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; // s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; // s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; // s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; // s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + // a6 * b1 + a7 * b0; // s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + // a6 * b2 + a7 * b1 + a8 * b0; // s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + // a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; // s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + // a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; // s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + // a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; // s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + // a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; // s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + // a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; // s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + // a9 * b5 + a10 * b4 + a11 * b3; // s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + // a10 * b5 + a11 * b4; // s16 = // a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; // s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; // s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; // s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; // s20 = a9 * b11 + a10 * b10 + a11 * b9; // s21 = a10 * b11 + a11 * b10; // s22 = a11 * b11; // s23 = 0; $s0 = self::mul($a0, $b0, 22); $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22); $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22); $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22); $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) + self::mul($a4, $b0, 22); $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) + self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22); $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) + self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22); $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) + self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22); $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) + self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) + self::mul($a8, $b0, 22); $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) + self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) + self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22); $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) + self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) + self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22); $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) + self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) + self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22); $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) + self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) + self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22); $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) + self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) + self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22); $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) + self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) + self::mul($a11, $b3, 22); $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) + self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22); $s16 = self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) + self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22); $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) + self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22); $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22) + self::mul($a11, $b7, 22); $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) + self::mul($a11, $b8, 22); $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22); $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22); $s22 = self::mul($a11, $b11, 22); $s23 = 0; // carry0 = (s0 + (int64_t) (1L << 20)) >> 21; // s1 += carry0; // s0 -= carry0 * ((uint64_t) 1L << 21); $carry0 = ($s0 + (1 << 20)) >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; // carry2 = (s2 + (int64_t) (1L << 20)) >> 21; // s3 += carry2; // s2 -= carry2 * ((uint64_t) 1L << 21); $carry2 = ($s2 + (1 << 20)) >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; // carry4 = (s4 + (int64_t) (1L << 20)) >> 21; // s5 += carry4; // s4 -= carry4 * ((uint64_t) 1L << 21); $carry4 = ($s4 + (1 << 20)) >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; // carry6 = (s6 + (int64_t) (1L << 20)) >> 21; // s7 += carry6; // s6 -= carry6 * ((uint64_t) 1L << 21); $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; // carry8 = (s8 + (int64_t) (1L << 20)) >> 21; // s9 += carry8; // s8 -= carry8 * ((uint64_t) 1L << 21); $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; // carry10 = (s10 + (int64_t) (1L << 20)) >> 21; // s11 += carry10; // s10 -= carry10 * ((uint64_t) 1L << 21); $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; // carry12 = (s12 + (int64_t) (1L << 20)) >> 21; // s13 += carry12; // s12 -= carry12 * ((uint64_t) 1L << 21); $carry12 = ($s12 + (1 << 20)) >> 21; $s13 += $carry12; $s12 -= $carry12 << 21; // carry14 = (s14 + (int64_t) (1L << 20)) >> 21; // s15 += carry14; // s14 -= carry14 * ((uint64_t) 1L << 21); $carry14 = ($s14 + (1 << 20)) >> 21; $s15 += $carry14; $s14 -= $carry14 << 21; // carry16 = (s16 + (int64_t) (1L << 20)) >> 21; // s17 += carry16; // s16 -= carry16 * ((uint64_t) 1L << 21); $carry16 = ($s16 + (1 << 20)) >> 21; $s17 += $carry16; $s16 -= $carry16 << 21; // carry18 = (s18 + (int64_t) (1L << 20)) >> 21; // s19 += carry18; // s18 -= carry18 * ((uint64_t) 1L << 21); $carry18 = ($s18 + (1 << 20)) >> 21; $s19 += $carry18; $s18 -= $carry18 << 21; // carry20 = (s20 + (int64_t) (1L << 20)) >> 21; // s21 += carry20; // s20 -= carry20 * ((uint64_t) 1L << 21); $carry20 = ($s20 + (1 << 20)) >> 21; $s21 += $carry20; $s20 -= $carry20 << 21; // carry22 = (s22 + (int64_t) (1L << 20)) >> 21; // s23 += carry22; // s22 -= carry22 * ((uint64_t) 1L << 21); $carry22 = ($s22 + (1 << 20)) >> 21; $s23 += $carry22; $s22 -= $carry22 << 21; // carry1 = (s1 + (int64_t) (1L << 20)) >> 21; // s2 += carry1; // s1 -= carry1 * ((uint64_t) 1L << 21); $carry1 = ($s1 + (1 << 20)) >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; // carry3 = (s3 + (int64_t) (1L << 20)) >> 21; // s4 += carry3; // s3 -= carry3 * ((uint64_t) 1L << 21); $carry3 = ($s3 + (1 << 20)) >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; // carry5 = (s5 + (int64_t) (1L << 20)) >> 21; // s6 += carry5; // s5 -= carry5 * ((uint64_t) 1L << 21); $carry5 = ($s5 + (1 << 20)) >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; // carry7 = (s7 + (int64_t) (1L << 20)) >> 21; // s8 += carry7; // s7 -= carry7 * ((uint64_t) 1L << 21); $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; // carry9 = (s9 + (int64_t) (1L << 20)) >> 21; // s10 += carry9; // s9 -= carry9 * ((uint64_t) 1L << 21); $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; // carry11 = (s11 + (int64_t) (1L << 20)) >> 21; // s12 += carry11; // s11 -= carry11 * ((uint64_t) 1L << 21); $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; // carry13 = (s13 + (int64_t) (1L << 20)) >> 21; // s14 += carry13; // s13 -= carry13 * ((uint64_t) 1L << 21); $carry13 = ($s13 + (1 << 20)) >> 21; $s14 += $carry13; $s13 -= $carry13 << 21; // carry15 = (s15 + (int64_t) (1L << 20)) >> 21; // s16 += carry15; // s15 -= carry15 * ((uint64_t) 1L << 21); $carry15 = ($s15 + (1 << 20)) >> 21; $s16 += $carry15; $s15 -= $carry15 << 21; // carry17 = (s17 + (int64_t) (1L << 20)) >> 21; // s18 += carry17; // s17 -= carry17 * ((uint64_t) 1L << 21); $carry17 = ($s17 + (1 << 20)) >> 21; $s18 += $carry17; $s17 -= $carry17 << 21; // carry19 = (s19 + (int64_t) (1L << 20)) >> 21; // s20 += carry19; // s19 -= carry19 * ((uint64_t) 1L << 21); $carry19 = ($s19 + (1 << 20)) >> 21; $s20 += $carry19; $s19 -= $carry19 << 21; // carry21 = (s21 + (int64_t) (1L << 20)) >> 21; // s22 += carry21; // s21 -= carry21 * ((uint64_t) 1L << 21); $carry21 = ($s21 + (1 << 20)) >> 21; $s22 += $carry21; $s21 -= $carry21 << 21; // s11 += s23 * 666643; // s12 += s23 * 470296; // s13 += s23 * 654183; // s14 -= s23 * 997805; // s15 += s23 * 136657; // s16 -= s23 * 683901; $s11 += self::mul($s23, 666643, 20); $s12 += self::mul($s23, 470296, 19); $s13 += self::mul($s23, 654183, 20); $s14 -= self::mul($s23, 997805, 20); $s15 += self::mul($s23, 136657, 18); $s16 -= self::mul($s23, 683901, 20); // s10 += s22 * 666643; // s11 += s22 * 470296; // s12 += s22 * 654183; // s13 -= s22 * 997805; // s14 += s22 * 136657; // s15 -= s22 * 683901; $s10 += self::mul($s22, 666643, 20); $s11 += self::mul($s22, 470296, 19); $s12 += self::mul($s22, 654183, 20); $s13 -= self::mul($s22, 997805, 20); $s14 += self::mul($s22, 136657, 18); $s15 -= self::mul($s22, 683901, 20); // s9 += s21 * 666643; // s10 += s21 * 470296; // s11 += s21 * 654183; // s12 -= s21 * 997805; // s13 += s21 * 136657; // s14 -= s21 * 683901; $s9 += self::mul($s21, 666643, 20); $s10 += self::mul($s21, 470296, 19); $s11 += self::mul($s21, 654183, 20); $s12 -= self::mul($s21, 997805, 20); $s13 += self::mul($s21, 136657, 18); $s14 -= self::mul($s21, 683901, 20); // s8 += s20 * 666643; // s9 += s20 * 470296; // s10 += s20 * 654183; // s11 -= s20 * 997805; // s12 += s20 * 136657; // s13 -= s20 * 683901; $s8 += self::mul($s20, 666643, 20); $s9 += self::mul($s20, 470296, 19); $s10 += self::mul($s20, 654183, 20); $s11 -= self::mul($s20, 997805, 20); $s12 += self::mul($s20, 136657, 18); $s13 -= self::mul($s20, 683901, 20); // s7 += s19 * 666643; // s8 += s19 * 470296; // s9 += s19 * 654183; // s10 -= s19 * 997805; // s11 += s19 * 136657; // s12 -= s19 * 683901; $s7 += self::mul($s19, 666643, 20); $s8 += self::mul($s19, 470296, 19); $s9 += self::mul($s19, 654183, 20); $s10 -= self::mul($s19, 997805, 20); $s11 += self::mul($s19, 136657, 18); $s12 -= self::mul($s19, 683901, 20); // s6 += s18 * 666643; // s7 += s18 * 470296; // s8 += s18 * 654183; // s9 -= s18 * 997805; // s10 += s18 * 136657; // s11 -= s18 * 683901; $s6 += self::mul($s18, 666643, 20); $s7 += self::mul($s18, 470296, 19); $s8 += self::mul($s18, 654183, 20); $s9 -= self::mul($s18, 997805, 20); $s10 += self::mul($s18, 136657, 18); $s11 -= self::mul($s18, 683901, 20); // carry6 = (s6 + (int64_t) (1L << 20)) >> 21; // s7 += carry6; // s6 -= carry6 * ((uint64_t) 1L << 21); $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; // carry8 = (s8 + (int64_t) (1L << 20)) >> 21; // s9 += carry8; // s8 -= carry8 * ((uint64_t) 1L << 21); $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; // carry10 = (s10 + (int64_t) (1L << 20)) >> 21; // s11 += carry10; // s10 -= carry10 * ((uint64_t) 1L << 21); $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; // carry12 = (s12 + (int64_t) (1L << 20)) >> 21; // s13 += carry12; // s12 -= carry12 * ((uint64_t) 1L << 21); $carry12 = ($s12 + (1 << 20)) >> 21; $s13 += $carry12; $s12 -= $carry12 << 21; // carry14 = (s14 + (int64_t) (1L << 20)) >> 21; // s15 += carry14; // s14 -= carry14 * ((uint64_t) 1L << 21); $carry14 = ($s14 + (1 << 20)) >> 21; $s15 += $carry14; $s14 -= $carry14 << 21; // carry16 = (s16 + (int64_t) (1L << 20)) >> 21; // s17 += carry16; // s16 -= carry16 * ((uint64_t) 1L << 21); $carry16 = ($s16 + (1 << 20)) >> 21; $s17 += $carry16; $s16 -= $carry16 << 21; // carry7 = (s7 + (int64_t) (1L << 20)) >> 21; // s8 += carry7; // s7 -= carry7 * ((uint64_t) 1L << 21); $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; // carry9 = (s9 + (int64_t) (1L << 20)) >> 21; // s10 += carry9; // s9 -= carry9 * ((uint64_t) 1L << 21); $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; // carry11 = (s11 + (int64_t) (1L << 20)) >> 21; // s12 += carry11; // s11 -= carry11 * ((uint64_t) 1L << 21); $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; // carry13 = (s13 + (int64_t) (1L << 20)) >> 21; // s14 += carry13; // s13 -= carry13 * ((uint64_t) 1L << 21); $carry13 = ($s13 + (1 << 20)) >> 21; $s14 += $carry13; $s13 -= $carry13 << 21; // carry15 = (s15 + (int64_t) (1L << 20)) >> 21; // s16 += carry15; // s15 -= carry15 * ((uint64_t) 1L << 21); $carry15 = ($s15 + (1 << 20)) >> 21; $s16 += $carry15; $s15 -= $carry15 << 21; // s5 += s17 * 666643; // s6 += s17 * 470296; // s7 += s17 * 654183; // s8 -= s17 * 997805; // s9 += s17 * 136657; // s10 -= s17 * 683901; $s5 += self::mul($s17, 666643, 20); $s6 += self::mul($s17, 470296, 19); $s7 += self::mul($s17, 654183, 20); $s8 -= self::mul($s17, 997805, 20); $s9 += self::mul($s17, 136657, 18); $s10 -= self::mul($s17, 683901, 20); // s4 += s16 * 666643; // s5 += s16 * 470296; // s6 += s16 * 654183; // s7 -= s16 * 997805; // s8 += s16 * 136657; // s9 -= s16 * 683901; $s4 += self::mul($s16, 666643, 20); $s5 += self::mul($s16, 470296, 19); $s6 += self::mul($s16, 654183, 20); $s7 -= self::mul($s16, 997805, 20); $s8 += self::mul($s16, 136657, 18); $s9 -= self::mul($s16, 683901, 20); // s3 += s15 * 666643; // s4 += s15 * 470296; // s5 += s15 * 654183; // s6 -= s15 * 997805; // s7 += s15 * 136657; // s8 -= s15 * 683901; $s3 += self::mul($s15, 666643, 20); $s4 += self::mul($s15, 470296, 19); $s5 += self::mul($s15, 654183, 20); $s6 -= self::mul($s15, 997805, 20); $s7 += self::mul($s15, 136657, 18); $s8 -= self::mul($s15, 683901, 20); // s2 += s14 * 666643; // s3 += s14 * 470296; // s4 += s14 * 654183; // s5 -= s14 * 997805; // s6 += s14 * 136657; // s7 -= s14 * 683901; $s2 += self::mul($s14, 666643, 20); $s3 += self::mul($s14, 470296, 19); $s4 += self::mul($s14, 654183, 20); $s5 -= self::mul($s14, 997805, 20); $s6 += self::mul($s14, 136657, 18); $s7 -= self::mul($s14, 683901, 20); // s1 += s13 * 666643; // s2 += s13 * 470296; // s3 += s13 * 654183; // s4 -= s13 * 997805; // s5 += s13 * 136657; // s6 -= s13 * 683901; $s1 += self::mul($s13, 666643, 20); $s2 += self::mul($s13, 470296, 19); $s3 += self::mul($s13, 654183, 20); $s4 -= self::mul($s13, 997805, 20); $s5 += self::mul($s13, 136657, 18); $s6 -= self::mul($s13, 683901, 20); // s0 += s12 * 666643; // s1 += s12 * 470296; // s2 += s12 * 654183; // s3 -= s12 * 997805; // s4 += s12 * 136657; // s5 -= s12 * 683901; // s12 = 0; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $s12 = 0; // carry0 = (s0 + (int64_t) (1L << 20)) >> 21; // s1 += carry0; // s0 -= carry0 * ((uint64_t) 1L << 21); $carry0 = ($s0 + (1 << 20)) >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; // carry2 = (s2 + (int64_t) (1L << 20)) >> 21; // s3 += carry2; // s2 -= carry2 * ((uint64_t) 1L << 21); $carry2 = ($s2 + (1 << 20)) >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; // carry4 = (s4 + (int64_t) (1L << 20)) >> 21; // s5 += carry4; // s4 -= carry4 * ((uint64_t) 1L << 21); $carry4 = ($s4 + (1 << 20)) >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; // carry6 = (s6 + (int64_t) (1L << 20)) >> 21; // s7 += carry6; // s6 -= carry6 * ((uint64_t) 1L << 21); $carry6 = ($s6 + (1 << 20)) >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; // carry8 = (s8 + (int64_t) (1L << 20)) >> 21; // s9 += carry8; // s8 -= carry8 * ((uint64_t) 1L << 21); $carry8 = ($s8 + (1 << 20)) >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; // carry10 = (s10 + (int64_t) (1L << 20)) >> 21; // s11 += carry10; // s10 -= carry10 * ((uint64_t) 1L << 21); $carry10 = ($s10 + (1 << 20)) >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; // carry1 = (s1 + (int64_t) (1L << 20)) >> 21; // s2 += carry1; // s1 -= carry1 * ((uint64_t) 1L << 21); $carry1 = ($s1 + (1 << 20)) >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; // carry3 = (s3 + (int64_t) (1L << 20)) >> 21; // s4 += carry3; // s3 -= carry3 * ((uint64_t) 1L << 21); $carry3 = ($s3 + (1 << 20)) >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; // carry5 = (s5 + (int64_t) (1L << 20)) >> 21; // s6 += carry5; // s5 -= carry5 * ((uint64_t) 1L << 21); $carry5 = ($s5 + (1 << 20)) >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; // carry7 = (s7 + (int64_t) (1L << 20)) >> 21; // s8 += carry7; // s7 -= carry7 * ((uint64_t) 1L << 21); $carry7 = ($s7 + (1 << 20)) >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; // carry9 = (s9 + (int64_t) (1L << 20)) >> 21; // s10 += carry9; // s9 -= carry9 * ((uint64_t) 1L << 21); $carry9 = ($s9 + (1 << 20)) >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; // carry11 = (s11 + (int64_t) (1L << 20)) >> 21; // s12 += carry11; // s11 -= carry11 * ((uint64_t) 1L << 21); $carry11 = ($s11 + (1 << 20)) >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; // s0 += s12 * 666643; // s1 += s12 * 470296; // s2 += s12 * 654183; // s3 -= s12 * 997805; // s4 += s12 * 136657; // s5 -= s12 * 683901; // s12 = 0; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); $s12 = 0; // carry0 = s0 >> 21; // s1 += carry0; // s0 -= carry0 * ((uint64_t) 1L << 21); $carry0 = $s0 >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; // carry1 = s1 >> 21; // s2 += carry1; // s1 -= carry1 * ((uint64_t) 1L << 21); $carry1 = $s1 >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; // carry2 = s2 >> 21; // s3 += carry2; // s2 -= carry2 * ((uint64_t) 1L << 21); $carry2 = $s2 >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; // carry3 = s3 >> 21; // s4 += carry3; // s3 -= carry3 * ((uint64_t) 1L << 21); $carry3 = $s3 >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; // carry4 = s4 >> 21; // s5 += carry4; // s4 -= carry4 * ((uint64_t) 1L << 21); $carry4 = $s4 >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; // carry5 = s5 >> 21; // s6 += carry5; // s5 -= carry5 * ((uint64_t) 1L << 21); $carry5 = $s5 >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; // carry6 = s6 >> 21; // s7 += carry6; // s6 -= carry6 * ((uint64_t) 1L << 21); $carry6 = $s6 >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; // carry7 = s7 >> 21; // s8 += carry7; // s7 -= carry7 * ((uint64_t) 1L << 21); $carry7 = $s7 >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; // carry8 = s8 >> 21; // s9 += carry8; // s8 -= carry8 * ((uint64_t) 1L << 21); $carry8 = $s8 >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; // carry9 = s9 >> 21; // s10 += carry9; // s9 -= carry9 * ((uint64_t) 1L << 21); $carry9 = $s9 >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; // carry10 = s10 >> 21; // s11 += carry10; // s10 -= carry10 * ((uint64_t) 1L << 21); $carry10 = $s10 >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; // carry11 = s11 >> 21; // s12 += carry11; // s11 -= carry11 * ((uint64_t) 1L << 21); $carry11 = $s11 >> 21; $s12 += $carry11; $s11 -= $carry11 << 21; // s0 += s12 * 666643; // s1 += s12 * 470296; // s2 += s12 * 654183; // s3 -= s12 * 997805; // s4 += s12 * 136657; // s5 -= s12 * 683901; $s0 += self::mul($s12, 666643, 20); $s1 += self::mul($s12, 470296, 19); $s2 += self::mul($s12, 654183, 20); $s3 -= self::mul($s12, 997805, 20); $s4 += self::mul($s12, 136657, 18); $s5 -= self::mul($s12, 683901, 20); // carry0 = s0 >> 21; // s1 += carry0; // s0 -= carry0 * ((uint64_t) 1L << 21); $carry0 = $s0 >> 21; $s1 += $carry0; $s0 -= $carry0 << 21; // carry1 = s1 >> 21; // s2 += carry1; // s1 -= carry1 * ((uint64_t) 1L << 21); $carry1 = $s1 >> 21; $s2 += $carry1; $s1 -= $carry1 << 21; // carry2 = s2 >> 21; // s3 += carry2; // s2 -= carry2 * ((uint64_t) 1L << 21); $carry2 = $s2 >> 21; $s3 += $carry2; $s2 -= $carry2 << 21; // carry3 = s3 >> 21; // s4 += carry3; // s3 -= carry3 * ((uint64_t) 1L << 21); $carry3 = $s3 >> 21; $s4 += $carry3; $s3 -= $carry3 << 21; // carry4 = s4 >> 21; // s5 += carry4; // s4 -= carry4 * ((uint64_t) 1L << 21); $carry4 = $s4 >> 21; $s5 += $carry4; $s4 -= $carry4 << 21; // carry5 = s5 >> 21; // s6 += carry5; // s5 -= carry5 * ((uint64_t) 1L << 21); $carry5 = $s5 >> 21; $s6 += $carry5; $s5 -= $carry5 << 21; // carry6 = s6 >> 21; // s7 += carry6; // s6 -= carry6 * ((uint64_t) 1L << 21); $carry6 = $s6 >> 21; $s7 += $carry6; $s6 -= $carry6 << 21; // carry7 = s7 >> 21; // s8 += carry7; // s7 -= carry7 * ((uint64_t) 1L << 21); $carry7 = $s7 >> 21; $s8 += $carry7; $s7 -= $carry7 << 21; // carry8 = s8 >> 21; // s9 += carry8; // s8 -= carry8 * ((uint64_t) 1L << 21); $carry8 = $s8 >> 21; $s9 += $carry8; $s8 -= $carry8 << 21; // carry9 = s9 >> 21; // s10 += carry9; // s9 -= carry9 * ((uint64_t) 1L << 21); $carry9 = $s9 >> 21; $s10 += $carry9; $s9 -= $carry9 << 21; // carry10 = s10 >> 21; // s11 += carry10; // s10 -= carry10 * ((uint64_t) 1L << 21); $carry10 = $s10 >> 21; $s11 += $carry10; $s10 -= $carry10 << 21; $s = array_fill(0, 32, 0); // s[0] = s0 >> 0; $s[0] = $s0 >> 0; // s[1] = s0 >> 8; $s[1] = $s0 >> 8; // s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5)); $s[2] = ($s0 >> 16) | ($s1 << 5); // s[3] = s1 >> 3; $s[3] = $s1 >> 3; // s[4] = s1 >> 11; $s[4] = $s1 >> 11; // s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2)); $s[5] = ($s1 >> 19) | ($s2 << 2); // s[6] = s2 >> 6; $s[6] = $s2 >> 6; // s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7)); $s[7] = ($s2 >> 14) | ($s3 << 7); // s[8] = s3 >> 1; $s[8] = $s3 >> 1; // s[9] = s3 >> 9; $s[9] = $s3 >> 9; // s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4)); $s[10] = ($s3 >> 17) | ($s4 << 4); // s[11] = s4 >> 4; $s[11] = $s4 >> 4; // s[12] = s4 >> 12; $s[12] = $s4 >> 12; // s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1)); $s[13] = ($s4 >> 20) | ($s5 << 1); // s[14] = s5 >> 7; $s[14] = $s5 >> 7; // s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6)); $s[15] = ($s5 >> 15) | ($s6 << 6); // s[16] = s6 >> 2; $s[16] = $s6 >> 2; // s[17] = s6 >> 10; $s[17] = $s6 >> 10; // s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3)); $s[18] = ($s6 >> 18) | ($s7 << 3); // s[19] = s7 >> 5; $s[19] = $s7 >> 5; // s[20] = s7 >> 13; $s[20] = $s7 >> 13; // s[21] = s8 >> 0; $s[21] = $s8 >> 0; // s[22] = s8 >> 8; $s[22] = $s8 >> 8; // s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5)); $s[23] = ($s8 >> 16) | ($s9 << 5); // s[24] = s9 >> 3; $s[24] = $s9 >> 3; // s[25] = s9 >> 11; $s[25] = $s9 >> 11; // s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2)); $s[26] = ($s9 >> 19) | ($s10 << 2); // s[27] = s10 >> 6; $s[27] = $s10 >> 6; // s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7)); $s[28] = ($s10 >> 14) | ($s11 << 7); // s[29] = s11 >> 1; $s[29] = $s11 >> 1; // s[30] = s11 >> 9; $s[30] = $s11 >> 9; // s[31] = s11 >> 17; $s[31] = $s11 >> 17; return self::intArrayToString($s); } /** * @param string $s * @return string */ public static function sc25519_sq($s) { return self::sc25519_mul($s, $s); } /** * @param string $s * @param int $n * @param string $a * @return string */ public static function sc25519_sqmul($s, $n, $a) { for ($i = 0; $i < $n; ++$i) { $s = self::sc25519_sq($s); } return self::sc25519_mul($s, $a); } /** * @param string $s * @return string */ public static function sc25519_invert($s) { $_10 = self::sc25519_sq($s); $_11 = self::sc25519_mul($s, $_10); $_100 = self::sc25519_mul($s, $_11); $_1000 = self::sc25519_sq($_100); $_1010 = self::sc25519_mul($_10, $_1000); $_1011 = self::sc25519_mul($s, $_1010); $_10000 = self::sc25519_sq($_1000); $_10110 = self::sc25519_sq($_1011); $_100000 = self::sc25519_mul($_1010, $_10110); $_100110 = self::sc25519_mul($_10000, $_10110); $_1000000 = self::sc25519_sq($_100000); $_1010000 = self::sc25519_mul($_10000, $_1000000); $_1010011 = self::sc25519_mul($_11, $_1010000); $_1100011 = self::sc25519_mul($_10000, $_1010011); $_1100111 = self::sc25519_mul($_100, $_1100011); $_1101011 = self::sc25519_mul($_100, $_1100111); $_10010011 = self::sc25519_mul($_1000000, $_1010011); $_10010111 = self::sc25519_mul($_100, $_10010011); $_10111101 = self::sc25519_mul($_100110, $_10010111); $_11010011 = self::sc25519_mul($_10110, $_10111101); $_11100111 = self::sc25519_mul($_1010000, $_10010111); $_11101011 = self::sc25519_mul($_100, $_11100111); $_11110101 = self::sc25519_mul($_1010, $_11101011); $recip = self::sc25519_mul($_1011, $_11110101); $recip = self::sc25519_sqmul($recip, 126, $_1010011); $recip = self::sc25519_sqmul($recip, 9, $_10); $recip = self::sc25519_mul($recip, $_11110101); $recip = self::sc25519_sqmul($recip, 7, $_1100111); $recip = self::sc25519_sqmul($recip, 9, $_11110101); $recip = self::sc25519_sqmul($recip, 11, $_10111101); $recip = self::sc25519_sqmul($recip, 8, $_11100111); $recip = self::sc25519_sqmul($recip, 9, $_1101011); $recip = self::sc25519_sqmul($recip, 6, $_1011); $recip = self::sc25519_sqmul($recip, 14, $_10010011); $recip = self::sc25519_sqmul($recip, 10, $_1100011); $recip = self::sc25519_sqmul($recip, 9, $_10010111); $recip = self::sc25519_sqmul($recip, 10, $_11110101); $recip = self::sc25519_sqmul($recip, 8, $_11010011); return self::sc25519_sqmul($recip, 8, $_11101011); } /** * @param string $s * @return string */ public static function clamp($s) { $s_ = self::stringToIntArray($s); $s_[0] &= 248; $s_[31] |= 64; $s_[31] &= 128; return self::intArrayToString($s_); } /** * Ensure limbs are less than 28 bits long to prevent float promotion. * * This uses a constant-time conditional swap under the hood. * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_normalize(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $x = (PHP_INT_SIZE << 3) - 1; // 31 or 63 $g = self::fe_copy($f); for ($i = 0; $i < 10; ++$i) { $mask = -(($g[$i] >> $x) & 1); /* * Get two candidate normalized values for $g[$i], depending on the sign of $g[$i]: */ $a = $g[$i] & 0x7ffffff; $b = -((-$g[$i]) & 0x7ffffff); /* * Return the appropriate candidate value, based on the sign of the original input: * * The following is equivalent to this ternary: * * $g[$i] = (($g[$i] >> $x) & 1) ? $a : $b; * * Except what's written doesn't contain timing leaks. */ $g[$i] = ($a ^ (($a ^ $b) & $mask)); } return $g; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/Ge/P3.php���������������������������������������������������������������������������0000644�����������������00000004312�15021200076�0010445 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P3', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_P3 */ class ParagonIE_Sodium_Core_Curve25519_Ge_P3 { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $T; /** * ParagonIE_Sodium_Core_Curve25519_Ge_P3 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t */ public function __construct( $x = null, $y = null, $z = null, $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($t instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->T = $t; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/Ge/P2.php���������������������������������������������������������������������������0000644�����������������00000003375�15021200076�0010454 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P2', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_P2 */ class ParagonIE_Sodium_Core_Curve25519_Ge_P2 { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * ParagonIE_Sodium_Core_Curve25519_Ge_P2 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z */ public function __construct( $x = null, $y = null, $z = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Z = $z; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/Ge/P1p1.php�������������������������������������������������������������������������0000644�����������������00000004321�15021200076�0010704 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P1p1', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 */ class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $T; /** * ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t */ public function __construct( $x = null, $y = null, $z = null, $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($x instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($y instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($t instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->T = $t; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/Ge/Precomp.php����������������������������������������������������������������������0000644�����������������00000003562�15021200076�0011576 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Precomp', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp */ class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $yplusx; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $yminusx; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $xy2d; /** * ParagonIE_Sodium_Core_Curve25519_Ge_Precomp constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $yplusx * @param ParagonIE_Sodium_Core_Curve25519_Fe $yminusx * @param ParagonIE_Sodium_Core_Curve25519_Fe $xy2d */ public function __construct( $yplusx = null, $yminusx = null, $xy2d = null ) { if ($yplusx === null) { $yplusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($yplusx instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->yplusx = $yplusx; if ($yminusx === null) { $yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($yminusx instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->yminusx = $yminusx; if ($xy2d === null) { $xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($xy2d instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->xy2d = $xy2d; } } ����������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/Ge/Cached.php�����������������������������������������������������������������������0000644�����������������00000004502�15021200076�0011333 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Cached', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached */ class ParagonIE_Sodium_Core_Curve25519_Ge_Cached { /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $YplusX; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $YminusX; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core_Curve25519_Fe */ public $T2d; /** * ParagonIE_Sodium_Core_Curve25519_Ge_Cached constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YplusX * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YminusX * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $Z * @param ParagonIE_Sodium_Core_Curve25519_Fe|null $T2d */ public function __construct( $YplusX = null, $YminusX = null, $Z = null, $T2d = null ) { if ($YplusX === null) { $YplusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($YplusX instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->YplusX = $YplusX; if ($YminusX === null) { $YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($YminusX instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->YminusX = $YminusX; if ($Z === null) { $Z = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->Z = $Z; if ($T2d === null) { $T2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); } if (!($T2d instanceof ParagonIE_Sodium_Core_Curve25519_Fe)) { throw new TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe'); } $this->T2d = $T2d; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/Fe.php������������������������������������������������������������������������������0000644�����������������00000006021�15021200076�0010161 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_Fe', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_Fe * * This represents a Field Element */ class ParagonIE_Sodium_Core_Curve25519_Fe implements ArrayAccess { /** * @var array<int, int> */ protected $container = array(); /** * @var int */ protected $size = 10; /** * @internal You should not use this directly from another application * * @param array<int, int> $array * @param bool $save_indexes * @return self */ public static function fromArray($array, $save_indexes = null) { $count = count($array); if ($save_indexes) { $keys = array_keys($array); } else { $keys = range(0, $count - 1); } $array = array_values($array); /** @var array<int, int> $keys */ $obj = new ParagonIE_Sodium_Core_Curve25519_Fe(); if ($save_indexes) { for ($i = 0; $i < $count; ++$i) { $obj->offsetSet($keys[$i], $array[$i]); } } else { for ($i = 0; $i < $count; ++$i) { $obj->offsetSet($i, $array[$i]); } } return $obj; } /** * @internal You should not use this directly from another application * * @param int|null $offset * @param int $value * @return void * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if (!is_int($value)) { throw new InvalidArgumentException('Expected an integer'); } if (is_null($offset)) { $this->container[] = $value; } else { $this->container[$offset] = $value; } } /** * @internal You should not use this directly from another application * * @param int $offset * @return bool * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return void * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return int * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetGet($offset) { if (!isset($this->container[$offset])) { $this->container[$offset] = 0; } return (int) ($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @return array */ public function __debugInfo() { return array(implode(', ', $this->container)); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/README.md���������������������������������������������������������������������������0000644�����������������00000000332�15021200076�0010374 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Curve25519 Data Structures These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h). ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Curve25519/H.php�������������������������������������������������������������������������������0000644�����������������00000327571�15021200076�0010036 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Curve25519_H', false)) { return; } /** * Class ParagonIE_Sodium_Core_Curve25519_H * * This just contains the constants in the ref10/base.h file */ class ParagonIE_Sodium_Core_Curve25519_H extends ParagonIE_Sodium_Core_Util { /** * See: libsodium's crypto_core/curve25519/ref10/base.h * * @var array<int, array<int, array<int, array<int, int>>>> Basically, int[32][8][3][10] */ protected static $base = array( array( array( array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605), array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378), array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546), ), array( array(-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303), array(-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081), array(26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697), ), array( array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024), array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574), array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357), ), array( array(-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540), array(23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397), array(7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325), ), array( array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380), array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306), array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942), ), array( array(-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777), array(-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737), array(-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652), ), array( array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766), array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701), array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300), ), array( array(14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726), array(-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955), array(27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425), ), ), array( array( array(-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171), array(27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510), array(17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660), ), array( array(-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639), array(29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963), array(5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950), ), array( array(-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568), array(12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335), array(25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628), ), array( array(-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007), array(-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772), array(-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653), ), array( array(2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567), array(13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686), array(21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372), ), array( array(-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887), array(-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954), array(-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953), ), array( array(24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833), array(-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532), array(-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876), ), array( array(2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268), array(33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214), array(1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038), ), ), array( array( array(6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800), array(4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645), array(-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664), ), array( array(1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933), array(-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182), array(-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222), ), array( array(-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991), array(20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880), array(9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092), ), array( array(-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295), array(19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788), array(8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553), ), array( array(-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026), array(11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347), array(-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033), ), array( array(-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395), array(-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278), array(1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890), ), array( array(32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995), array(-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596), array(-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891), ), array( array(31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060), array(11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608), array(-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606), ), ), array( array( array(7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389), array(-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016), array(-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341), ), array( array(-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505), array(14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553), array(-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655), ), array( array(15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220), array(12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631), array(-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099), ), array( array(26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556), array(14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749), array(236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930), ), array( array(1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391), array(5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253), array(20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066), ), array( array(24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958), array(-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082), array(-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383), ), array( array(-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521), array(-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807), array(23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948), ), array( array(9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134), array(-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455), array(27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629), ), ), array( array( array(-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069), array(-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746), array(24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919), ), array( array(11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837), array(8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906), array(-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771), ), array( array(-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817), array(10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098), array(10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409), ), array( array(-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504), array(-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727), array(28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420), ), array( array(-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003), array(-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605), array(-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384), ), array( array(-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701), array(-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683), array(29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708), ), array( array(-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563), array(-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260), array(-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387), ), array( array(-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672), array(23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686), array(-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665), ), ), array( array( array(11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182), array(-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277), array(14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628), ), array( array(-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474), array(-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539), array(-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822), ), array( array(-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970), array(19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756), array(-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508), ), array( array(-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683), array(-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655), array(-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158), ), array( array(-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125), array(-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839), array(-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664), ), array( array(27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294), array(-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899), array(-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070), ), array( array(3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294), array(-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949), array(-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083), ), array( array(31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420), array(-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940), array(29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396), ), ), array( array( array(-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567), array(20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127), array(-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294), ), array( array(-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887), array(22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964), array(16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195), ), array( array(9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244), array(24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999), array(-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762), ), array( array(-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274), array(-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236), array(-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605), ), array( array(-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761), array(-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884), array(-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482), ), array( array(-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638), array(-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490), array(-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170), ), array( array(5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736), array(10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124), array(-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392), ), array( array(8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029), array(6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048), array(28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958), ), ), array( array( array(24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593), array(26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071), array(-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692), ), array( array(11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687), array(-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441), array(-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001), ), array( array(-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460), array(-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007), array(-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762), ), array( array(15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005), array(-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674), array(4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035), ), array( array(7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590), array(-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957), array(-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812), ), array( array(33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740), array(-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122), array(-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158), ), array( array(8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885), array(26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140), array(19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857), ), array( array(801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155), array(19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260), array(19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483), ), ), array( array( array(-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677), array(32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815), array(22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751), ), array( array(-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203), array(-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208), array(1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230), ), array( array(16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850), array(-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389), array(-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968), ), array( array(-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689), array(14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880), array(5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304), ), array( array(30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632), array(-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412), array(20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566), ), array( array(-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038), array(-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232), array(-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943), ), array( array(17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856), array(23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738), array(15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971), ), array( array(-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718), array(-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697), array(-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883), ), ), array( array( array(5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912), array(-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358), array(3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849), ), array( array(29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307), array(-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977), array(-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335), ), array( array(-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644), array(-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616), array(-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735), ), array( array(-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099), array(29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341), array(-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336), ), array( array(-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646), array(31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425), array(-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388), ), array( array(-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743), array(-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822), array(-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462), ), array( array(18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985), array(9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702), array(-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797), ), array( array(21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293), array(27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100), array(19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688), ), ), array( array( array(12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186), array(2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610), array(-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707), ), array( array(7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220), array(915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025), array(32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044), ), array( array(32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992), array(-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027), array(21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197), ), array( array(8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901), array(31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952), array(19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878), ), array( array(-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390), array(32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730), array(2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730), ), array( array(-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180), array(-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272), array(-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715), ), array( array(-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970), array(-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772), array(-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865), ), array( array(15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750), array(20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373), array(32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348), ), ), array( array( array(9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144), array(-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195), array(5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086), ), array( array(-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684), array(-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518), array(-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233), ), array( array(-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793), array(-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794), array(580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435), ), array( array(23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921), array(13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518), array(2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563), ), array( array(14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278), array(-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024), array(4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030), ), array( array(10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783), array(27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717), array(6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844), ), array( array(14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333), array(16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048), array(22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760), ), array( array(-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760), array(-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757), array(-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112), ), ), array( array( array(-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468), array(3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184), array(10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289), ), array( array(15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066), array(24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882), array(13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226), ), array( array(16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101), array(29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279), array(-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811), ), array( array(27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709), array(20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714), array(-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121), ), array( array(9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464), array(12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847), array(13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400), ), array( array(4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414), array(-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158), array(17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045), ), array( array(-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415), array(-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459), array(-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079), ), array( array(21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412), array(-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743), array(-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836), ), ), array( array( array(12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022), array(18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429), array(-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065), ), array( array(30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861), array(10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000), array(-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101), ), array( array(32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815), array(29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642), array(10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966), ), array( array(25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574), array(-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742), array(-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689), ), array( array(12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020), array(-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772), array(3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982), ), array( array(-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953), array(-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218), array(-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265), ), array( array(29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073), array(-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325), array(-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798), ), array( array(-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870), array(-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863), array(-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927), ), ), array( array( array(-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267), array(-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663), array(22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862), ), array( array(-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673), array(15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943), array(15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020), ), array( array(-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238), array(11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064), array(14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795), ), array( array(15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052), array(-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904), array(29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531), ), array( array(-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979), array(-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841), array(10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431), ), array( array(10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324), array(-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940), array(10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320), ), array( array(-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184), array(14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114), array(30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878), ), array( array(12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784), array(-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091), array(-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585), ), ), array( array( array(-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208), array(10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864), array(17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661), ), array( array(7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233), array(26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212), array(-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525), ), array( array(-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068), array(9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397), array(-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988), ), array( array(5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889), array(32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038), array(14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697), ), array( array(20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875), array(-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905), array(-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656), ), array( array(11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818), array(27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714), array(10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203), ), array( array(20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931), array(-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024), array(-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084), ), array( array(-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204), array(20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817), array(27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667), ), ), array( array( array(11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504), array(-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768), array(-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255), ), array( array(6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790), array(1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438), array(-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333), ), array( array(17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971), array(31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905), array(29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409), ), array( array(12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409), array(6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499), array(-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363), ), array( array(28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664), array(-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324), array(-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940), ), array( array(13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990), array(-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914), array(-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290), ), array( array(24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257), array(-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433), array(-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236), ), array( array(-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045), array(11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093), array(-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347), ), ), array( array( array(-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191), array(-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507), array(-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906), ), array( array(3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018), array(-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109), array(-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926), ), array( array(-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528), array(8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625), array(-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286), ), array( array(2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033), array(27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866), array(21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896), ), array( array(30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075), array(26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347), array(-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437), ), array( array(-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165), array(-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588), array(-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193), ), array( array(-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017), array(-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883), array(21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961), ), array( array(8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043), array(29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663), array(-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362), ), ), array( array( array(-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860), array(2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466), array(-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063), ), array( array(-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997), array(-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295), array(-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369), ), array( array(9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385), array(18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109), array(2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906), ), array( array(4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424), array(-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185), array(7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962), ), array( array(-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325), array(10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593), array(696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404), ), array( array(-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644), array(17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801), array(26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804), ), array( array(-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884), array(-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577), array(-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849), ), array( array(32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473), array(-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644), array(-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319), ), ), array( array( array(-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599), array(-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768), array(-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084), ), array( array(-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328), array(-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369), array(20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920), ), array( array(12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815), array(-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025), array(-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397), ), array( array(-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448), array(6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981), array(30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165), ), array( array(32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501), array(17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073), array(-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861), ), array( array(14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845), array(-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211), array(18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870), ), array( array(10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096), array(33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803), array(-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168), ), array( array(30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965), array(-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505), array(18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598), ), ), array( array( array(5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782), array(5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900), array(-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479), ), array( array(-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208), array(8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232), array(17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719), ), array( array(16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271), array(-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326), array(-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132), ), array( array(14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300), array(8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570), array(15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670), ), array( array(-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994), array(-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913), array(31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317), ), array( array(-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730), array(842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096), array(-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078), ), array( array(-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411), array(-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905), array(-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654), ), array( array(-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870), array(-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498), array(12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579), ), ), array( array( array(14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677), array(10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647), array(-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743), ), array( array(-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468), array(21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375), array(-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155), ), array( array(6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725), array(-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612), array(-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943), ), array( array(-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944), array(30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928), array(9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406), ), array( array(22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139), array(-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963), array(-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693), ), array( array(1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734), array(-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680), array(-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410), ), array( array(-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931), array(-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654), array(22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710), ), array( array(29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180), array(-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684), array(-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895), ), ), array( array( array(22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501), array(-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413), array(6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880), ), array( array(-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874), array(22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962), array(-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899), ), array( array(21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152), array(9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063), array(7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080), ), array( array(-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146), array(-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183), array(-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133), ), array( array(-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421), array(-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622), array(-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197), ), array( array(2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663), array(31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753), array(4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755), ), array( array(-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862), array(-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118), array(26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171), ), array( array(15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380), array(16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824), array(28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270), ), ), array( array( array(-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438), array(-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584), array(-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562), ), array( array(30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471), array(18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610), array(19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269), ), array( array(-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650), array(14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369), array(19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461), ), array( array(30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462), array(-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793), array(-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218), ), array( array(-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226), array(18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019), array(-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037), ), array( array(31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171), array(-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132), array(-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841), ), array( array(21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181), array(-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210), array(-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040), ), array( array(3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935), array(24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105), array(-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814), ), ), array( array( array(793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852), array(5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581), array(-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646), ), array( array(10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844), array(10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025), array(27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453), ), array( array(-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068), array(4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192), array(-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921), ), array( array(-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259), array(-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426), array(-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072), ), array( array(-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305), array(13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832), array(28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943), ), array( array(-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011), array(24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447), array(17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494), ), array( array(-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245), array(-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859), array(28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915), ), array( array(16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707), array(10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848), array(-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224), ), ), array( array( array(-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391), array(15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215), array(-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101), ), array( array(23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713), array(21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849), array(-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930), ), array( array(-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940), array(-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031), array(-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404), ), array( array(-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243), array(-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116), array(-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525), ), array( array(-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509), array(-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883), array(15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865), ), array( array(-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660), array(4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273), array(-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138), ), array( array(-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560), array(-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135), array(2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941), ), array( array(-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739), array(18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756), array(-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819), ), ), array( array( array(-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347), array(-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028), array(21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075), ), array( array(16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799), array(-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609), array(-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817), ), array( array(-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989), array(-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523), array(4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278), ), array( array(31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045), array(19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377), array(24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480), ), array( array(17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016), array(510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426), array(18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525), ), array( array(13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396), array(9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080), array(12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892), ), array( array(15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275), array(11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074), array(20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140), ), array( array(-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717), array(-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101), array(24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127), ), ), array( array( array(-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632), array(-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415), array(-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160), ), array( array(31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876), array(22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625), array(-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478), ), array( array(27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164), array(26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595), array(-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248), ), array( array(-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858), array(15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193), array(8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184), ), array( array(-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942), array(-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635), array(21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948), ), array( array(11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935), array(-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415), array(-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416), ), array( array(-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018), array(4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778), array(366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659), ), array( array(-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385), array(18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503), array(476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329), ), ), array( array( array(20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056), array(-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838), array(24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948), ), array( array(-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691), array(-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118), array(-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517), ), array( array(-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269), array(-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904), array(-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589), ), array( array(-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193), array(-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910), array(-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930), ), array( array(-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667), array(25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481), array(-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876), ), array( array(22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640), array(-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278), array(-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112), ), array( array(26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272), array(17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012), array(-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221), ), array( array(30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046), array(13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345), array(-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310), ), ), array( array( array(19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937), array(31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636), array(-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008), ), array( array(-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429), array(-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576), array(31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066), ), array( array(-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490), array(-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104), array(33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053), ), array( array(31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275), array(-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511), array(22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095), ), array( array(-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439), array(23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939), array(-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424), ), array( array(2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310), array(3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608), array(-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079), ), array( array(-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101), array(21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418), array(18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576), ), array( array(30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356), array(9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996), array(-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099), ), ), array( array( array(-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728), array(-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658), array(-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242), ), array( array(-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001), array(-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766), array(18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373), ), array( array(26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458), array(-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628), array(-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657), ), array( array(-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062), array(25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616), array(31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014), ), array( array(24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383), array(-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814), array(-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718), ), array( array(30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417), array(2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222), array(33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444), ), array( array(-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597), array(23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970), array(1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799), ), array( array(-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647), array(13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511), array(-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032), ), ), array( array( array(9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834), array(-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461), array(29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062), ), array( array(-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516), array(-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547), array(-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240), ), array( array(-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038), array(-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741), array(16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103), ), array( array(-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747), array(-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323), array(31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016), ), array( array(-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373), array(15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228), array(-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141), ), array( array(16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399), array(11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831), array(-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376), ), array( array(-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313), array(-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958), array(-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577), ), array( array(-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743), array(29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684), array(-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476), ), ) ); /** * See: libsodium's crypto_core/curve25519/ref10/base2.h * * @var array basically int[8][3] */ protected static $base2 = array( array( array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605), array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378), array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546), ), array( array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024), array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574), array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357), ), array( array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380), array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306), array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942), ), array( array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766), array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701), array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300), ), array( array(-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877), array(-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951), array(4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784), ), array( array(-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436), array(25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918), array(23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877), ), array( array(-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800), array(-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305), array(-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300), ), array( array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876), array(-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619), array(-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683), ) ); /** * 37095705934669439343138083508754565189542113879843219016388785533085940283555 * * @var array<int, int> */ protected static $d = array( -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 ); /** * 2 * d = 16295367250680780974490674513165176452449235426866156013048779062215315747161 * * @var array<int, int> */ protected static $d2 = array( -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 ); /** * sqrt(-1) * * @var array<int, int> */ protected static $sqrtm1 = array( -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 ); /** * 1 / sqrt(a - d) * * @var array<int, int> */ protected static $invsqrtamd = array( 6111485, 4156064, -27798727, 12243468, -25904040, 120897, 20826367, -7060776, 6093568, -1986012 ); /** * sqrt(ad - 1) with a = -1 (mod p) * * @var array<int, int> */ protected static $sqrtadm1 = array( 24849947, -153582, -23613485, 6347715, -21072328, -667138, -25271143, -15367704, -870347, 14525639 ); /** * 1 - d ^ 2 * * @var array<int, int> */ protected static $onemsqd = array( 6275446, -16617371, -22938544, -3773710, 11667077, 7397348, -27922721, 1766195, -24433858, 672203 ); /** * (d - 1) ^ 2 * @var array<int, int> */ protected static $sqdmone = array( 15551795, -11097455, -13425098, -10125071, -11896535, 10178284, -26634327, 4729244, -5282110, -10116402 ); /* * 2^252+27742317777372353535851937790883648493 static const unsigned char L[] = { 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }; */ const L = "\xed\xd3\xf5\x5c\x1a\x63\x12\x58\xd6\x9c\xf7\xa2\xde\xf9\xde\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"; } ���������������������������������������������������������������������������������������������������������������������������������������Core/HSalsa20.php�����������������������������������������������������������������������������������0000644�����������������00000007131�15021200076�0007455 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_HSalsa20', false)) { return; } /** * Class ParagonIE_Sodium_Core_HSalsa20 */ abstract class ParagonIE_Sodium_Core_HSalsa20 extends ParagonIE_Sodium_Core_Salsa20 { /** * Calculate an hsalsa20 hash of a single block * * HSalsa20 doesn't have a counter and will never be used for more than * one block (used to derive a subkey for xsalsa20). * * @internal You should not use this directly from another application * * @param string $in * @param string $k * @param string|null $c * @return string * @throws TypeError */ public static function hsalsa20($in, $k, $c = null) { if ($c === null) { $x0 = 0x61707865; $x5 = 0x3320646e; $x10 = 0x79622d32; $x15 = 0x6b206574; } else { $x0 = self::load_4(self::substr($c, 0, 4)); $x5 = self::load_4(self::substr($c, 4, 4)); $x10 = self::load_4(self::substr($c, 8, 4)); $x15 = self::load_4(self::substr($c, 12, 4)); } $x1 = self::load_4(self::substr($k, 0, 4)); $x2 = self::load_4(self::substr($k, 4, 4)); $x3 = self::load_4(self::substr($k, 8, 4)); $x4 = self::load_4(self::substr($k, 12, 4)); $x11 = self::load_4(self::substr($k, 16, 4)); $x12 = self::load_4(self::substr($k, 20, 4)); $x13 = self::load_4(self::substr($k, 24, 4)); $x14 = self::load_4(self::substr($k, 28, 4)); $x6 = self::load_4(self::substr($in, 0, 4)); $x7 = self::load_4(self::substr($in, 4, 4)); $x8 = self::load_4(self::substr($in, 8, 4)); $x9 = self::load_4(self::substr($in, 12, 4)); for ($i = self::ROUNDS; $i > 0; $i -= 2) { $x4 ^= self::rotate($x0 + $x12, 7); $x8 ^= self::rotate($x4 + $x0, 9); $x12 ^= self::rotate($x8 + $x4, 13); $x0 ^= self::rotate($x12 + $x8, 18); $x9 ^= self::rotate($x5 + $x1, 7); $x13 ^= self::rotate($x9 + $x5, 9); $x1 ^= self::rotate($x13 + $x9, 13); $x5 ^= self::rotate($x1 + $x13, 18); $x14 ^= self::rotate($x10 + $x6, 7); $x2 ^= self::rotate($x14 + $x10, 9); $x6 ^= self::rotate($x2 + $x14, 13); $x10 ^= self::rotate($x6 + $x2, 18); $x3 ^= self::rotate($x15 + $x11, 7); $x7 ^= self::rotate($x3 + $x15, 9); $x11 ^= self::rotate($x7 + $x3, 13); $x15 ^= self::rotate($x11 + $x7, 18); $x1 ^= self::rotate($x0 + $x3, 7); $x2 ^= self::rotate($x1 + $x0, 9); $x3 ^= self::rotate($x2 + $x1, 13); $x0 ^= self::rotate($x3 + $x2, 18); $x6 ^= self::rotate($x5 + $x4, 7); $x7 ^= self::rotate($x6 + $x5, 9); $x4 ^= self::rotate($x7 + $x6, 13); $x5 ^= self::rotate($x4 + $x7, 18); $x11 ^= self::rotate($x10 + $x9, 7); $x8 ^= self::rotate($x11 + $x10, 9); $x9 ^= self::rotate($x8 + $x11, 13); $x10 ^= self::rotate($x9 + $x8, 18); $x12 ^= self::rotate($x15 + $x14, 7); $x13 ^= self::rotate($x12 + $x15, 9); $x14 ^= self::rotate($x13 + $x12, 13); $x15 ^= self::rotate($x14 + $x13, 18); } return self::store32_le($x0) . self::store32_le($x5) . self::store32_le($x10) . self::store32_le($x15) . self::store32_le($x6) . self::store32_le($x7) . self::store32_le($x8) . self::store32_le($x9); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AES.php����������������������������������������������������������������������������������������0000644�����������������00000037015�15021200076�0006554 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_AES', false)) { return; } /** * Bitsliced implementation of the AES block cipher. * * Based on the implementation provided by BearSSL. * * @internal This should only be used by sodium_compat */ class ParagonIE_Sodium_Core_AES extends ParagonIE_Sodium_Core_Util { /** * @var int[] AES round constants */ private static $Rcon = array( 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 ); /** * Mutates the values of $q! * * @param ParagonIE_Sodium_Core_AES_Block $q * @return void */ public static function sbox(ParagonIE_Sodium_Core_AES_Block $q) { /** * @var int $x0 * @var int $x1 * @var int $x2 * @var int $x3 * @var int $x4 * @var int $x5 * @var int $x6 * @var int $x7 */ $x0 = $q[7] & self::U32_MAX; $x1 = $q[6] & self::U32_MAX; $x2 = $q[5] & self::U32_MAX; $x3 = $q[4] & self::U32_MAX; $x4 = $q[3] & self::U32_MAX; $x5 = $q[2] & self::U32_MAX; $x6 = $q[1] & self::U32_MAX; $x7 = $q[0] & self::U32_MAX; $y14 = $x3 ^ $x5; $y13 = $x0 ^ $x6; $y9 = $x0 ^ $x3; $y8 = $x0 ^ $x5; $t0 = $x1 ^ $x2; $y1 = $t0 ^ $x7; $y4 = $y1 ^ $x3; $y12 = $y13 ^ $y14; $y2 = $y1 ^ $x0; $y5 = $y1 ^ $x6; $y3 = $y5 ^ $y8; $t1 = $x4 ^ $y12; $y15 = $t1 ^ $x5; $y20 = $t1 ^ $x1; $y6 = $y15 ^ $x7; $y10 = $y15 ^ $t0; $y11 = $y20 ^ $y9; $y7 = $x7 ^ $y11; $y17 = $y10 ^ $y11; $y19 = $y10 ^ $y8; $y16 = $t0 ^ $y11; $y21 = $y13 ^ $y16; $y18 = $x0 ^ $y16; /* * Non-linear section. */ $t2 = $y12 & $y15; $t3 = $y3 & $y6; $t4 = $t3 ^ $t2; $t5 = $y4 & $x7; $t6 = $t5 ^ $t2; $t7 = $y13 & $y16; $t8 = $y5 & $y1; $t9 = $t8 ^ $t7; $t10 = $y2 & $y7; $t11 = $t10 ^ $t7; $t12 = $y9 & $y11; $t13 = $y14 & $y17; $t14 = $t13 ^ $t12; $t15 = $y8 & $y10; $t16 = $t15 ^ $t12; $t17 = $t4 ^ $t14; $t18 = $t6 ^ $t16; $t19 = $t9 ^ $t14; $t20 = $t11 ^ $t16; $t21 = $t17 ^ $y20; $t22 = $t18 ^ $y19; $t23 = $t19 ^ $y21; $t24 = $t20 ^ $y18; $t25 = $t21 ^ $t22; $t26 = $t21 & $t23; $t27 = $t24 ^ $t26; $t28 = $t25 & $t27; $t29 = $t28 ^ $t22; $t30 = $t23 ^ $t24; $t31 = $t22 ^ $t26; $t32 = $t31 & $t30; $t33 = $t32 ^ $t24; $t34 = $t23 ^ $t33; $t35 = $t27 ^ $t33; $t36 = $t24 & $t35; $t37 = $t36 ^ $t34; $t38 = $t27 ^ $t36; $t39 = $t29 & $t38; $t40 = $t25 ^ $t39; $t41 = $t40 ^ $t37; $t42 = $t29 ^ $t33; $t43 = $t29 ^ $t40; $t44 = $t33 ^ $t37; $t45 = $t42 ^ $t41; $z0 = $t44 & $y15; $z1 = $t37 & $y6; $z2 = $t33 & $x7; $z3 = $t43 & $y16; $z4 = $t40 & $y1; $z5 = $t29 & $y7; $z6 = $t42 & $y11; $z7 = $t45 & $y17; $z8 = $t41 & $y10; $z9 = $t44 & $y12; $z10 = $t37 & $y3; $z11 = $t33 & $y4; $z12 = $t43 & $y13; $z13 = $t40 & $y5; $z14 = $t29 & $y2; $z15 = $t42 & $y9; $z16 = $t45 & $y14; $z17 = $t41 & $y8; /* * Bottom linear transformation. */ $t46 = $z15 ^ $z16; $t47 = $z10 ^ $z11; $t48 = $z5 ^ $z13; $t49 = $z9 ^ $z10; $t50 = $z2 ^ $z12; $t51 = $z2 ^ $z5; $t52 = $z7 ^ $z8; $t53 = $z0 ^ $z3; $t54 = $z6 ^ $z7; $t55 = $z16 ^ $z17; $t56 = $z12 ^ $t48; $t57 = $t50 ^ $t53; $t58 = $z4 ^ $t46; $t59 = $z3 ^ $t54; $t60 = $t46 ^ $t57; $t61 = $z14 ^ $t57; $t62 = $t52 ^ $t58; $t63 = $t49 ^ $t58; $t64 = $z4 ^ $t59; $t65 = $t61 ^ $t62; $t66 = $z1 ^ $t63; $s0 = $t59 ^ $t63; $s6 = $t56 ^ ~$t62; $s7 = $t48 ^ ~$t60; $t67 = $t64 ^ $t65; $s3 = $t53 ^ $t66; $s4 = $t51 ^ $t66; $s5 = $t47 ^ $t65; $s1 = $t64 ^ ~$s3; $s2 = $t55 ^ ~$t67; $q[7] = $s0 & self::U32_MAX; $q[6] = $s1 & self::U32_MAX; $q[5] = $s2 & self::U32_MAX; $q[4] = $s3 & self::U32_MAX; $q[3] = $s4 & self::U32_MAX; $q[2] = $s5 & self::U32_MAX; $q[1] = $s6 & self::U32_MAX; $q[0] = $s7 & self::U32_MAX; } /** * Mutates the values of $q! * * @param ParagonIE_Sodium_Core_AES_Block $q * @return void */ public static function invSbox(ParagonIE_Sodium_Core_AES_Block $q) { self::processInversion($q); self::sbox($q); self::processInversion($q); } /** * This is some boilerplate code needed to invert an S-box. Rather than repeat the code * twice, I moved it to a protected method. * * Mutates $q * * @param ParagonIE_Sodium_Core_AES_Block $q * @return void */ protected static function processInversion(ParagonIE_Sodium_Core_AES_Block $q) { $q0 = (~$q[0]) & self::U32_MAX; $q1 = (~$q[1]) & self::U32_MAX; $q2 = $q[2] & self::U32_MAX; $q3 = $q[3] & self::U32_MAX; $q4 = $q[4] & self::U32_MAX; $q5 = (~$q[5]) & self::U32_MAX; $q6 = (~$q[6]) & self::U32_MAX; $q7 = $q[7] & self::U32_MAX; $q[7] = ($q1 ^ $q4 ^ $q6) & self::U32_MAX; $q[6] = ($q0 ^ $q3 ^ $q5) & self::U32_MAX; $q[5] = ($q7 ^ $q2 ^ $q4) & self::U32_MAX; $q[4] = ($q6 ^ $q1 ^ $q3) & self::U32_MAX; $q[3] = ($q5 ^ $q0 ^ $q2) & self::U32_MAX; $q[2] = ($q4 ^ $q7 ^ $q1) & self::U32_MAX; $q[1] = ($q3 ^ $q6 ^ $q0) & self::U32_MAX; $q[0] = ($q2 ^ $q5 ^ $q7) & self::U32_MAX; } /** * @param int $x * @return int */ public static function subWord($x) { $q = ParagonIE_Sodium_Core_AES_Block::fromArray( array($x, $x, $x, $x, $x, $x, $x, $x) ); $q->orthogonalize(); self::sbox($q); $q->orthogonalize(); return $q[0] & self::U32_MAX; } /** * Calculate the key schedule from a given random key * * @param string $key * @return ParagonIE_Sodium_Core_AES_KeySchedule * @throws SodiumException */ public static function keySchedule($key) { $key_len = self::strlen($key); switch ($key_len) { case 16: $num_rounds = 10; break; case 24: $num_rounds = 12; break; case 32: $num_rounds = 14; break; default: throw new SodiumException('Invalid key length: ' . $key_len); } $skey = array(); $comp_skey = array(); $nk = $key_len >> 2; $nkf = ($num_rounds + 1) << 2; $tmp = 0; for ($i = 0; $i < $nk; ++$i) { $tmp = self::load_4(self::substr($key, $i << 2, 4)); $skey[($i << 1)] = $tmp; $skey[($i << 1) + 1] = $tmp; } for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) { if ($j === 0) { $tmp = (($tmp & 0xff) << 24) | ($tmp >> 8); $tmp = (self::subWord($tmp) ^ self::$Rcon[$k]) & self::U32_MAX; } elseif ($nk > 6 && $j === 4) { $tmp = self::subWord($tmp); } $tmp ^= $skey[($i - $nk) << 1]; $skey[($i << 1)] = $tmp & self::U32_MAX; $skey[($i << 1) + 1] = $tmp & self::U32_MAX; if (++$j === $nk) { /** @psalm-suppress LoopInvalidation */ $j = 0; ++$k; } } for ($i = 0; $i < $nkf; $i += 4) { $q = ParagonIE_Sodium_Core_AES_Block::fromArray( array_slice($skey, $i << 1, 8) ); $q->orthogonalize(); // We have to overwrite $skey since we're not using C pointers like BearSSL did for ($j = 0; $j < 8; ++$j) { $skey[($i << 1) + $j] = $q[$j]; } } for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) { $comp_skey[$i] = ($skey[$j] & 0x55555555) | ($skey[$j + 1] & 0xAAAAAAAA); } return new ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds); } /** * Mutates $q * * @param ParagonIE_Sodium_Core_AES_KeySchedule $skey * @param ParagonIE_Sodium_Core_AES_Block $q * @param int $offset * @return void */ public static function addRoundKey( ParagonIE_Sodium_Core_AES_Block $q, ParagonIE_Sodium_Core_AES_KeySchedule $skey, $offset = 0 ) { $block = $skey->getRoundKey($offset); for ($j = 0; $j < 8; ++$j) { $q[$j] = ($q[$j] ^ $block[$j]) & ParagonIE_Sodium_Core_Util::U32_MAX; } } /** * This mainly exists for testing, as we need the round key features for AEGIS. * * @param string $message * @param string $key * @return string * @throws SodiumException */ public static function decryptBlockECB($message, $key) { if (self::strlen($message) !== 16) { throw new SodiumException('decryptBlockECB() expects a 16 byte message'); } $skey = self::keySchedule($key)->expand(); $q = ParagonIE_Sodium_Core_AES_Block::init(); $q[0] = self::load_4(self::substr($message, 0, 4)); $q[2] = self::load_4(self::substr($message, 4, 4)); $q[4] = self::load_4(self::substr($message, 8, 4)); $q[6] = self::load_4(self::substr($message, 12, 4)); $q->orthogonalize(); self::bitsliceDecryptBlock($skey, $q); $q->orthogonalize(); return self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]); } /** * This mainly exists for testing, as we need the round key features for AEGIS. * * @param string $message * @param string $key * @return string * @throws SodiumException */ public static function encryptBlockECB($message, $key) { if (self::strlen($message) !== 16) { throw new SodiumException('encryptBlockECB() expects a 16 byte message'); } $comp_skey = self::keySchedule($key); $skey = $comp_skey->expand(); $q = ParagonIE_Sodium_Core_AES_Block::init(); $q[0] = self::load_4(self::substr($message, 0, 4)); $q[2] = self::load_4(self::substr($message, 4, 4)); $q[4] = self::load_4(self::substr($message, 8, 4)); $q[6] = self::load_4(self::substr($message, 12, 4)); $q->orthogonalize(); self::bitsliceEncryptBlock($skey, $q); $q->orthogonalize(); return self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]); } /** * Mutates $q * * @param ParagonIE_Sodium_Core_AES_Expanded $skey * @param ParagonIE_Sodium_Core_AES_Block $q * @return void */ public static function bitsliceEncryptBlock( ParagonIE_Sodium_Core_AES_Expanded $skey, ParagonIE_Sodium_Core_AES_Block $q ) { self::addRoundKey($q, $skey); for ($u = 1; $u < $skey->getNumRounds(); ++$u) { self::sbox($q); $q->shiftRows(); $q->mixColumns(); self::addRoundKey($q, $skey, ($u << 3)); } self::sbox($q); $q->shiftRows(); self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3)); } /** * @param string $x * @param string $y * @return string */ public static function aesRound($x, $y) { $q = ParagonIE_Sodium_Core_AES_Block::init(); $q[0] = self::load_4(self::substr($x, 0, 4)); $q[2] = self::load_4(self::substr($x, 4, 4)); $q[4] = self::load_4(self::substr($x, 8, 4)); $q[6] = self::load_4(self::substr($x, 12, 4)); $rk = ParagonIE_Sodium_Core_AES_Block::init(); $rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4)); $rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4)); $rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4)); $rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4)); $q->orthogonalize(); self::sbox($q); $q->shiftRows(); $q->mixColumns(); $q->orthogonalize(); // add round key without key schedule: for ($i = 0; $i < 8; ++$i) { $q[$i] ^= $rk[$i]; } return self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]); } /** * Process two AES blocks in one shot. * * @param string $b0 First AES block * @param string $rk0 First round key * @param string $b1 Second AES block * @param string $rk1 Second round key * @return string[] */ public static function doubleRound($b0, $rk0, $b1, $rk1) { $q = ParagonIE_Sodium_Core_AES_Block::init(); // First block $q[0] = self::load_4(self::substr($b0, 0, 4)); $q[2] = self::load_4(self::substr($b0, 4, 4)); $q[4] = self::load_4(self::substr($b0, 8, 4)); $q[6] = self::load_4(self::substr($b0, 12, 4)); // Second block $q[1] = self::load_4(self::substr($b1, 0, 4)); $q[3] = self::load_4(self::substr($b1, 4, 4)); $q[5] = self::load_4(self::substr($b1, 8, 4)); $q[7] = self::load_4(self::substr($b1, 12, 4));; $rk = ParagonIE_Sodium_Core_AES_Block::init(); // First round key $rk[0] = self::load_4(self::substr($rk0, 0, 4)); $rk[2] = self::load_4(self::substr($rk0, 4, 4)); $rk[4] = self::load_4(self::substr($rk0, 8, 4)); $rk[6] = self::load_4(self::substr($rk0, 12, 4)); // Second round key $rk[1] = self::load_4(self::substr($rk1, 0, 4)); $rk[3] = self::load_4(self::substr($rk1, 4, 4)); $rk[5] = self::load_4(self::substr($rk1, 8, 4)); $rk[7] = self::load_4(self::substr($rk1, 12, 4)); $q->orthogonalize(); self::sbox($q); $q->shiftRows(); $q->mixColumns(); $q->orthogonalize(); // add round key without key schedule: for ($i = 0; $i < 8; ++$i) { $q[$i] ^= $rk[$i]; } return array( self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]), self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]), ); } /** * @param ParagonIE_Sodium_Core_AES_Expanded $skey * @param ParagonIE_Sodium_Core_AES_Block $q * @return void */ public static function bitsliceDecryptBlock( ParagonIE_Sodium_Core_AES_Expanded $skey, ParagonIE_Sodium_Core_AES_Block $q ) { self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3)); for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) { $q->inverseShiftRows(); self::invSbox($q); self::addRoundKey($q, $skey, ($u << 3)); $q->inverseMixColumns(); } $q->inverseShiftRows(); self::invSbox($q); self::addRoundKey($q, $skey, ($u << 3)); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Poly1305.php�����������������������������������������������������������������������������������0000644�����������������00000003046�15021200076�0007375 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Poly1305', false)) { return; } /** * Class ParagonIE_Sodium_Core_Poly1305 */ abstract class ParagonIE_Sodium_Core_Poly1305 extends ParagonIE_Sodium_Core_Util { const BLOCK_SIZE = 16; /** * @internal You should not use this directly from another application * * @param string $m * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function onetimeauth($m, $key) { if (self::strlen($key) < 32) { throw new InvalidArgumentException( 'Key must be 32 bytes long.' ); } $state = new ParagonIE_Sodium_Core_Poly1305_State( self::substr($key, 0, 32) ); return $state ->update($m) ->finish(); } /** * @internal You should not use this directly from another application * * @param string $mac * @param string $m * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ public static function onetimeauth_verify($mac, $m, $key) { if (self::strlen($key) < 32) { throw new InvalidArgumentException( 'Key must be 32 bytes long.' ); } $state = new ParagonIE_Sodium_Core_Poly1305_State( self::substr($key, 0, 32) ); $calc = $state ->update($m) ->finish(); return self::verify_16($calc, $mac); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AES/Block.php����������������������������������������������������������������������������������0000644�����������������00000024342�15021200076�0007605 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_AES_Block', false)) { return; } /** * @internal This should only be used by sodium_compat */ class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray { /** * @var array<int, int> */ protected $values = array(); /** * @var int */ protected $size; /** * @param int $size */ public function __construct($size = 8) { parent::__construct($size); $this->size = $size; $this->values = array_fill(0, $size, 0); } /** * @return self */ public static function init() { return new self(8); } /** * @internal You should not use this directly from another application * * @param array<int, int> $array * @param bool $save_indexes * @return self * * @psalm-suppress MethodSignatureMismatch */ #[ReturnTypeWillChange] public static function fromArray($array, $save_indexes = null) { $count = count($array); if ($save_indexes) { $keys = array_keys($array); } else { $keys = range(0, $count - 1); } $array = array_values($array); /** @var array<int, int> $keys */ $obj = new ParagonIE_Sodium_Core_AES_Block(); if ($save_indexes) { for ($i = 0; $i < $count; ++$i) { $obj->offsetSet($keys[$i], $array[$i]); } } else { for ($i = 0; $i < $count; ++$i) { $obj->offsetSet($i, $array[$i]); } } return $obj; } /** * @internal You should not use this directly from another application * * @param int|null $offset * @param int $value * @return void * * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if (!is_int($value)) { throw new InvalidArgumentException('Expected an integer'); } if (is_null($offset)) { $this->values[] = $value; } else { $this->values[$offset] = $value; } } /** * @internal You should not use this directly from another application * * @param int $offset * @return bool * * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->values[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return void * * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->values[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return int * * @psalm-suppress MethodSignatureMismatch * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetGet($offset) { if (!isset($this->values[$offset])) { $this->values[$offset] = 0; } return (int) ($this->values[$offset]); } /** * @internal You should not use this directly from another application * * @return array */ public function __debugInfo() { $out = array(); foreach ($this->values as $v) { $out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT); } return array(implode(', ', $out)); /* return array(implode(', ', $this->values)); */ } /** * @param int $cl low bit mask * @param int $ch high bit mask * @param int $s shift * @param int $x index 1 * @param int $y index 2 * @return self */ public function swapN($cl, $ch, $s, $x, $y) { static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX; $a = $this->values[$x] & $u32mask; $b = $this->values[$y] & $u32mask; // (x) = (a & cl) | ((b & cl) << (s)); $this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask); // (y) = ((a & ch) >> (s)) | (b & ch); $this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch); return $this; } /** * @param int $x index 1 * @param int $y index 2 * @return self */ public function swap2($x, $y) { return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y); } /** * @param int $x index 1 * @param int $y index 2 * @return self */ public function swap4($x, $y) { return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y); } /** * @param int $x index 1 * @param int $y index 2 * @return self */ public function swap8($x, $y) { return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y); } /** * @return self */ public function orthogonalize() { return $this ->swap2(0, 1) ->swap2(2, 3) ->swap2(4, 5) ->swap2(6, 7) ->swap4(0, 2) ->swap4(1, 3) ->swap4(4, 6) ->swap4(5, 7) ->swap8(0, 4) ->swap8(1, 5) ->swap8(2, 6) ->swap8(3, 7); } /** * @return self */ public function shiftRows() { for ($i = 0; $i < 8; ++$i) { $x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX; $this->values[$i] = ( ($x & 0x000000FF) | (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6) | (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4) | (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2) ) & ParagonIE_Sodium_Core_Util::U32_MAX; } return $this; } /** * @param int $x * @return int */ public static function rotr16($x) { return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16); } /** * @return self */ public function mixColumns() { $q0 = $this->values[0]; $q1 = $this->values[1]; $q2 = $this->values[2]; $q3 = $this->values[3]; $q4 = $this->values[4]; $q5 = $this->values[5]; $q6 = $this->values[6]; $q7 = $this->values[7]; $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0); $this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1); $this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2); $this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3); $this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4); $this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5); $this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6); $this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7); return $this; } /** * @return self */ public function inverseMixColumns() { $q0 = $this->values[0]; $q1 = $this->values[1]; $q2 = $this->values[2]; $q3 = $this->values[3]; $q4 = $this->values[4]; $q5 = $this->values[5]; $q6 = $this->values[6]; $q7 = $this->values[7]; $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX; $this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5); $this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6); $this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7); $this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7); $this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6); $this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7); $this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7); $this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7); return $this; } /** * @return self */ public function inverseShiftRows() { for ($i = 0; $i < 8; ++$i) { $x = $this->values[$i]; $this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & ( ($x & 0x000000FF) | (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6) | (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4) | (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2) ); } return $this; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AES/Expanded.php�������������������������������������������������������������������������������0000644�����������������00000000460�15021200076�0010276 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_AES_Expanded', false)) { return; } /** * @internal This should only be used by sodium_compat */ class ParagonIE_Sodium_Core_AES_Expanded extends ParagonIE_Sodium_Core_AES_KeySchedule { /** @var bool $expanded */ protected $expanded = true; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AES/KeySchedule.php����������������������������������������������������������������������������0000644�����������������00000003531�15021200076�0010755 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_AES_KeySchedule', false)) { return; } /** * @internal This should only be used by sodium_compat */ class ParagonIE_Sodium_Core_AES_KeySchedule { /** @var array<int, int> $skey -- has size 120 */ protected $skey; /** @var bool $expanded */ protected $expanded = false; /** @var int $numRounds */ private $numRounds; /** * @param array $skey * @param int $numRounds */ public function __construct(array $skey, $numRounds = 10) { $this->skey = $skey; $this->numRounds = $numRounds; } /** * Get a value at an arbitrary index. Mostly used for unit testing. * * @param int $i * @return int */ public function get($i) { return $this->skey[$i]; } /** * @return int */ public function getNumRounds() { return $this->numRounds; } /** * @param int $offset * @return ParagonIE_Sodium_Core_AES_Block */ public function getRoundKey($offset) { return ParagonIE_Sodium_Core_AES_Block::fromArray( array_slice($this->skey, $offset, 8) ); } /** * Return an expanded key schedule * * @return ParagonIE_Sodium_Core_AES_Expanded */ public function expand() { $exp = new ParagonIE_Sodium_Core_AES_Expanded( array_fill(0, 120, 0), $this->numRounds ); $n = ($exp->numRounds + 1) << 2; for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) { $x = $y = $this->skey[$u]; $x &= 0x55555555; $exp->skey[$v] = ($x | ($x << 1)) & ParagonIE_Sodium_Core_Util::U32_MAX; $y &= 0xAAAAAAAA; $exp->skey[$v + 1] = ($y | ($y >> 1)) & ParagonIE_Sodium_Core_Util::U32_MAX; } return $exp; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Ed25519.php������������������������������������������������������������������������������������0000644�����������������00000042114�15021200076�0007076 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) { return; } if (!class_exists('ParagonIE_Sodium_Core_Curve25519', false)) { require_once dirname(__FILE__) . '/Curve25519.php'; } /** * Class ParagonIE_Sodium_Core_Ed25519 */ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve25519 { const KEYPAIR_BYTES = 96; const SEED_BYTES = 32; const SCALAR_BYTES = 32; /** * @internal You should not use this directly from another application * * @return string (96 bytes) * @throws Exception * @throws SodiumException * @throws TypeError */ public static function keypair() { $seed = random_bytes(self::SEED_BYTES); $pk = ''; $sk = ''; self::seed_keypair($pk, $sk, $seed); return $sk . $pk; } /** * @internal You should not use this directly from another application * * @param string $pk * @param string $sk * @param string $seed * @return string * @throws SodiumException * @throws TypeError */ public static function seed_keypair(&$pk, &$sk, $seed) { if (self::strlen($seed) !== self::SEED_BYTES) { throw new RangeException('crypto_sign keypair seed must be 32 bytes long'); } /** @var string $pk */ $pk = self::publickey_from_secretkey($seed); $sk = $seed . $pk; return $sk; } /** * @internal You should not use this directly from another application * * @param string $keypair * @return string * @throws TypeError */ public static function secretkey($keypair) { if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { throw new RangeException('crypto_sign keypair must be 96 bytes long'); } return self::substr($keypair, 0, 64); } /** * @internal You should not use this directly from another application * * @param string $keypair * @return string * @throws TypeError */ public static function publickey($keypair) { if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { throw new RangeException('crypto_sign keypair must be 96 bytes long'); } return self::substr($keypair, 64, 32); } /** * @internal You should not use this directly from another application * * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function publickey_from_secretkey($sk) { /** @var string $sk */ $sk = hash('sha512', self::substr($sk, 0, 32), true); $sk[0] = self::intToChr( self::chrToInt($sk[0]) & 248 ); $sk[31] = self::intToChr( (self::chrToInt($sk[31]) & 63) | 64 ); return self::sk_to_pk($sk); } /** * @param string $pk * @return string * @throws SodiumException * @throws TypeError */ public static function pk_to_curve25519($pk) { if (self::small_order($pk)) { throw new SodiumException('Public key is on a small order'); } $A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32)); $p1 = self::ge_mul_l($A); if (!self::fe_isnonzero($p1->X)) { throw new SodiumException('Unexpected zero result'); } # fe_1(one_minus_y); # fe_sub(one_minus_y, one_minus_y, A.Y); # fe_invert(one_minus_y, one_minus_y); $one_minux_y = self::fe_invert( self::fe_sub( self::fe_1(), $A->Y ) ); # fe_1(x); # fe_add(x, x, A.Y); # fe_mul(x, x, one_minus_y); $x = self::fe_mul( self::fe_add(self::fe_1(), $A->Y), $one_minux_y ); # fe_tobytes(curve25519_pk, x); return self::fe_tobytes($x); } /** * @internal You should not use this directly from another application * * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sk_to_pk($sk) { return self::ge_p3_tobytes( self::ge_scalarmult_base( self::substr($sk, 0, 32) ) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign($message, $sk) { /** @var string $signature */ $signature = self::sign_detached($message, $sk); return $signature . $message; } /** * @internal You should not use this directly from another application * * @param string $message A signed message * @param string $pk Public key * @return string Message (without signature) * @throws SodiumException * @throws TypeError */ public static function sign_open($message, $pk) { /** @var string $signature */ $signature = self::substr($message, 0, 64); /** @var string $message */ $message = self::substr($message, 64); if (self::verify_detached($signature, $message, $pk)) { return $message; } throw new SodiumException('Invalid signature'); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign_detached($message, $sk) { # crypto_hash_sha512(az, sk, 32); $az = hash('sha512', self::substr($sk, 0, 32), true); # az[0] &= 248; # az[31] &= 63; # az[31] |= 64; $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); # crypto_hash_sha512_init(&hs); # crypto_hash_sha512_update(&hs, az + 32, 32); # crypto_hash_sha512_update(&hs, m, mlen); # crypto_hash_sha512_final(&hs, nonce); $hs = hash_init('sha512'); hash_update($hs, self::substr($az, 32, 32)); hash_update($hs, $message); $nonceHash = hash_final($hs, true); # memmove(sig + 32, sk + 32, 32); $pk = self::substr($sk, 32, 32); # sc_reduce(nonce); # ge_scalarmult_base(&R, nonce); # ge_p3_tobytes(sig, &R); $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); $sig = self::ge_p3_tobytes( self::ge_scalarmult_base($nonce) ); # crypto_hash_sha512_init(&hs); # crypto_hash_sha512_update(&hs, sig, 64); # crypto_hash_sha512_update(&hs, m, mlen); # crypto_hash_sha512_final(&hs, hram); $hs = hash_init('sha512'); hash_update($hs, self::substr($sig, 0, 32)); hash_update($hs, self::substr($pk, 0, 32)); hash_update($hs, $message); $hramHash = hash_final($hs, true); # sc_reduce(hram); # sc_muladd(sig + 32, hram, az, nonce); $hram = self::sc_reduce($hramHash); $sigAfter = self::sc_muladd($hram, $az, $nonce); $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); try { ParagonIE_Sodium_Compat::memzero($az); } catch (SodiumException $ex) { $az = null; } return $sig; } /** * @internal You should not use this directly from another application * * @param string $sig * @param string $message * @param string $pk * @return bool * @throws SodiumException * @throws TypeError */ public static function verify_detached($sig, $message, $pk) { if (self::strlen($sig) < 64) { throw new SodiumException('Signature is too short'); } if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { throw new SodiumException('S < L - Invalid signature'); } if (self::small_order($sig)) { throw new SodiumException('Signature is on too small of an order'); } if ((self::chrToInt($sig[63]) & 224) !== 0) { throw new SodiumException('Invalid signature'); } $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= self::chrToInt($pk[$i]); } if ($d === 0) { throw new SodiumException('All zero public key'); } /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ $orig = ParagonIE_Sodium_Compat::$fastMult; // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. ParagonIE_Sodium_Compat::$fastMult = true; /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */ $A = self::ge_frombytes_negate_vartime($pk); /** @var string $hDigest */ $hDigest = hash( 'sha512', self::substr($sig, 0, 32) . self::substr($pk, 0, 32) . $message, true ); /** @var string $h */ $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */ $R = self::ge_double_scalarmult_vartime( $h, $A, self::substr($sig, 32) ); /** @var string $rcheck */ $rcheck = self::ge_tobytes($R); // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. ParagonIE_Sodium_Compat::$fastMult = $orig; return self::verify_32($rcheck, self::substr($sig, 0, 32)); } /** * @internal You should not use this directly from another application * * @param string $S * @return bool * @throws SodiumException * @throws TypeError */ public static function check_S_lt_L($S) { if (self::strlen($S) < 32) { throw new SodiumException('Signature must be 32 bytes'); } $L = array( 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ); $c = 0; $n = 1; $i = 32; /** @var array<int, int> $L */ do { --$i; $x = self::chrToInt($S[$i]); $c |= ( (($x - $L[$i]) >> 8) & $n ); $n &= ( (($x ^ $L[$i]) - 1) >> 8 ); } while ($i !== 0); return $c === 0; } /** * @param string $R * @return bool * @throws SodiumException * @throws TypeError */ public static function small_order($R) { /** @var array<int, array<int, int>> $blocklist */ $blocklist = array( /* 0 (order 4) */ array( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), /* 1 (order 1) */ array( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ array( 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 ), /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ array( 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a ), /* p-1 (order 2) */ array( 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 ), /* p (order 4) */ array( 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa ), /* p+1 (order 1) */ array( 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f ), /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ array( 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f ), /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ array( 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f ), /* 2p-1 (order 2) */ array( 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), /* 2p (order 4) */ array( 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), /* 2p+1 (order 1) */ array( 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ) ); /** @var int $countBlocklist */ $countBlocklist = count($blocklist); for ($i = 0; $i < $countBlocklist; ++$i) { $c = 0; for ($j = 0; $j < 32; ++$j) { $c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j]; } if ($c === 0) { return true; } } return false; } /** * @param string $s * @return string * @throws SodiumException */ public static function scalar_complement($s) { $t_ = self::L . str_repeat("\x00", 32); sodium_increment($t_); $s_ = $s . str_repeat("\x00", 32); ParagonIE_Sodium_Compat::sub($t_, $s_); return self::sc_reduce($t_); } /** * @return string * @throws SodiumException */ public static function scalar_random() { do { $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES); $r[self::SCALAR_BYTES - 1] = self::intToChr( self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f ); } while ( !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r) ); return $r; } /** * @param string $s * @return string * @throws SodiumException */ public static function scalar_negate($s) { $t_ = self::L . str_repeat("\x00", 32) ; $s_ = $s . str_repeat("\x00", 32) ; ParagonIE_Sodium_Compat::sub($t_, $s_); return self::sc_reduce($t_); } /** * @param string $a * @param string $b * @return string * @throws SodiumException */ public static function scalar_add($a, $b) { $a_ = $a . str_repeat("\x00", 32); $b_ = $b . str_repeat("\x00", 32); ParagonIE_Sodium_Compat::add($a_, $b_); return self::sc_reduce($a_); } /** * @param string $x * @param string $y * @return string * @throws SodiumException */ public static function scalar_sub($x, $y) { $yn = self::scalar_negate($y); return self::scalar_add($x, $yn); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Base64/UrlSafe.php�����������������������������������������������������������������������������0000644�����������������00000017063�15021200076�0010532 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core_Base64UrlSafe * * Copyright (c) 2016 - 2018 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) */ class ParagonIE_Sodium_Core_Base64_UrlSafe { // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE /** * Encode into Base64 * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encode($src) { return self::doEncode($src, true); } /** * Encode into Base64, no = padding * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encodeUnpadded($src) { return self::doEncode($src, false); } /** * @param string $src * @param bool $pad Include = padding? * @return string * @throws TypeError */ protected static function doEncode($src, $pad = true) { $dest = ''; $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); // Main loop (no padding): for ($i = 0; $i + 3 <= $srcLen; $i += 3) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= self::encode6Bits( $b0 >> 2 ) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . self::encode6Bits( $b2 & 63); } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits(($b1 << 2) & 63); if ($pad) { $dest .= '='; } } else { $dest .= self::encode6Bits( $b0 >> 2) . self::encode6Bits(($b0 << 4) & 63); if ($pad) { $dest .= '=='; } } } return $dest; } /** * decode from base64 into binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @param bool $strictPadding * @return string * @throws RangeException * @throws TypeError * @psalm-suppress RedundantCondition */ public static function decode($src, $strictPadding = false) { // Remove padding $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 3) === 0) { if ($src[$srcLen - 1] === '=') { $srcLen--; if ($src[$srcLen - 1] === '=') { $srcLen--; } } } if (($srcLen & 3) === 1) { throw new RangeException( 'Incorrect padding' ); } if ($src[$srcLen - 1] === '=') { throw new RangeException( 'Incorrect padding' ); } } else { $src = rtrim($src, '='); $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 4 <= $srcLen; $i += 4) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); $c0 = self::decode6Bits($chunk[1]); $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $c3 = self::decode6Bits($chunk[4]); $dest .= pack( 'CCC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff), ((($c2 << 6) | $c3) & 0xff) ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $c0 = self::decode6Bits($chunk[1]); if ($i + 2 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $dest .= pack( 'CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff) ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif ($i + 1 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $dest .= pack( 'C', ((($c0 << 2) | ($c1 >> 4)) & 0xff) ); $err |= ($c0 | $c1) >> 8; } elseif ($i < $srcLen && $strictPadding) { $err |= 1; } } /** @var bool $check */ $check = ($err === 0); if (!$check) { throw new RangeException( 'Base64::decode() only expects characters in the correct base64 alphabet' ); } return $dest; } // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] + / * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); // if ($src == 0x2c) $ret += 62 + 1; $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63; // if ($src == 0x5f) ret += 63 + 1; $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64; return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $diff = 0x41; // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 $diff += ((25 - $src) >> 8) & 6; // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 $diff -= ((51 - $src) >> 8) & 75; // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13 $diff -= ((61 - $src) >> 8) & 13; // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3 $diff += ((62 - $src) >> 8) & 49; return pack('C', $src + $diff); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Base64/Original.php����������������������������������������������������������������������������0000644�����������������00000017055�15021200076�0010736 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core_Base64 * * Copyright (c) 2016 - 2018 Paragon Initiative Enterprises. * Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com) */ class ParagonIE_Sodium_Core_Base64_Original { // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE /** * Encode into Base64 * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encode($src) { return self::doEncode($src, true); } /** * Encode into Base64, no = padding * * Base64 character set "[A-Z][a-z][0-9]+/" * * @param string $src * @return string * @throws TypeError */ public static function encodeUnpadded($src) { return self::doEncode($src, false); } /** * @param string $src * @param bool $pad Include = padding? * @return string * @throws TypeError */ protected static function doEncode($src, $pad = true) { $dest = ''; $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); // Main loop (no padding): for ($i = 0; $i + 3 <= $srcLen; $i += 3) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3)); $b0 = $chunk[1]; $b1 = $chunk[2]; $b2 = $chunk[3]; $dest .= self::encode6Bits( $b0 >> 2 ) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) . self::encode6Bits( $b2 & 63); } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $b0 = $chunk[1]; if ($i + 1 < $srcLen) { $b1 = $chunk[2]; $dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) . self::encode6Bits(($b1 << 2) & 63); if ($pad) { $dest .= '='; } } else { $dest .= self::encode6Bits( $b0 >> 2) . self::encode6Bits(($b0 << 4) & 63); if ($pad) { $dest .= '=='; } } } return $dest; } /** * decode from base64 into binary * * Base64 character set "./[A-Z][a-z][0-9]" * * @param string $src * @param bool $strictPadding * @return string * @throws RangeException * @throws TypeError * @psalm-suppress RedundantCondition */ public static function decode($src, $strictPadding = false) { // Remove padding $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); if ($srcLen === 0) { return ''; } if ($strictPadding) { if (($srcLen & 3) === 0) { if ($src[$srcLen - 1] === '=') { $srcLen--; if ($src[$srcLen - 1] === '=') { $srcLen--; } } } if (($srcLen & 3) === 1) { throw new RangeException( 'Incorrect padding' ); } if ($src[$srcLen - 1] === '=') { throw new RangeException( 'Incorrect padding' ); } } else { $src = rtrim($src, '='); $srcLen = ParagonIE_Sodium_Core_Util::strlen($src); } $err = 0; $dest = ''; // Main loop (no padding): for ($i = 0; $i + 4 <= $srcLen; $i += 4) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4)); $c0 = self::decode6Bits($chunk[1]); $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $c3 = self::decode6Bits($chunk[4]); $dest .= pack( 'CCC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff), ((($c2 << 6) | $c3) & 0xff) ); $err |= ($c0 | $c1 | $c2 | $c3) >> 8; } // The last chunk, which may have padding: if ($i < $srcLen) { /** @var array<int, int> $chunk */ $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i)); $c0 = self::decode6Bits($chunk[1]); if ($i + 2 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $c2 = self::decode6Bits($chunk[3]); $dest .= pack( 'CC', ((($c0 << 2) | ($c1 >> 4)) & 0xff), ((($c1 << 4) | ($c2 >> 2)) & 0xff) ); $err |= ($c0 | $c1 | $c2) >> 8; } elseif ($i + 1 < $srcLen) { $c1 = self::decode6Bits($chunk[2]); $dest .= pack( 'C', ((($c0 << 2) | ($c1 >> 4)) & 0xff) ); $err |= ($c0 | $c1) >> 8; } elseif ($i < $srcLen && $strictPadding) { $err |= 1; } } /** @var bool $check */ $check = ($err === 0); if (!$check) { throw new RangeException( 'Base64::decode() only expects characters in the correct base64 alphabet' ); } return $dest; } // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE /** * Uses bitwise operators instead of table-lookups to turn 6-bit integers * into 8-bit integers. * * Base64 character set: * [A-Z] [a-z] [0-9] + / * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f * * @param int $src * @return int */ protected static function decode6Bits($src) { $ret = -1; // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64 $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64); // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70 $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70); // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5 $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5); // if ($src == 0x2b) $ret += 62 + 1; $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63; // if ($src == 0x2f) ret += 63 + 1; $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64; return $ret; } /** * Uses bitwise operators instead of table-lookups to turn 8-bit integers * into 6-bit integers. * * @param int $src * @return string */ protected static function encode6Bits($src) { $diff = 0x41; // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6 $diff += ((25 - $src) >> 8) & 6; // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75 $diff -= ((51 - $src) >> 8) & 75; // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15 $diff -= ((61 - $src) >> 8) & 15; // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3 $diff += ((62 - $src) >> 8) & 3; return pack('C', $src + $diff); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Salsa20.php������������������������������������������������������������������������������������0000644�����������������00000020051�15021200076�0007341 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Salsa20', false)) { return; } /** * Class ParagonIE_Sodium_Core_Salsa20 */ abstract class ParagonIE_Sodium_Core_Salsa20 extends ParagonIE_Sodium_Core_Util { const ROUNDS = 20; /** * Calculate an salsa20 hash of a single block * * @internal You should not use this directly from another application * * @param string $in * @param string $k * @param string|null $c * @return string * @throws TypeError */ public static function core_salsa20($in, $k, $c = null) { if (self::strlen($k) < 32) { throw new RangeException('Key must be 32 bytes long'); } if ($c === null) { $j0 = $x0 = 0x61707865; $j5 = $x5 = 0x3320646e; $j10 = $x10 = 0x79622d32; $j15 = $x15 = 0x6b206574; } else { $j0 = $x0 = self::load_4(self::substr($c, 0, 4)); $j5 = $x5 = self::load_4(self::substr($c, 4, 4)); $j10 = $x10 = self::load_4(self::substr($c, 8, 4)); $j15 = $x15 = self::load_4(self::substr($c, 12, 4)); } $j1 = $x1 = self::load_4(self::substr($k, 0, 4)); $j2 = $x2 = self::load_4(self::substr($k, 4, 4)); $j3 = $x3 = self::load_4(self::substr($k, 8, 4)); $j4 = $x4 = self::load_4(self::substr($k, 12, 4)); $j6 = $x6 = self::load_4(self::substr($in, 0, 4)); $j7 = $x7 = self::load_4(self::substr($in, 4, 4)); $j8 = $x8 = self::load_4(self::substr($in, 8, 4)); $j9 = $x9 = self::load_4(self::substr($in, 12, 4)); $j11 = $x11 = self::load_4(self::substr($k, 16, 4)); $j12 = $x12 = self::load_4(self::substr($k, 20, 4)); $j13 = $x13 = self::load_4(self::substr($k, 24, 4)); $j14 = $x14 = self::load_4(self::substr($k, 28, 4)); for ($i = self::ROUNDS; $i > 0; $i -= 2) { $x4 ^= self::rotate($x0 + $x12, 7); $x8 ^= self::rotate($x4 + $x0, 9); $x12 ^= self::rotate($x8 + $x4, 13); $x0 ^= self::rotate($x12 + $x8, 18); $x9 ^= self::rotate($x5 + $x1, 7); $x13 ^= self::rotate($x9 + $x5, 9); $x1 ^= self::rotate($x13 + $x9, 13); $x5 ^= self::rotate($x1 + $x13, 18); $x14 ^= self::rotate($x10 + $x6, 7); $x2 ^= self::rotate($x14 + $x10, 9); $x6 ^= self::rotate($x2 + $x14, 13); $x10 ^= self::rotate($x6 + $x2, 18); $x3 ^= self::rotate($x15 + $x11, 7); $x7 ^= self::rotate($x3 + $x15, 9); $x11 ^= self::rotate($x7 + $x3, 13); $x15 ^= self::rotate($x11 + $x7, 18); $x1 ^= self::rotate($x0 + $x3, 7); $x2 ^= self::rotate($x1 + $x0, 9); $x3 ^= self::rotate($x2 + $x1, 13); $x0 ^= self::rotate($x3 + $x2, 18); $x6 ^= self::rotate($x5 + $x4, 7); $x7 ^= self::rotate($x6 + $x5, 9); $x4 ^= self::rotate($x7 + $x6, 13); $x5 ^= self::rotate($x4 + $x7, 18); $x11 ^= self::rotate($x10 + $x9, 7); $x8 ^= self::rotate($x11 + $x10, 9); $x9 ^= self::rotate($x8 + $x11, 13); $x10 ^= self::rotate($x9 + $x8, 18); $x12 ^= self::rotate($x15 + $x14, 7); $x13 ^= self::rotate($x12 + $x15, 9); $x14 ^= self::rotate($x13 + $x12, 13); $x15 ^= self::rotate($x14 + $x13, 18); } $x0 += $j0; $x1 += $j1; $x2 += $j2; $x3 += $j3; $x4 += $j4; $x5 += $j5; $x6 += $j6; $x7 += $j7; $x8 += $j8; $x9 += $j9; $x10 += $j10; $x11 += $j11; $x12 += $j12; $x13 += $j13; $x14 += $j14; $x15 += $j15; return self::store32_le($x0) . self::store32_le($x1) . self::store32_le($x2) . self::store32_le($x3) . self::store32_le($x4) . self::store32_le($x5) . self::store32_le($x6) . self::store32_le($x7) . self::store32_le($x8) . self::store32_le($x9) . self::store32_le($x10) . self::store32_le($x11) . self::store32_le($x12) . self::store32_le($x13) . self::store32_le($x14) . self::store32_le($x15); } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function salsa20($len, $nonce, $key) { if (self::strlen($key) !== 32) { throw new RangeException('Key must be 32 bytes long'); } $kcopy = '' . $key; $in = self::substr($nonce, 0, 8) . str_repeat("\0", 8); $c = ''; while ($len >= 64) { $c .= self::core_salsa20($in, $kcopy, null); $u = 1; // Internal counter. for ($i = 8; $i < 16; ++$i) { $u += self::chrToInt($in[$i]); $in[$i] = self::intToChr($u & 0xff); $u >>= 8; } $len -= 64; } if ($len > 0) { $c .= self::substr( self::core_salsa20($in, $kcopy, null), 0, $len ); } try { ParagonIE_Sodium_Compat::memzero($kcopy); } catch (SodiumException $ex) { $kcopy = null; } return $c; } /** * @internal You should not use this directly from another application * * @param string $m * @param string $n * @param int $ic * @param string $k * @return string * @throws SodiumException * @throws TypeError */ public static function salsa20_xor_ic($m, $n, $ic, $k) { $mlen = self::strlen($m); if ($mlen < 1) { return ''; } $kcopy = self::substr($k, 0, 32); $in = self::substr($n, 0, 8); // Initialize the counter $in .= ParagonIE_Sodium_Core_Util::store64_le($ic); $c = ''; while ($mlen >= 64) { $block = self::core_salsa20($in, $kcopy, null); $c .= self::xorStrings( self::substr($m, 0, 64), self::substr($block, 0, 64) ); $u = 1; for ($i = 8; $i < 16; ++$i) { $u += self::chrToInt($in[$i]); $in[$i] = self::intToChr($u & 0xff); $u >>= 8; } $mlen -= 64; $m = self::substr($m, 64); } if ($mlen) { $block = self::core_salsa20($in, $kcopy, null); $c .= self::xorStrings( self::substr($m, 0, $mlen), self::substr($block, 0, $mlen) ); } try { ParagonIE_Sodium_Compat::memzero($block); ParagonIE_Sodium_Compat::memzero($kcopy); } catch (SodiumException $ex) { $block = null; $kcopy = null; } return $c; } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function salsa20_xor($message, $nonce, $key) { return self::xorStrings( $message, self::salsa20( self::strlen($message), $nonce, $key ) ); } /** * @internal You should not use this directly from another application * * @param int $u * @param int $c * @return int */ public static function rotate($u, $c) { $u &= 0xffffffff; $c %= 32; return (int) (0xffffffff & ( ($u << $c) | ($u >> (32 - $c)) ) ); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/XSalsa20.php�����������������������������������������������������������������������������������0000644�����������������00000002533�15021200076�0007476 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_XSalsa20', false)) { return; } /** * Class ParagonIE_Sodium_Core_XSalsa20 */ abstract class ParagonIE_Sodium_Core_XSalsa20 extends ParagonIE_Sodium_Core_HSalsa20 { /** * Expand a key and nonce into an xsalsa20 keystream. * * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function xsalsa20($len, $nonce, $key) { $ret = self::salsa20( $len, self::substr($nonce, 16, 8), self::hsalsa20($nonce, $key) ); return $ret; } /** * Encrypt a string with XSalsa20. Doesn't provide integrity. * * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function xsalsa20_xor($message, $nonce, $key) { return self::xorStrings( $message, self::xsalsa20( self::strlen($message), $nonce, $key ) ); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Ristretto255.php�������������������������������������������������������������������������������0000644�����������������00000052574�15021200076�0010406 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core_Ristretto255 */ class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519 { const crypto_core_ristretto255_HASHBYTES = 64; const HASH_SC_L = 48; const CORE_H2C_SHA256 = 1; const CORE_H2C_SHA512 = 2; /** * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @param int $b * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_cneg(ParagonIE_Sodium_Core_Curve25519_Fe $f, $b) { $negf = self::fe_neg($f); return self::fe_cmov($f, $negf, $b); } /** * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe * @throws SodiumException */ public static function fe_abs(ParagonIE_Sodium_Core_Curve25519_Fe $f) { return self::fe_cneg($f, self::fe_isnegative($f)); } /** * Returns 0 if this field element results in all NUL bytes. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return int * @throws SodiumException */ public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f) { static $zero; if ($zero === null) { $zero = str_repeat("\x00", 32); } /** @var string $zero */ $str = self::fe_tobytes($f); $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= self::chrToInt($str[$i]); } return (($d - 1) >> 31) & 1; } /** * @param ParagonIE_Sodium_Core_Curve25519_Fe $u * @param ParagonIE_Sodium_Core_Curve25519_Fe $v * @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int} * * @throws SodiumException */ public static function ristretto255_sqrt_ratio_m1( ParagonIE_Sodium_Core_Curve25519_Fe $u, ParagonIE_Sodium_Core_Curve25519_Fe $v ) { $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1); $v3 = self::fe_mul( self::fe_sq($v), $v ); /* v3 = v^3 */ $x = self::fe_mul( self::fe_mul( self::fe_sq($v3), $u ), $v ); /* x = uv^7 */ $x = self::fe_mul( self::fe_mul( self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */ $v3 ), $u ); /* x = uv^3(uv^7)^((q-5)/8) */ $vxx = self::fe_mul( self::fe_sq($x), $v ); /* vx^2 */ $m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */ $p_root_check = self::fe_add($vxx, $u); /* vx^2+u */ $f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */ $f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */ $has_m_root = self::fe_iszero($m_root_check); $has_p_root = self::fe_iszero($p_root_check); $has_f_root = self::fe_iszero($f_root_check); $x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */ $x = self::fe_abs( self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root) ); return array( 'x' => $x, 'nonsquare' => $has_m_root | $has_p_root ); } /** * @param string $s * @return int * @throws SodiumException */ public static function ristretto255_point_is_canonical($s) { $c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f; for ($i = 30; $i > 0; --$i) { $c |= self::chrToInt($s[$i]) ^ 0xff; } $c = ($c - 1) >> 8; $d = (0xed - 1 - self::chrToInt($s[0])) >> 8; $e = self::chrToInt($s[31]) >> 7; return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1); } /** * @param string $s * @param bool $skipCanonicalCheck * @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int} * @throws SodiumException */ public static function ristretto255_frombytes($s, $skipCanonicalCheck = false) { if (!$skipCanonicalCheck) { if (!self::ristretto255_point_is_canonical($s)) { throw new SodiumException('S is not canonical'); } } $s_ = self::fe_frombytes($s); $ss = self::fe_sq($s_); /* ss = s^2 */ $u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */ $u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */ $u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */ $u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */ $v = self::fe_mul( ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d), $u1u1 ); /* v = d*u1^2 */ $v = self::fe_neg($v); /* v = -d*u1^2 */ $v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */ $v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */ // fe25519_1(one); // notsquare = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2); $one = self::fe_1(); $result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2); $inv_sqrt = $result['x']; $notsquare = $result['nonsquare']; $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); $h->X = self::fe_mul($inv_sqrt, $u2); $h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v); $h->X = self::fe_mul($h->X, $s_); $h->X = self::fe_abs( self::fe_add($h->X, $h->X) ); $h->Y = self::fe_mul($u1, $h->Y); $h->Z = self::fe_1(); $h->T = self::fe_mul($h->X, $h->Y); $res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y)); return array('h' => $h, 'res' => $res); } /** * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h * @return string * @throws SodiumException */ public static function ristretto255_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h) { $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1); $invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$invsqrtamd); $u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */ $zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */ $u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */ $u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */ $u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */ $one = self::fe_1(); // fe25519_1(one); // (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2); $result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2); $inv_sqrt = $result['x']; $den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */ $den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */ $z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */ $ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */ $iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */ $eden = self::fe_mul($den1, $invsqrtamd); $t_z_inv = self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */ $rotate = self::fe_isnegative($t_z_inv); $x_ = self::fe_copy($h->X); $y_ = self::fe_copy($h->Y); $den_inv = self::fe_copy($den2); $x_ = self::fe_cmov($x_, $iy, $rotate); $y_ = self::fe_cmov($y_, $ix, $rotate); $den_inv = self::fe_cmov($den_inv, $eden, $rotate); $x_z_inv = self::fe_mul($x_, $z_inv); $y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv)); // fe25519_sub(s_, h->Z, y_); // fe25519_mul(s_, den_inv, s_); // fe25519_abs(s_, s_); // fe25519_tobytes(s, s_); return self::fe_tobytes( self::fe_abs( self::fe_mul( $den_inv, self::fe_sub($h->Z, $y_) ) ) ); } /** * @param ParagonIE_Sodium_Core_Curve25519_Fe $t * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 * * @throws SodiumException */ public static function ristretto255_elligator(ParagonIE_Sodium_Core_Curve25519_Fe $t) { $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1); $onemsqd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$onemsqd); $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d); $sqdmone = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqdmone); $sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtadm1); $one = self::fe_1(); $r = self::fe_mul($sqrtm1, self::fe_sq($t)); /* r = sqrt(-1)*t^2 */ $u = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */ $c = self::fe_neg(self::fe_1()); /* c = -1 */ $rpd = self::fe_add($r, $d); /* rpd = r+d */ $v = self::fe_mul( self::fe_sub( $c, self::fe_mul($r, $d) ), $rpd ); /* v = (c-r*d)*(r+d) */ $result = self::ristretto255_sqrt_ratio_m1($u, $v); $s = $result['x']; $wasnt_square = 1 - $result['nonsquare']; $s_prime = self::fe_neg( self::fe_abs( self::fe_mul($s, $t) ) ); /* s_prime = -|s*t| */ $s = self::fe_cmov($s, $s_prime, $wasnt_square); $c = self::fe_cmov($c, $r, $wasnt_square); // fe25519_sub(n, r, one); /* n = r-1 */ // fe25519_mul(n, n, c); /* n = c*(r-1) */ // fe25519_mul(n, n, ed25519_sqdmone); /* n = c*(r-1)*(d-1)^2 */ // fe25519_sub(n, n, v); /* n = c*(r-1)*(d-1)^2-v */ $n = self::fe_sub( self::fe_mul( self::fe_mul( self::fe_sub($r, $one), $c ), $sqdmone ), $v ); /* n = c*(r-1)*(d-1)^2-v */ $w0 = self::fe_mul( self::fe_add($s, $s), $v ); /* w0 = 2s*v */ $w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */ $ss = self::fe_sq($s); /* ss = s^2 */ $w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */ $w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */ return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( self::fe_mul($w0, $w3), self::fe_mul($w2, $w1), self::fe_mul($w1, $w3), self::fe_mul($w0, $w2) ); } /** * @param string $h * @return string * @throws SodiumException */ public static function ristretto255_from_hash($h) { if (self::strlen($h) !== 64) { throw new SodiumException('Hash must be 64 bytes'); } //fe25519_frombytes(r0, h); //fe25519_frombytes(r1, h + 32); $r0 = self::fe_frombytes(self::substr($h, 0, 32)); $r1 = self::fe_frombytes(self::substr($h, 32, 32)); //ristretto255_elligator(&p0, r0); //ristretto255_elligator(&p1, r1); $p0 = self::ristretto255_elligator($r0); $p1 = self::ristretto255_elligator($r1); //ge25519_p3_to_cached(&p1_cached, &p1); //ge25519_add_cached(&p_p1p1, &p0, &p1_cached); $p_p1p1 = self::ge_add( $p0, self::ge_p3_to_cached($p1) ); //ge25519_p1p1_to_p3(&p, &p_p1p1); //ristretto255_p3_tobytes(s, &p); return self::ristretto255_p3_tobytes( self::ge_p1p1_to_p3($p_p1p1) ); } /** * @param string $p * @return int * @throws SodiumException */ public static function is_valid_point($p) { $result = self::ristretto255_frombytes($p); if ($result['res'] !== 0) { return 0; } return 1; } /** * @param string $p * @param string $q * @return string * @throws SodiumException */ public static function ristretto255_add($p, $q) { $p_res = self::ristretto255_frombytes($p); $q_res = self::ristretto255_frombytes($q); if ($p_res['res'] !== 0 || $q_res['res'] !== 0) { throw new SodiumException('Could not add points'); } $p_p3 = $p_res['h']; $q_p3 = $q_res['h']; $q_cached = self::ge_p3_to_cached($q_p3); $r_p1p1 = self::ge_add($p_p3, $q_cached); $r_p3 = self::ge_p1p1_to_p3($r_p1p1); return self::ristretto255_p3_tobytes($r_p3); } /** * @param string $p * @param string $q * @return string * @throws SodiumException */ public static function ristretto255_sub($p, $q) { $p_res = self::ristretto255_frombytes($p); $q_res = self::ristretto255_frombytes($q); if ($p_res['res'] !== 0 || $q_res['res'] !== 0) { throw new SodiumException('Could not add points'); } $p_p3 = $p_res['h']; $q_p3 = $q_res['h']; $q_cached = self::ge_p3_to_cached($q_p3); $r_p1p1 = self::ge_sub($p_p3, $q_cached); $r_p3 = self::ge_p1p1_to_p3($r_p1p1); return self::ristretto255_p3_tobytes($r_p3); } /** * @param int $hLen * @param ?string $ctx * @param string $msg * @return string * @throws SodiumException * @psalm-suppress PossiblyInvalidArgument hash API */ protected static function h2c_string_to_hash_sha256($hLen, $ctx, $msg) { $h = array_fill(0, $hLen, 0); $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0; if ($hLen > 0xff) { throw new SodiumException('Hash must be less than 256 bytes'); } if ($ctx_len > 0xff) { $st = hash_init('sha256'); self::hash_update($st, "H2C-OVERSIZE-DST-"); self::hash_update($st, $ctx); $ctx = hash_final($st, true); $ctx_len = 32; } $t = array(0, $hLen, 0); $ux = str_repeat("\0", 64); $st = hash_init('sha256'); self::hash_update($st, $ux); self::hash_update($st, $msg); self::hash_update($st, self::intArrayToString($t)); self::hash_update($st, $ctx); self::hash_update($st, self::intToChr($ctx_len)); $u0 = hash_final($st, true); for ($i = 0; $i < $hLen; $i += 64) { $ux = self::xorStrings($ux, $u0); ++$t[2]; $st = hash_init('sha256'); self::hash_update($st, $ux); self::hash_update($st, self::intToChr($t[2])); self::hash_update($st, $ctx); self::hash_update($st, self::intToChr($ctx_len)); $ux = hash_final($st, true); $amount = min($hLen - $i, 64); for ($j = 0; $j < $amount; ++$j) { $h[$i + $j] = self::chrToInt($ux[$i]); } } return self::intArrayToString(array_slice($h, 0, $hLen)); } /** * @param int $hLen * @param ?string $ctx * @param string $msg * @return string * @throws SodiumException * @psalm-suppress PossiblyInvalidArgument hash API */ protected static function h2c_string_to_hash_sha512($hLen, $ctx, $msg) { $h = array_fill(0, $hLen, 0); $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0; if ($hLen > 0xff) { throw new SodiumException('Hash must be less than 256 bytes'); } if ($ctx_len > 0xff) { $st = hash_init('sha256'); self::hash_update($st, "H2C-OVERSIZE-DST-"); self::hash_update($st, $ctx); $ctx = hash_final($st, true); $ctx_len = 32; } $t = array(0, $hLen, 0); $ux = str_repeat("\0", 128); $st = hash_init('sha512'); self::hash_update($st, $ux); self::hash_update($st, $msg); self::hash_update($st, self::intArrayToString($t)); self::hash_update($st, $ctx); self::hash_update($st, self::intToChr($ctx_len)); $u0 = hash_final($st, true); for ($i = 0; $i < $hLen; $i += 128) { $ux = self::xorStrings($ux, $u0); ++$t[2]; $st = hash_init('sha512'); self::hash_update($st, $ux); self::hash_update($st, self::intToChr($t[2])); self::hash_update($st, $ctx); self::hash_update($st, self::intToChr($ctx_len)); $ux = hash_final($st, true); $amount = min($hLen - $i, 128); for ($j = 0; $j < $amount; ++$j) { $h[$i + $j] = self::chrToInt($ux[$i]); } } return self::intArrayToString(array_slice($h, 0, $hLen)); } /** * @param int $hLen * @param ?string $ctx * @param string $msg * @param int $hash_alg * @return string * @throws SodiumException */ public static function h2c_string_to_hash($hLen, $ctx, $msg, $hash_alg) { switch ($hash_alg) { case self::CORE_H2C_SHA256: return self::h2c_string_to_hash_sha256($hLen, $ctx, $msg); case self::CORE_H2C_SHA512: return self::h2c_string_to_hash_sha512($hLen, $ctx, $msg); default: throw new SodiumException('Invalid H2C hash algorithm'); } } /** * @param ?string $ctx * @param string $msg * @param int $hash_alg * @return string * @throws SodiumException */ protected static function _string_to_element($ctx, $msg, $hash_alg) { return self::ristretto255_from_hash( self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg) ); } /** * @return string * @throws SodiumException * @throws Exception */ public static function ristretto255_random() { return self::ristretto255_from_hash( ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES) ); } /** * @return string * @throws SodiumException */ public static function ristretto255_scalar_random() { return self::scalar_random(); } /** * @param string $s * @return string * @throws SodiumException */ public static function ristretto255_scalar_complement($s) { return self::scalar_complement($s); } /** * @param string $s * @return string */ public static function ristretto255_scalar_invert($s) { return self::sc25519_invert($s); } /** * @param string $s * @return string * @throws SodiumException */ public static function ristretto255_scalar_negate($s) { return self::scalar_negate($s); } /** * @param string $x * @param string $y * @return string */ public static function ristretto255_scalar_add($x, $y) { return self::scalar_add($x, $y); } /** * @param string $x * @param string $y * @return string */ public static function ristretto255_scalar_sub($x, $y) { return self::scalar_sub($x, $y); } /** * @param string $x * @param string $y * @return string */ public static function ristretto255_scalar_mul($x, $y) { return self::sc25519_mul($x, $y); } /** * @param string $ctx * @param string $msg * @param int $hash_alg * @return string * @throws SodiumException */ public static function ristretto255_scalar_from_string($ctx, $msg, $hash_alg) { $h = array_fill(0, 64, 0); $h_be = self::stringToIntArray( self::h2c_string_to_hash( self::HASH_SC_L, $ctx, $msg, $hash_alg ) ); for ($i = 0; $i < self::HASH_SC_L; ++$i) { $h[$i] = $h_be[self::HASH_SC_L - 1 - $i]; } return self::ristretto255_scalar_reduce(self::intArrayToString($h)); } /** * @param string $s * @return string */ public static function ristretto255_scalar_reduce($s) { return self::sc_reduce($s); } /** * @param string $n * @param string $p * @return string * @throws SodiumException */ public static function scalarmult_ristretto255($n, $p) { if (self::strlen($n) !== 32) { throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.'); } if (self::strlen($p) !== 32) { throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.'); } $result = self::ristretto255_frombytes($p); if ($result['res'] !== 0) { throw new SodiumException('Could not multiply points'); } $P = $result['h']; $t = self::stringToIntArray($n); $t[31] &= 0x7f; $Q = self::ge_scalarmult(self::intArrayToString($t), $P); $q = self::ristretto255_p3_tobytes($Q); if (ParagonIE_Sodium_Compat::is_zero($q)) { throw new SodiumException('An unknown error has occurred'); } return $q; } /** * @param string $n * @return string * @throws SodiumException */ public static function scalarmult_ristretto255_base($n) { $t = self::stringToIntArray($n); $t[31] &= 0x7f; $Q = self::ge_scalarmult_base(self::intArrayToString($t)); $q = self::ristretto255_p3_tobytes($Q); if (ParagonIE_Sodium_Compat::is_zero($q)) { throw new SodiumException('An unknown error has occurred'); } return $q; } } ������������������������������������������������������������������������������������������������������������������������������������Core/BLAKE2b.php������������������������������������������������������������������������������������0000644�����������������00000057200�15021200076�0007204 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) { return; } /** * Class ParagonIE_Sodium_Core_BLAKE2b * * Based on the work of Devi Mandiri in devi/salt. */ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util { /** * @var SplFixedArray */ protected static $iv; /** * @var array<int, array<int, int>> */ protected static $sigma = array( array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0), array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3) ); const BLOCKBYTES = 128; const OUTBYTES = 64; const KEYBYTES = 64; /** * Turn two 32-bit integers into a fixed array representing a 64-bit integer. * * @internal You should not use this directly from another application * * @param int $high * @param int $low * @return SplFixedArray * @psalm-suppress MixedAssignment */ public static function new64($high, $low) { if (PHP_INT_SIZE === 4) { throw new SodiumException("Error, use 32-bit"); } $i64 = new SplFixedArray(2); $i64[0] = $high & 0xffffffff; $i64[1] = $low & 0xffffffff; return $i64; } /** * Convert an arbitrary number into an SplFixedArray of two 32-bit integers * that represents a 64-bit integer. * * @internal You should not use this directly from another application * * @param int $num * @return SplFixedArray */ protected static function to64($num) { list($hi, $lo) = self::numericTo64BitInteger($num); return self::new64($hi, $lo); } /** * Adds two 64-bit integers together, returning their sum as a SplFixedArray * containing two 32-bit integers (representing a 64-bit integer). * * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param SplFixedArray $y * @return SplFixedArray * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand */ protected static function add64($x, $y) { if (PHP_INT_SIZE === 4) { throw new SodiumException("Error, use 32-bit"); } $l = ($x[1] + $y[1]) & 0xffffffff; return self::new64( (int) ($x[0] + $y[0] + ( ($l < $x[1]) ? 1 : 0 )), (int) $l ); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param SplFixedArray $y * @param SplFixedArray $z * @return SplFixedArray */ protected static function add364($x, $y, $z) { return self::add64($x, self::add64($y, $z)); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param SplFixedArray $y * @return SplFixedArray * @throws SodiumException * @throws TypeError */ protected static function xor64(SplFixedArray $x, SplFixedArray $y) { if (PHP_INT_SIZE === 4) { throw new SodiumException("Error, use 32-bit"); } if (!is_numeric($x[0])) { throw new SodiumException('x[0] is not an integer'); } if (!is_numeric($x[1])) { throw new SodiumException('x[1] is not an integer'); } if (!is_numeric($y[0])) { throw new SodiumException('y[0] is not an integer'); } if (!is_numeric($y[1])) { throw new SodiumException('y[1] is not an integer'); } return self::new64( (int) (($x[0] ^ $y[0]) & 0xffffffff), (int) (($x[1] ^ $y[1]) & 0xffffffff) ); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $c * @return SplFixedArray * @psalm-suppress MixedAssignment */ public static function rotr64($x, $c) { if (PHP_INT_SIZE === 4) { throw new SodiumException("Error, use 32-bit"); } if ($c >= 64) { $c %= 64; } if ($c >= 32) { /** @var int $tmp */ $tmp = $x[0]; $x[0] = $x[1]; $x[1] = $tmp; $c -= 32; } if ($c === 0) { return $x; } $l0 = 0; $c = 64 - $c; /** @var int $c */ if ($c < 32) { $h0 = ((int) ($x[0]) << $c) | ( ( (int) ($x[1]) & ((1 << $c) - 1) << (32 - $c) ) >> (32 - $c) ); $l0 = (int) ($x[1]) << $c; } else { $h0 = (int) ($x[1]) << ($c - 32); } $h1 = 0; $c1 = 64 - $c; if ($c1 < 32) { $h1 = (int) ($x[0]) >> $c1; $l1 = ((int) ($x[1]) >> $c1) | ((int) ($x[0]) & ((1 << $c1) - 1)) << (32 - $c1); } else { $l1 = (int) ($x[0]) >> ($c1 - 32); } return self::new64($h0 | $h1, $l0 | $l1); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @return int * @psalm-suppress MixedOperand */ protected static function flatten64($x) { return (int) ($x[0] * 4294967296 + $x[1]); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $i * @return SplFixedArray * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayOffset */ protected static function load64(SplFixedArray $x, $i) { /** @var int $l */ $l = (int) ($x[$i]) | ((int) ($x[$i+1]) << 8) | ((int) ($x[$i+2]) << 16) | ((int) ($x[$i+3]) << 24); /** @var int $h */ $h = (int) ($x[$i+4]) | ((int) ($x[$i+5]) << 8) | ((int) ($x[$i+6]) << 16) | ((int) ($x[$i+7]) << 24); return self::new64($h, $l); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $i * @param SplFixedArray $u * @return void * @psalm-suppress MixedAssignment */ protected static function store64(SplFixedArray $x, $i, SplFixedArray $u) { $maxLength = $x->getSize() - 1; for ($j = 0; $j < 8; ++$j) { /* [0, 1, 2, 3, 4, 5, 6, 7] ... becomes ... [0, 0, 0, 0, 1, 1, 1, 1] */ /** @var int $uIdx */ $uIdx = ((7 - $j) & 4) >> 2; $x[$i] = ((int) ($u[$uIdx]) & 0xff); if (++$i > $maxLength) { return; } /** @psalm-suppress MixedOperand */ $u[$uIdx] >>= 8; } } /** * This just sets the $iv static variable. * * @internal You should not use this directly from another application * * @return void */ public static function pseudoConstructor() { static $called = false; if ($called) { return; } self::$iv = new SplFixedArray(8); self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908); self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b); self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b); self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1); self::$iv[4] = self::new64(0x510e527f, 0xade682d1); self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f); self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b); self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179); $called = true; } /** * Returns a fresh BLAKE2 context. * * @internal You should not use this directly from another application * * @return SplFixedArray * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment */ protected static function context() { $ctx = new SplFixedArray(6); $ctx[0] = new SplFixedArray(8); // h $ctx[1] = new SplFixedArray(2); // t $ctx[2] = new SplFixedArray(2); // f $ctx[3] = new SplFixedArray(256); // buf $ctx[4] = 0; // buflen $ctx[5] = 0; // last_node (uint8_t) for ($i = 8; $i--;) { $ctx[0][$i] = self::$iv[$i]; } for ($i = 256; $i--;) { $ctx[3][$i] = 0; } $zero = self::new64(0, 0); $ctx[1][0] = $zero; $ctx[1][1] = $zero; $ctx[2][0] = $zero; $ctx[2][1] = $zero; return $ctx; } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $buf * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset */ protected static function compress(SplFixedArray $ctx, SplFixedArray $buf) { $m = new SplFixedArray(16); $v = new SplFixedArray(16); for ($i = 16; $i--;) { $m[$i] = self::load64($buf, $i << 3); } for ($i = 8; $i--;) { $v[$i] = $ctx[0][$i]; } $v[ 8] = self::$iv[0]; $v[ 9] = self::$iv[1]; $v[10] = self::$iv[2]; $v[11] = self::$iv[3]; $v[12] = self::xor64($ctx[1][0], self::$iv[4]); $v[13] = self::xor64($ctx[1][1], self::$iv[5]); $v[14] = self::xor64($ctx[2][0], self::$iv[6]); $v[15] = self::xor64($ctx[2][1], self::$iv[7]); for ($r = 0; $r < 12; ++$r) { $v = self::G($r, 0, 0, 4, 8, 12, $v, $m); $v = self::G($r, 1, 1, 5, 9, 13, $v, $m); $v = self::G($r, 2, 2, 6, 10, 14, $v, $m); $v = self::G($r, 3, 3, 7, 11, 15, $v, $m); $v = self::G($r, 4, 0, 5, 10, 15, $v, $m); $v = self::G($r, 5, 1, 6, 11, 12, $v, $m); $v = self::G($r, 6, 2, 7, 8, 13, $v, $m); $v = self::G($r, 7, 3, 4, 9, 14, $v, $m); } for ($i = 8; $i--;) { $ctx[0][$i] = self::xor64( $ctx[0][$i], self::xor64($v[$i], $v[$i+8]) ); } } /** * @internal You should not use this directly from another application * * @param int $r * @param int $i * @param int $a * @param int $b * @param int $c * @param int $d * @param SplFixedArray $v * @param SplFixedArray $m * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayOffset */ public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v, SplFixedArray $m) { $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]); $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32); $v[$c] = self::add64($v[$c], $v[$d]); $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24); $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]); $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16); $v[$c] = self::add64($v[$c], $v[$d]); $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63); return $v; } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param int $inc * @return void * @throws SodiumException * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment */ public static function increment_counter($ctx, $inc) { if ($inc < 0) { throw new SodiumException('Increasing by a negative number makes no sense.'); } $t = self::to64($inc); # S->t is $ctx[1] in our implementation # S->t[0] = ( uint64_t )( t >> 0 ); $ctx[1][0] = self::add64($ctx[1][0], $t); # S->t[1] += ( S->t[0] < inc ); if (self::flatten64($ctx[1][0]) < $inc) { $ctx[1][1] = self::add64($ctx[1][1], self::to64(1)); } } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $p * @param int $plen * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedOperand */ public static function update(SplFixedArray $ctx, SplFixedArray $p, $plen) { self::pseudoConstructor(); $offset = 0; while ($plen > 0) { $left = $ctx[4]; $fill = 256 - $left; if ($plen > $fill) { # memcpy( S->buf + left, in, fill ); /* Fill buffer */ for ($i = $fill; $i--;) { $ctx[3][$i + $left] = $p[$i + $offset]; } # S->buflen += fill; $ctx[4] += $fill; # blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); self::increment_counter($ctx, 128); # blake2b_compress( S, S->buf ); /* Compress */ self::compress($ctx, $ctx[3]); # memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */ for ($i = 128; $i--;) { $ctx[3][$i] = $ctx[3][$i + 128]; } # S->buflen -= BLAKE2B_BLOCKBYTES; $ctx[4] -= 128; # in += fill; $offset += $fill; # inlen -= fill; $plen -= $fill; } else { for ($i = $plen; $i--;) { $ctx[3][$i + $left] = $p[$i + $offset]; } $ctx[4] += $plen; $offset += $plen; $plen -= $plen; } } } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $out * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedOperand */ public static function finish(SplFixedArray $ctx, SplFixedArray $out) { self::pseudoConstructor(); if ($ctx[4] > 128) { self::increment_counter($ctx, 128); self::compress($ctx, $ctx[3]); $ctx[4] -= 128; if ($ctx[4] > 128) { throw new SodiumException('Failed to assert that buflen <= 128 bytes'); } for ($i = $ctx[4]; $i--;) { $ctx[3][$i] = $ctx[3][$i + 128]; } } self::increment_counter($ctx, $ctx[4]); $ctx[2][0] = self::new64(0xffffffff, 0xffffffff); for ($i = 256 - $ctx[4]; $i--;) { $ctx[3][$i+$ctx[4]] = 0; } self::compress($ctx, $ctx[3]); $i = (int) (($out->getSize() - 1) / 8); for (; $i >= 0; --$i) { self::store64($out, $i << 3, $ctx[0][$i]); } return $out; } /** * @internal You should not use this directly from another application * * @param SplFixedArray|null $key * @param int $outlen * @param SplFixedArray|null $salt * @param SplFixedArray|null $personal * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset */ public static function init( $key = null, $outlen = 64, $salt = null, $personal = null ) { self::pseudoConstructor(); $klen = 0; if ($key !== null) { if (count($key) > 64) { throw new SodiumException('Invalid key size'); } $klen = count($key); } if ($outlen > 64) { throw new SodiumException('Invalid output size'); } $ctx = self::context(); $p = new SplFixedArray(64); // Zero our param buffer... for ($i = 64; --$i;) { $p[$i] = 0; } $p[0] = $outlen; // digest_length $p[1] = $klen; // key_length $p[2] = 1; // fanout $p[3] = 1; // depth if ($salt instanceof SplFixedArray) { // salt: [32] through [47] for ($i = 0; $i < 16; ++$i) { $p[32 + $i] = (int) $salt[$i]; } } if ($personal instanceof SplFixedArray) { // personal: [48] through [63] for ($i = 0; $i < 16; ++$i) { $p[48 + $i] = (int) $personal[$i]; } } $ctx[0][0] = self::xor64( $ctx[0][0], self::load64($p, 0) ); if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) { // We need to do what blake2b_init_param() does: for ($i = 1; $i < 8; ++$i) { $ctx[0][$i] = self::xor64( $ctx[0][$i], self::load64($p, $i << 3) ); } } if ($klen > 0 && $key instanceof SplFixedArray) { $block = new SplFixedArray(128); for ($i = 128; $i--;) { $block[$i] = 0; } for ($i = $klen; $i--;) { $block[$i] = $key[$i]; } self::update($ctx, $block, 128); $ctx[4] = 128; } return $ctx; } /** * Convert a string into an SplFixedArray of integers * * @internal You should not use this directly from another application * * @param string $str * @return SplFixedArray * @psalm-suppress MixedArgumentTypeCoercion */ public static function stringToSplFixedArray($str = '') { $values = unpack('C*', $str); return SplFixedArray::fromArray(array_values($values)); } /** * Convert an SplFixedArray of integers into a string * * @internal You should not use this directly from another application * * @param SplFixedArray $a * @return string * @throws TypeError */ public static function SplFixedArrayToString(SplFixedArray $a) { /** * @var array<int, int|string> $arr */ $arr = $a->toArray(); $c = $a->count(); array_unshift($arr, str_repeat('C', $c)); return (string) (call_user_func_array('pack', $arr)); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @return string * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedMethodCall */ public static function contextToString(SplFixedArray $ctx) { $str = ''; /** @var array<int, array<int, int>> $ctxA */ $ctxA = $ctx[0]->toArray(); # uint64_t h[8]; for ($i = 0; $i < 8; ++$i) { $str .= self::store32_le($ctxA[$i][1]); $str .= self::store32_le($ctxA[$i][0]); } # uint64_t t[2]; # uint64_t f[2]; for ($i = 1; $i < 3; ++$i) { $ctxA = $ctx[$i]->toArray(); $str .= self::store32_le($ctxA[0][1]); $str .= self::store32_le($ctxA[0][0]); $str .= self::store32_le($ctxA[1][1]); $str .= self::store32_le($ctxA[1][0]); } # uint8_t buf[2 * 128]; $str .= self::SplFixedArrayToString($ctx[3]); /** @var int $ctx4 */ $ctx4 = (int) $ctx[4]; # size_t buflen; $str .= implode('', array( self::intToChr($ctx4 & 0xff), self::intToChr(($ctx4 >> 8) & 0xff), self::intToChr(($ctx4 >> 16) & 0xff), self::intToChr(($ctx4 >> 24) & 0xff), self::intToChr(($ctx4 >> 32) & 0xff), self::intToChr(($ctx4 >> 40) & 0xff), self::intToChr(($ctx4 >> 48) & 0xff), self::intToChr(($ctx4 >> 56) & 0xff) )); # uint8_t last_node; return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23); } /** * Creates an SplFixedArray containing other SplFixedArray elements, from * a string (compatible with \Sodium\crypto_generichash_{init, update, final}) * * @internal You should not use this directly from another application * * @param string $string * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAssignment */ public static function stringToContext($string) { $ctx = self::context(); # uint64_t h[8]; for ($i = 0; $i < 8; ++$i) { $ctx[0][$i] = SplFixedArray::fromArray( array( self::load_4( self::substr($string, (($i << 3) + 4), 4) ), self::load_4( self::substr($string, (($i << 3) + 0), 4) ) ) ); } # uint64_t t[2]; # uint64_t f[2]; for ($i = 1; $i < 3; ++$i) { $ctx[$i][1] = SplFixedArray::fromArray( array( self::load_4(self::substr($string, 76 + (($i - 1) << 4), 4)), self::load_4(self::substr($string, 72 + (($i - 1) << 4), 4)) ) ); $ctx[$i][0] = SplFixedArray::fromArray( array( self::load_4(self::substr($string, 68 + (($i - 1) << 4), 4)), self::load_4(self::substr($string, 64 + (($i - 1) << 4), 4)) ) ); } # uint8_t buf[2 * 128]; $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256)); # uint8_t buf[2 * 128]; $int = 0; for ($i = 0; $i < 8; ++$i) { $int |= self::chrToInt($string[352 + $i]) << ($i << 3); } $ctx[4] = $int; return $ctx; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AEGIS/State256.php�����������������������������������������������������������������������������0000644�����������������00000014575�15021200076�0010317 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_AEGIS_State256', false)) { return; } if (!defined('SODIUM_COMPAT_AEGIS_C0')) { define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62"); } if (!defined('SODIUM_COMPAT_AEGIS_C1')) { define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd"); } class ParagonIE_Sodium_Core_AEGIS_State256 { /** @var array<int, string> $state */ protected $state; public function __construct() { $this->state = array_fill(0, 6, ''); } /** * @internal Only use this for unit tests! * @return string[] */ public function getState() { return array_values($this->state); } /** * @param array $input * @return self * @throws SodiumException * * @internal Only for unit tests */ public static function initForUnitTests(array $input) { if (count($input) < 6) { throw new SodiumException('invalid input'); } $state = new self(); for ($i = 0; $i < 6; ++$i) { $state->state[$i] = $input[$i]; } return $state; } /** * @param string $key * @param string $nonce * @return self */ public static function init($key, $nonce) { $state = new self(); $k0 = ParagonIE_Sodium_Core_Util::substr($key, 0, 16); $k1 = ParagonIE_Sodium_Core_Util::substr($key, 16, 16); $n0 = ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16); $n1 = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16); // S0 = k0 ^ n0 // S1 = k1 ^ n1 // S2 = C1 // S3 = C0 // S4 = k0 ^ C0 // S5 = k1 ^ C1 $k0_n0 = $k0 ^ $n0; $k1_n1 = $k1 ^ $n1; $state->state[0] = $k0_n0; $state->state[1] = $k1_n1; $state->state[2] = SODIUM_COMPAT_AEGIS_C1; $state->state[3] = SODIUM_COMPAT_AEGIS_C0; $state->state[4] = $k0 ^ SODIUM_COMPAT_AEGIS_C0; $state->state[5] = $k1 ^ SODIUM_COMPAT_AEGIS_C1; // Repeat(4, // Update(k0) // Update(k1) // Update(k0 ^ n0) // Update(k1 ^ n1) // ) for ($i = 0; $i < 4; ++$i) { $state->update($k0); $state->update($k1); $state->update($k0 ^ $n0); $state->update($k1 ^ $n1); } return $state; } /** * @param string $ai * @return self * @throws SodiumException */ public function absorb($ai) { if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) { throw new SodiumException('Input must be an AES block in size'); } return $this->update($ai); } /** * @param string $ci * @return string * @throws SodiumException */ public function dec($ci) { if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) { throw new SodiumException('Input must be an AES block in size'); } // z = S1 ^ S4 ^ S5 ^ (S2 & S3) $z = $this->state[1] ^ $this->state[4] ^ $this->state[5] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); $xi = $ci ^ $z; $this->update($xi); return $xi; } /** * @param string $cn * @return string */ public function decPartial($cn) { $len = ParagonIE_Sodium_Core_Util::strlen($cn); // z = S1 ^ S4 ^ S5 ^ (S2 & S3) $z = $this->state[1] ^ $this->state[4] ^ $this->state[5] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); // t = ZeroPad(cn, 128) $t = str_pad($cn, 16, "\0", STR_PAD_RIGHT); // out = t ^ z $out = $t ^ $z; // xn = Truncate(out, |cn|) $xn = ParagonIE_Sodium_Core_Util::substr($out, 0, $len); // v = ZeroPad(xn, 128) $v = str_pad($xn, 16, "\0", STR_PAD_RIGHT); // Update(v) $this->update($v); // return xn return $xn; } /** * @param string $xi * @return string * @throws SodiumException */ public function enc($xi) { if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) { throw new SodiumException('Input must be an AES block in size'); } // z = S1 ^ S4 ^ S5 ^ (S2 & S3) $z = $this->state[1] ^ $this->state[4] ^ $this->state[5] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); $this->update($xi); return $xi ^ $z; } /** * @param int $ad_len_bits * @param int $msg_len_bits * @return string */ public function finalize($ad_len_bits, $msg_len_bits) { $encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) . ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits); $t = $this->state[3] ^ $encoded; for ($i = 0; $i < 7; ++$i) { $this->update($t); } return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) . ($this->state[3] ^ $this->state[4] ^ $this->state[5]); } /** * @param string $m * @return self */ public function update($m) { /* S'0 = AESRound(S5, S0 ^ M) S'1 = AESRound(S0, S1) S'2 = AESRound(S1, S2) S'3 = AESRound(S2, S3) S'4 = AESRound(S3, S4) S'5 = AESRound(S4, S5) */ list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[5],$this->state[0] ^ $m, $this->state[0], $this->state[1] ); list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[1], $this->state[2], $this->state[2], $this->state[3] ); list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[3], $this->state[4], $this->state[4], $this->state[5] ); /* S0 = S'0 S1 = S'1 S2 = S'2 S3 = S'3 S4 = S'4 S5 = S'5 */ $this->state[0] = $s_0; $this->state[1] = $s_1; $this->state[2] = $s_2; $this->state[3] = $s_3; $this->state[4] = $s_4; $this->state[5] = $s_5; return $this; } } �����������������������������������������������������������������������������������������������������������������������������������Core/AEGIS/State128L.php����������������������������������������������������������������������������0000644�����������������00000020052�15021200076�0010414 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_AEGIS_State128L', false)) { return; } if (!defined('SODIUM_COMPAT_AEGIS_C0')) { define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62"); } if (!defined('SODIUM_COMPAT_AEGIS_C1')) { define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd"); } class ParagonIE_Sodium_Core_AEGIS_State128L { /** @var array<int, string> $state */ protected $state; public function __construct() { $this->state = array_fill(0, 8, ''); } /** * @internal Only use this for unit tests! * @return string[] */ public function getState() { return array_values($this->state); } /** * @param array $input * @return self * @throws SodiumException * * @internal Only for unit tests */ public static function initForUnitTests(array $input) { if (count($input) < 8) { throw new SodiumException('invalid input'); } $state = new self(); for ($i = 0; $i < 8; ++$i) { $state->state[$i] = $input[$i]; } return $state; } /** * @param string $key * @param string $nonce * @return self */ public static function init($key, $nonce) { $state = new self(); // S0 = key ^ nonce $state->state[0] = $key ^ $nonce; // S1 = C1 $state->state[1] = SODIUM_COMPAT_AEGIS_C1; // S2 = C0 $state->state[2] = SODIUM_COMPAT_AEGIS_C0; // S3 = C1 $state->state[3] = SODIUM_COMPAT_AEGIS_C1; // S4 = key ^ nonce $state->state[4] = $key ^ $nonce; // S5 = key ^ C0 $state->state[5] = $key ^ SODIUM_COMPAT_AEGIS_C0; // S6 = key ^ C1 $state->state[6] = $key ^ SODIUM_COMPAT_AEGIS_C1; // S7 = key ^ C0 $state->state[7] = $key ^ SODIUM_COMPAT_AEGIS_C0; // Repeat(10, Update(nonce, key)) for ($i = 0; $i < 10; ++$i) { $state->update($nonce, $key); } return $state; } /** * @param string $ai * @return self */ public function absorb($ai) { if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) { throw new SodiumException('Input must be two AES blocks in size'); } $t0 = ParagonIE_Sodium_Core_Util::substr($ai, 0, 16); $t1 = ParagonIE_Sodium_Core_Util::substr($ai, 16, 16); return $this->update($t0, $t1); } /** * @param string $ci * @return string * @throws SodiumException */ public function dec($ci) { if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) { throw new SodiumException('Input must be two AES blocks in size'); } // z0 = S6 ^ S1 ^ (S2 & S3) $z0 = $this->state[6] ^ $this->state[1] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); // z1 = S2 ^ S5 ^ (S6 & S7) $z1 = $this->state[2] ^ $this->state[5] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]); // t0, t1 = Split(xi, 128) $t0 = ParagonIE_Sodium_Core_Util::substr($ci, 0, 16); $t1 = ParagonIE_Sodium_Core_Util::substr($ci, 16, 16); // out0 = t0 ^ z0 // out1 = t1 ^ z1 $out0 = $t0 ^ $z0; $out1 = $t1 ^ $z1; // Update(out0, out1) // xi = out0 || out1 $this->update($out0, $out1); return $out0 . $out1; } /** * @param string $cn * @return string */ public function decPartial($cn) { $len = ParagonIE_Sodium_Core_Util::strlen($cn); // z0 = S6 ^ S1 ^ (S2 & S3) $z0 = $this->state[6] ^ $this->state[1] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); // z1 = S2 ^ S5 ^ (S6 & S7) $z1 = $this->state[2] ^ $this->state[5] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]); // t0, t1 = Split(ZeroPad(cn, 256), 128) $cn = str_pad($cn, 32, "\0", STR_PAD_RIGHT); $t0 = ParagonIE_Sodium_Core_Util::substr($cn, 0, 16); $t1 = ParagonIE_Sodium_Core_Util::substr($cn, 16, 16); // out0 = t0 ^ z0 // out1 = t1 ^ z1 $out0 = $t0 ^ $z0; $out1 = $t1 ^ $z1; // xn = Truncate(out0 || out1, |cn|) $xn = ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len); // v0, v1 = Split(ZeroPad(xn, 256), 128) $padded = str_pad($xn, 32, "\0", STR_PAD_RIGHT); $v0 = ParagonIE_Sodium_Core_Util::substr($padded, 0, 16); $v1 = ParagonIE_Sodium_Core_Util::substr($padded, 16, 16); // Update(v0, v1) $this->update($v0, $v1); // return xn return $xn; } /** * @param string $xi * @return string * @throws SodiumException */ public function enc($xi) { if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) { throw new SodiumException('Input must be two AES blocks in size'); } // z0 = S6 ^ S1 ^ (S2 & S3) $z0 = $this->state[6] ^ $this->state[1] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]); // z1 = S2 ^ S5 ^ (S6 & S7) $z1 = $this->state[2] ^ $this->state[5] ^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]); // t0, t1 = Split(xi, 128) $t0 = ParagonIE_Sodium_Core_Util::substr($xi, 0, 16); $t1 = ParagonIE_Sodium_Core_Util::substr($xi, 16, 16); // out0 = t0 ^ z0 // out1 = t1 ^ z1 $out0 = $t0 ^ $z0; $out1 = $t1 ^ $z1; // Update(t0, t1) // ci = out0 || out1 $this->update($t0, $t1); // return ci return $out0 . $out1; } /** * @param int $ad_len_bits * @param int $msg_len_bits * @return string */ public function finalize($ad_len_bits, $msg_len_bits) { $encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) . ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits); $t = $this->state[2] ^ $encoded; for ($i = 0; $i < 7; ++$i) { $this->update($t, $t); } return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) . ($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]); } /** * @param string $m0 * @param string $m1 * @return self */ public function update($m0, $m1) { /* S'0 = AESRound(S7, S0 ^ M0) S'1 = AESRound(S0, S1) S'2 = AESRound(S1, S2) S'3 = AESRound(S2, S3) S'4 = AESRound(S3, S4 ^ M1) S'5 = AESRound(S4, S5) S'6 = AESRound(S5, S6) S'7 = AESRound(S6, S7) */ list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[7], $this->state[0] ^ $m0, $this->state[0], $this->state[1] ); list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[1], $this->state[2], $this->state[2], $this->state[3] ); list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[3], $this->state[4] ^ $m1, $this->state[4], $this->state[5] ); list($s_6, $s_7) = ParagonIE_Sodium_Core_AES::doubleRound( $this->state[5], $this->state[6], $this->state[6], $this->state[7] ); /* S0 = S'0 S1 = S'1 S2 = S'2 S3 = S'3 S4 = S'4 S5 = S'5 S6 = S'6 S7 = S'7 */ $this->state[0] = $s_0; $this->state[1] = $s_1; $this->state[2] = $s_2; $this->state[3] = $s_3; $this->state[4] = $s_4; $this->state[5] = $s_5; $this->state[6] = $s_6; $this->state[7] = $s_7; return $this; } }��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/ChaCha20/Ctx.php�������������������������������������������������������������������������������0000644�����������������00000007546�15021200076�0010161 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) { return; } /** * Class ParagonIE_Sodium_Core_ChaCha20_Ctx */ class ParagonIE_Sodium_Core_ChaCha20_Ctx extends ParagonIE_Sodium_Core_Util implements ArrayAccess { /** * @var SplFixedArray internally, <int, int> */ protected $container; /** * ParagonIE_Sodium_Core_ChaCha20_Ctx constructor. * * @internal You should not use this directly from another application * * @param string $key ChaCha20 key. * @param string $iv Initialization Vector (a.k.a. nonce). * @param string $counter The initial counter value. * Defaults to 8 0x00 bytes. * @throws InvalidArgumentException * @throws TypeError */ public function __construct($key = '', $iv = '', $counter = '') { if (self::strlen($key) !== 32) { throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.'); } if (self::strlen($iv) !== 8) { throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.'); } $this->container = new SplFixedArray(16); /* "expand 32-byte k" as per ChaCha20 spec */ $this->container[0] = 0x61707865; $this->container[1] = 0x3320646e; $this->container[2] = 0x79622d32; $this->container[3] = 0x6b206574; $this->container[4] = self::load_4(self::substr($key, 0, 4)); $this->container[5] = self::load_4(self::substr($key, 4, 4)); $this->container[6] = self::load_4(self::substr($key, 8, 4)); $this->container[7] = self::load_4(self::substr($key, 12, 4)); $this->container[8] = self::load_4(self::substr($key, 16, 4)); $this->container[9] = self::load_4(self::substr($key, 20, 4)); $this->container[10] = self::load_4(self::substr($key, 24, 4)); $this->container[11] = self::load_4(self::substr($key, 28, 4)); if (empty($counter)) { $this->container[12] = 0; $this->container[13] = 0; } else { $this->container[12] = self::load_4(self::substr($counter, 0, 4)); $this->container[13] = self::load_4(self::substr($counter, 4, 4)); } $this->container[14] = self::load_4(self::substr($iv, 0, 4)); $this->container[15] = self::load_4(self::substr($iv, 4, 4)); } /** * @internal You should not use this directly from another application * * @param int $offset * @param int $value * @return void * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if (!is_int($offset)) { throw new InvalidArgumentException('Expected an integer'); } if (!is_int($value)) { throw new InvalidArgumentException('Expected an integer'); } $this->container[$offset] = $value; } /** * @internal You should not use this directly from another application * * @param int $offset * @return bool */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return void * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return mixed|null * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetGet($offset) { return isset($this->container[$offset]) ? $this->container[$offset] : null; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������Core/ChaCha20/IetfCtx.php���������������������������������������������������������������������������0000644�����������������00000002452�15021200076�0010760 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', false)) { return; } /** * Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx */ class ParagonIE_Sodium_Core_ChaCha20_IetfCtx extends ParagonIE_Sodium_Core_ChaCha20_Ctx { /** * ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor. * * @internal You should not use this directly from another application * * @param string $key ChaCha20 key. * @param string $iv Initialization Vector (a.k.a. nonce). * @param string $counter The initial counter value. * Defaults to 4 0x00 bytes. * @throws InvalidArgumentException * @throws TypeError */ public function __construct($key = '', $iv = '', $counter = '') { if (self::strlen($iv) !== 12) { throw new InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.'); } parent::__construct($key, self::substr($iv, 0, 8), $counter); if (!empty($counter)) { $this->container[12] = self::load_4(self::substr($counter, 0, 4)); } $this->container[13] = self::load_4(self::substr($iv, 0, 4)); $this->container[14] = self::load_4(self::substr($iv, 4, 4)); $this->container[15] = self::load_4(self::substr($iv, 8, 4)); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AEGIS256.php�����������������������������������������������������������������������������������0000644�����������������00000007016�15021200076�0007227 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (!defined('SODIUM_COMPAT_AEGIS_C0')) { define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62"); } if (!defined('SODIUM_COMPAT_AEGIS_C1')) { define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd"); } class ParagonIE_Sodium_Core_AEGIS256 extends ParagonIE_Sodium_Core_AES { /** * @param string $ct * @param string $tag * @param string $ad * @param string $key * @param string $nonce * @return string * @throws SodiumException */ public static function decrypt($ct, $tag, $ad, $key, $nonce) { $state = self::init($key, $nonce); // ad_blocks = Split(ZeroPad(ad, 128), 128) $ad_blocks = (self::strlen($ad) + 15) >> 4; // for ai in ad_blocks: // Absorb(ai) for ($i = 0; $i < $ad_blocks; ++$i) { $ai = self::substr($ad, $i << 4, 16); if (self::strlen($ai) < 16) { $ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT); } $state->absorb($ai); } $msg = ''; $cn = self::strlen($ct) & 15; $ct_blocks = self::strlen($ct) >> 4; // ct_blocks = Split(ZeroPad(ct, 128), 128) // cn = Tail(ct, |ct| mod 128) for ($i = 0; $i < $ct_blocks; ++$i) { $msg .= $state->dec(self::substr($ct, $i << 4, 16)); } // if cn is not empty: // msg = msg || DecPartial(cn) if ($cn) { $start = $ct_blocks << 4; $msg .= $state->decPartial(self::substr($ct, $start, $cn)); } $expected_tag = $state->finalize( self::strlen($ad) << 3, self::strlen($msg) << 3 ); if (!self::hashEquals($expected_tag, $tag)) { try { // The RFC says to erase msg, so we shall try: ParagonIE_Sodium_Compat::memzero($msg); } catch (SodiumException $ex) { // Do nothing if we cannot memzero } throw new SodiumException('verification failed'); } return $msg; } /** * @param string $msg * @param string $ad * @param string $key * @param string $nonce * @return array * @throws SodiumException */ public static function encrypt($msg, $ad, $key, $nonce) { $state = self::init($key, $nonce); $ad_len = self::strlen($ad); $msg_len = self::strlen($msg); $ad_blocks = ($ad_len + 15) >> 4; for ($i = 0; $i < $ad_blocks; ++$i) { $ai = self::substr($ad, $i << 4, 16); if (self::strlen($ai) < 16) { $ai = str_pad($ai, 16, "\0", STR_PAD_RIGHT); } $state->absorb($ai); } $ct = ''; $msg_blocks = ($msg_len + 15) >> 4; for ($i = 0; $i < $msg_blocks; ++$i) { $xi = self::substr($msg, $i << 4, 16); if (self::strlen($xi) < 16) { $xi = str_pad($xi, 16, "\0", STR_PAD_RIGHT); } $ct .= $state->enc($xi); } $tag = $state->finalize( $ad_len << 3, $msg_len << 3 ); return array( self::substr($ct, 0, $msg_len), $tag ); } /** * @param string $key * @param string $nonce * @return ParagonIE_Sodium_Core_AEGIS_State256 */ public static function init($key, $nonce) { return ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/XChaCha20.php����������������������������������������������������������������������������������0000644�����������������00000006452�15021200076�0007546 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_XChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core_XChaCha20 */ class ParagonIE_Sodium_Core_XChaCha20 extends ParagonIE_Sodium_Core_HChaCha20 { /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function stream($len = 64, $nonce = '', $key = '') { if (self::strlen($nonce) !== 24) { throw new SodiumException('Nonce must be 24 bytes long'); } return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_Ctx( self::hChaCha20( self::substr($nonce, 0, 16), $key ), self::substr($nonce, 16, 8) ), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStream($len = 64, $nonce = '', $key = '') { if (self::strlen($nonce) !== 24) { throw new SodiumException('Nonce must be 24 bytes long'); } return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_IetfCtx( self::hChaCha20( self::substr($nonce, 0, 16), $key ), "\x00\x00\x00\x00" . self::substr($nonce, 16, 8) ), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function streamXorIc($message, $nonce = '', $key = '', $ic = '') { if (self::strlen($nonce) !== 24) { throw new SodiumException('Nonce must be 24 bytes long'); } return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_Ctx( self::hChaCha20(self::substr($nonce, 0, 16), $key), self::substr($nonce, 16, 8), $ic ), $message ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '') { if (self::strlen($nonce) !== 24) { throw new SodiumException('Nonce must be 24 bytes long'); } return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_IetfCtx( self::hChaCha20(self::substr($nonce, 0, 16), $key), "\x00\x00\x00\x00" . self::substr($nonce, 16, 8), $ic ), $message ); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/HChaCha20.php����������������������������������������������������������������������������������0000644�����������������00000007437�15021200076�0007532 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_HChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core_HChaCha20 */ class ParagonIE_Sodium_Core_HChaCha20 extends ParagonIE_Sodium_Core_ChaCha20 { /** * @param string $in * @param string $key * @param string|null $c * @return string * @throws TypeError */ public static function hChaCha20($in = '', $key = '', $c = null) { $ctx = array(); if ($c === null) { $ctx[0] = 0x61707865; $ctx[1] = 0x3320646e; $ctx[2] = 0x79622d32; $ctx[3] = 0x6b206574; } else { $ctx[0] = self::load_4(self::substr($c, 0, 4)); $ctx[1] = self::load_4(self::substr($c, 4, 4)); $ctx[2] = self::load_4(self::substr($c, 8, 4)); $ctx[3] = self::load_4(self::substr($c, 12, 4)); } $ctx[4] = self::load_4(self::substr($key, 0, 4)); $ctx[5] = self::load_4(self::substr($key, 4, 4)); $ctx[6] = self::load_4(self::substr($key, 8, 4)); $ctx[7] = self::load_4(self::substr($key, 12, 4)); $ctx[8] = self::load_4(self::substr($key, 16, 4)); $ctx[9] = self::load_4(self::substr($key, 20, 4)); $ctx[10] = self::load_4(self::substr($key, 24, 4)); $ctx[11] = self::load_4(self::substr($key, 28, 4)); $ctx[12] = self::load_4(self::substr($in, 0, 4)); $ctx[13] = self::load_4(self::substr($in, 4, 4)); $ctx[14] = self::load_4(self::substr($in, 8, 4)); $ctx[15] = self::load_4(self::substr($in, 12, 4)); return self::hChaCha20Bytes($ctx); } /** * @param array $ctx * @return string * @throws TypeError */ protected static function hChaCha20Bytes(array $ctx) { $x0 = (int) $ctx[0]; $x1 = (int) $ctx[1]; $x2 = (int) $ctx[2]; $x3 = (int) $ctx[3]; $x4 = (int) $ctx[4]; $x5 = (int) $ctx[5]; $x6 = (int) $ctx[6]; $x7 = (int) $ctx[7]; $x8 = (int) $ctx[8]; $x9 = (int) $ctx[9]; $x10 = (int) $ctx[10]; $x11 = (int) $ctx[11]; $x12 = (int) $ctx[12]; $x13 = (int) $ctx[13]; $x14 = (int) $ctx[14]; $x15 = (int) $ctx[15]; for ($i = 0; $i < 10; ++$i) { # QUARTERROUND( x0, x4, x8, x12) list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12); # QUARTERROUND( x1, x5, x9, x13) list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13); # QUARTERROUND( x2, x6, x10, x14) list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14); # QUARTERROUND( x3, x7, x11, x15) list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15); # QUARTERROUND( x0, x5, x10, x15) list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15); # QUARTERROUND( x1, x6, x11, x12) list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12); # QUARTERROUND( x2, x7, x8, x13) list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13); # QUARTERROUND( x3, x4, x9, x14) list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14); } return self::store32_le((int) ($x0 & 0xffffffff)) . self::store32_le((int) ($x1 & 0xffffffff)) . self::store32_le((int) ($x2 & 0xffffffff)) . self::store32_le((int) ($x3 & 0xffffffff)) . self::store32_le((int) ($x12 & 0xffffffff)) . self::store32_le((int) ($x13 & 0xffffffff)) . self::store32_le((int) ($x14 & 0xffffffff)) . self::store32_le((int) ($x15 & 0xffffffff)); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/X25519.php�������������������������������������������������������������������������������������0000644�����������������00000022352�15021200076�0006757 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_X25519', false)) { return; } /** * Class ParagonIE_Sodium_Core_X25519 */ abstract class ParagonIE_Sodium_Core_X25519 extends ParagonIE_Sodium_Core_Curve25519 { /** * Alters the objects passed to this method in place. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @param ParagonIE_Sodium_Core_Curve25519_Fe $g * @param int $b * @return void * @psalm-suppress MixedAssignment */ public static function fe_cswap( ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g, $b = 0 ) { $f0 = (int) $f[0]; $f1 = (int) $f[1]; $f2 = (int) $f[2]; $f3 = (int) $f[3]; $f4 = (int) $f[4]; $f5 = (int) $f[5]; $f6 = (int) $f[6]; $f7 = (int) $f[7]; $f8 = (int) $f[8]; $f9 = (int) $f[9]; $g0 = (int) $g[0]; $g1 = (int) $g[1]; $g2 = (int) $g[2]; $g3 = (int) $g[3]; $g4 = (int) $g[4]; $g5 = (int) $g[5]; $g6 = (int) $g[6]; $g7 = (int) $g[7]; $g8 = (int) $g[8]; $g9 = (int) $g[9]; $b = -$b; $x0 = ($f0 ^ $g0) & $b; $x1 = ($f1 ^ $g1) & $b; $x2 = ($f2 ^ $g2) & $b; $x3 = ($f3 ^ $g3) & $b; $x4 = ($f4 ^ $g4) & $b; $x5 = ($f5 ^ $g5) & $b; $x6 = ($f6 ^ $g6) & $b; $x7 = ($f7 ^ $g7) & $b; $x8 = ($f8 ^ $g8) & $b; $x9 = ($f9 ^ $g9) & $b; $f[0] = $f0 ^ $x0; $f[1] = $f1 ^ $x1; $f[2] = $f2 ^ $x2; $f[3] = $f3 ^ $x3; $f[4] = $f4 ^ $x4; $f[5] = $f5 ^ $x5; $f[6] = $f6 ^ $x6; $f[7] = $f7 ^ $x7; $f[8] = $f8 ^ $x8; $f[9] = $f9 ^ $x9; $g[0] = $g0 ^ $x0; $g[1] = $g1 ^ $x1; $g[2] = $g2 ^ $x2; $g[3] = $g3 ^ $x3; $g[4] = $g4 ^ $x4; $g[5] = $g5 ^ $x5; $g[6] = $g6 ^ $x6; $g[7] = $g7 ^ $x7; $g[8] = $g8 ^ $x8; $g[9] = $g9 ^ $x9; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $f * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function fe_mul121666(ParagonIE_Sodium_Core_Curve25519_Fe $f) { $h = array( self::mul((int) $f[0], 121666, 17), self::mul((int) $f[1], 121666, 17), self::mul((int) $f[2], 121666, 17), self::mul((int) $f[3], 121666, 17), self::mul((int) $f[4], 121666, 17), self::mul((int) $f[5], 121666, 17), self::mul((int) $f[6], 121666, 17), self::mul((int) $f[7], 121666, 17), self::mul((int) $f[8], 121666, 17), self::mul((int) $f[9], 121666, 17) ); /** @var int $carry9 */ $carry9 = ($h[9] + (1 << 24)) >> 25; $h[0] += self::mul($carry9, 19, 5); $h[9] -= $carry9 << 25; /** @var int $carry1 */ $carry1 = ($h[1] + (1 << 24)) >> 25; $h[2] += $carry1; $h[1] -= $carry1 << 25; /** @var int $carry3 */ $carry3 = ($h[3] + (1 << 24)) >> 25; $h[4] += $carry3; $h[3] -= $carry3 << 25; /** @var int $carry5 */ $carry5 = ($h[5] + (1 << 24)) >> 25; $h[6] += $carry5; $h[5] -= $carry5 << 25; /** @var int $carry7 */ $carry7 = ($h[7] + (1 << 24)) >> 25; $h[8] += $carry7; $h[7] -= $carry7 << 25; /** @var int $carry0 */ $carry0 = ($h[0] + (1 << 25)) >> 26; $h[1] += $carry0; $h[0] -= $carry0 << 26; /** @var int $carry2 */ $carry2 = ($h[2] + (1 << 25)) >> 26; $h[3] += $carry2; $h[2] -= $carry2 << 26; /** @var int $carry4 */ $carry4 = ($h[4] + (1 << 25)) >> 26; $h[5] += $carry4; $h[4] -= $carry4 << 26; /** @var int $carry6 */ $carry6 = ($h[6] + (1 << 25)) >> 26; $h[7] += $carry6; $h[6] -= $carry6 << 26; /** @var int $carry8 */ $carry8 = ($h[8] + (1 << 25)) >> 26; $h[9] += $carry8; $h[8] -= $carry8 << 26; foreach ($h as $i => $value) { $h[$i] = (int) $value; } return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); } /** * @internal You should not use this directly from another application * * Inline comments preceded by # are from libsodium's ref10 code. * * @param string $n * @param string $p * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_scalarmult_curve25519_ref10($n, $p) { # for (i = 0;i < 32;++i) e[i] = n[i]; $e = '' . $n; # e[0] &= 248; $e[0] = self::intToChr( self::chrToInt($e[0]) & 248 ); # e[31] &= 127; # e[31] |= 64; $e[31] = self::intToChr( (self::chrToInt($e[31]) & 127) | 64 ); # fe_frombytes(x1,p); $x1 = self::fe_frombytes($p); # fe_1(x2); $x2 = self::fe_1(); # fe_0(z2); $z2 = self::fe_0(); # fe_copy(x3,x1); $x3 = self::fe_copy($x1); # fe_1(z3); $z3 = self::fe_1(); # swap = 0; /** @var int $swap */ $swap = 0; # for (pos = 254;pos >= 0;--pos) { for ($pos = 254; $pos >= 0; --$pos) { # b = e[pos / 8] >> (pos & 7); /** @var int $b */ $b = self::chrToInt( $e[(int) floor($pos / 8)] ) >> ($pos & 7); # b &= 1; $b &= 1; # swap ^= b; $swap ^= $b; # fe_cswap(x2,x3,swap); self::fe_cswap($x2, $x3, $swap); # fe_cswap(z2,z3,swap); self::fe_cswap($z2, $z3, $swap); # swap = b; $swap = $b; # fe_sub(tmp0,x3,z3); $tmp0 = self::fe_sub($x3, $z3); # fe_sub(tmp1,x2,z2); $tmp1 = self::fe_sub($x2, $z2); # fe_add(x2,x2,z2); $x2 = self::fe_add($x2, $z2); # fe_add(z2,x3,z3); $z2 = self::fe_add($x3, $z3); # fe_mul(z3,tmp0,x2); $z3 = self::fe_mul($tmp0, $x2); # fe_mul(z2,z2,tmp1); $z2 = self::fe_mul($z2, $tmp1); # fe_sq(tmp0,tmp1); $tmp0 = self::fe_sq($tmp1); # fe_sq(tmp1,x2); $tmp1 = self::fe_sq($x2); # fe_add(x3,z3,z2); $x3 = self::fe_add($z3, $z2); # fe_sub(z2,z3,z2); $z2 = self::fe_sub($z3, $z2); # fe_mul(x2,tmp1,tmp0); $x2 = self::fe_mul($tmp1, $tmp0); # fe_sub(tmp1,tmp1,tmp0); $tmp1 = self::fe_sub($tmp1, $tmp0); # fe_sq(z2,z2); $z2 = self::fe_sq($z2); # fe_mul121666(z3,tmp1); $z3 = self::fe_mul121666($tmp1); # fe_sq(x3,x3); $x3 = self::fe_sq($x3); # fe_add(tmp0,tmp0,z3); $tmp0 = self::fe_add($tmp0, $z3); # fe_mul(z3,x1,z2); $z3 = self::fe_mul($x1, $z2); # fe_mul(z2,tmp1,tmp0); $z2 = self::fe_mul($tmp1, $tmp0); } # fe_cswap(x2,x3,swap); self::fe_cswap($x2, $x3, $swap); # fe_cswap(z2,z3,swap); self::fe_cswap($z2, $z3, $swap); # fe_invert(z2,z2); $z2 = self::fe_invert($z2); # fe_mul(x2,x2,z2); $x2 = self::fe_mul($x2, $z2); # fe_tobytes(q,x2); return self::fe_tobytes($x2); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ * @return ParagonIE_Sodium_Core_Curve25519_Fe */ public static function edwards_to_montgomery( ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY, ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ ) { $tempX = self::fe_add($edwardsZ, $edwardsY); $tempZ = self::fe_sub($edwardsZ, $edwardsY); $tempZ = self::fe_invert($tempZ); return self::fe_mul($tempX, $tempZ); } /** * @internal You should not use this directly from another application * * @param string $n * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_scalarmult_curve25519_ref10_base($n) { # for (i = 0;i < 32;++i) e[i] = n[i]; $e = '' . $n; # e[0] &= 248; $e[0] = self::intToChr( self::chrToInt($e[0]) & 248 ); # e[31] &= 127; # e[31] |= 64; $e[31] = self::intToChr( (self::chrToInt($e[31]) & 127) | 64 ); $A = self::ge_scalarmult_base($e); if ( !($A->Y instanceof ParagonIE_Sodium_Core_Curve25519_Fe) || !($A->Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe) ) { throw new TypeError('Null points encountered'); } $pk = self::edwards_to_montgomery($A->Y, $A->Z); return self::fe_tobytes($pk); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/Util.php���������������������������������������������������������������������������������������0000644�����������������00000070373�15021200076�0007065 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_Util', false)) { return; } /** * Class ParagonIE_Sodium_Core_Util */ abstract class ParagonIE_Sodium_Core_Util { const U32_MAX = 0xFFFFFFFF; /** * @param int $integer * @param int $size (16, 32, 64) * @return int */ public static function abs($integer, $size = 0) { /** @var int $realSize */ $realSize = (PHP_INT_SIZE << 3) - 1; if ($size) { --$size; } else { /** @var int $size */ $size = $realSize; } $negative = -(($integer >> $size) & 1); return (int) ( ($integer ^ $negative) + (($negative >> $realSize) & 1) ); } /** * @param string $a * @param string $b * @return string * @throws SodiumException */ public static function andStrings($a, $b) { /* Type checks: */ if (!is_string($a)) { throw new TypeError('Argument 1 must be a string'); } if (!is_string($b)) { throw new TypeError('Argument 2 must be a string'); } $len = self::strlen($a); if (self::strlen($b) !== $len) { throw new SodiumException('Both strings must be of equal length to combine with bitwise AND'); } return $a & $b; } /** * Convert a binary string into a hexadecimal string without cache-timing * leaks * * @internal You should not use this directly from another application * * @param string $binaryString (raw binary) * @return string * @throws TypeError */ public static function bin2hex($binaryString) { /* Type checks: */ if (!is_string($binaryString)) { throw new TypeError('Argument 1 must be a string, ' . gettype($binaryString) . ' given.'); } $hex = ''; $len = self::strlen($binaryString); for ($i = 0; $i < $len; ++$i) { /** @var array<int, int> $chunk */ $chunk = unpack('C', $binaryString[$i]); /** @var int $c */ $c = $chunk[1] & 0xf; /** @var int $b */ $b = $chunk[1] >> 4; $hex .= pack( 'CC', (87 + $b + ((($b - 10) >> 8) & ~38)), (87 + $c + ((($c - 10) >> 8) & ~38)) ); } return $hex; } /** * Convert a binary string into a hexadecimal string without cache-timing * leaks, returning uppercase letters (as per RFC 4648) * * @internal You should not use this directly from another application * * @param string $bin_string (raw binary) * @return string * @throws TypeError */ public static function bin2hexUpper($bin_string) { $hex = ''; $len = self::strlen($bin_string); for ($i = 0; $i < $len; ++$i) { /** @var array<int, int> $chunk */ $chunk = unpack('C', $bin_string[$i]); /** * Lower 16 bits * * @var int $c */ $c = $chunk[1] & 0xf; /** * Upper 16 bits * @var int $b */ $b = $chunk[1] >> 4; /** * Use pack() and binary operators to turn the two integers * into hexadecimal characters. We don't use chr() here, because * it uses a lookup table internally and we want to avoid * cache-timing side-channels. */ $hex .= pack( 'CC', (55 + $b + ((($b - 10) >> 8) & ~6)), (55 + $c + ((($c - 10) >> 8) & ~6)) ); } return $hex; } /** * Cache-timing-safe variant of ord() * * @internal You should not use this directly from another application * * @param string $chr * @return int * @throws SodiumException * @throws TypeError */ public static function chrToInt($chr) { /* Type checks: */ if (!is_string($chr)) { throw new TypeError('Argument 1 must be a string, ' . gettype($chr) . ' given.'); } if (self::strlen($chr) !== 1) { throw new SodiumException('chrToInt() expects a string that is exactly 1 character long'); } /** @var array<int, int> $chunk */ $chunk = unpack('C', $chr); return (int) ($chunk[1]); } /** * Compares two strings. * * @internal You should not use this directly from another application * * @param string $left * @param string $right * @param int $len * @return int * @throws SodiumException * @throws TypeError */ public static function compare($left, $right, $len = null) { $leftLen = self::strlen($left); $rightLen = self::strlen($right); if ($len === null) { $len = max($leftLen, $rightLen); $left = str_pad($left, $len, "\x00", STR_PAD_RIGHT); $right = str_pad($right, $len, "\x00", STR_PAD_RIGHT); } $gt = 0; $eq = 1; $i = $len; while ($i !== 0) { --$i; $gt |= ((self::chrToInt($right[$i]) - self::chrToInt($left[$i])) >> 8) & $eq; $eq &= ((self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1) >> 8; } return ($gt + $gt + $eq) - 1; } /** * If a variable does not match a given type, throw a TypeError. * * @param mixed $mixedVar * @param string $type * @param int $argumentIndex * @throws TypeError * @throws SodiumException * @return void */ public static function declareScalarType(&$mixedVar = null, $type = 'void', $argumentIndex = 0) { if (func_num_args() === 0) { /* Tautology, by default */ return; } if (func_num_args() === 1) { throw new TypeError('Declared void, but passed a variable'); } $realType = strtolower(gettype($mixedVar)); $type = strtolower($type); switch ($type) { case 'null': if ($mixedVar !== null) { throw new TypeError('Argument ' . $argumentIndex . ' must be null, ' . $realType . ' given.'); } break; case 'integer': case 'int': $allow = array('int', 'integer'); if (!in_array($type, $allow)) { throw new TypeError('Argument ' . $argumentIndex . ' must be an integer, ' . $realType . ' given.'); } $mixedVar = (int) $mixedVar; break; case 'boolean': case 'bool': $allow = array('bool', 'boolean'); if (!in_array($type, $allow)) { throw new TypeError('Argument ' . $argumentIndex . ' must be a boolean, ' . $realType . ' given.'); } $mixedVar = (bool) $mixedVar; break; case 'string': if (!is_string($mixedVar)) { throw new TypeError('Argument ' . $argumentIndex . ' must be a string, ' . $realType . ' given.'); } $mixedVar = (string) $mixedVar; break; case 'decimal': case 'double': case 'float': $allow = array('decimal', 'double', 'float'); if (!in_array($type, $allow)) { throw new TypeError('Argument ' . $argumentIndex . ' must be a float, ' . $realType . ' given.'); } $mixedVar = (float) $mixedVar; break; case 'object': if (!is_object($mixedVar)) { throw new TypeError('Argument ' . $argumentIndex . ' must be an object, ' . $realType . ' given.'); } break; case 'array': if (!is_array($mixedVar)) { if (is_object($mixedVar)) { if ($mixedVar instanceof ArrayAccess) { return; } } throw new TypeError('Argument ' . $argumentIndex . ' must be an array, ' . $realType . ' given.'); } break; default: throw new SodiumException('Unknown type (' . $realType .') does not match expect type (' . $type . ')'); } } /** * Evaluate whether or not two strings are equal (in constant-time) * * @param string $left * @param string $right * @return bool * @throws SodiumException * @throws TypeError */ public static function hashEquals($left, $right) { /* Type checks: */ if (!is_string($left)) { throw new TypeError('Argument 1 must be a string, ' . gettype($left) . ' given.'); } if (!is_string($right)) { throw new TypeError('Argument 2 must be a string, ' . gettype($right) . ' given.'); } if (is_callable('hash_equals')) { return hash_equals($left, $right); } $d = 0; /** @var int $len */ $len = self::strlen($left); if ($len !== self::strlen($right)) { return false; } for ($i = 0; $i < $len; ++$i) { $d |= self::chrToInt($left[$i]) ^ self::chrToInt($right[$i]); } if ($d !== 0) { return false; } return $left === $right; } /** * Catch hash_update() failures and throw instead of silently proceeding * * @param HashContext|resource &$hs * @param string $data * @return void * @throws SodiumException * @psalm-suppress PossiblyInvalidArgument */ protected static function hash_update(&$hs, $data) { if (!hash_update($hs, $data)) { throw new SodiumException('hash_update() failed'); } } /** * Convert a hexadecimal string into a binary string without cache-timing * leaks * * @internal You should not use this directly from another application * * @param string $hexString * @param string $ignore * @param bool $strictPadding * @return string (raw binary) * @throws RangeException * @throws TypeError */ public static function hex2bin($hexString, $ignore = '', $strictPadding = false) { /* Type checks: */ if (!is_string($hexString)) { throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.'); } if (!is_string($ignore)) { throw new TypeError('Argument 2 must be a string, ' . gettype($hexString) . ' given.'); } $hex_pos = 0; $bin = ''; $c_acc = 0; $hex_len = self::strlen($hexString); $state = 0; if (($hex_len & 1) !== 0) { if ($strictPadding) { throw new RangeException( 'Expected an even number of hexadecimal characters' ); } else { $hexString = '0' . $hexString; ++$hex_len; } } $chunk = unpack('C*', $hexString); while ($hex_pos < $hex_len) { ++$hex_pos; /** @var int $c */ $c = $chunk[$hex_pos]; $c_num = $c ^ 48; $c_num0 = ($c_num - 10) >> 8; $c_alpha = ($c & ~32) - 55; $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; if (($c_num0 | $c_alpha0) === 0) { if ($ignore && $state === 0 && strpos($ignore, self::intToChr($c)) !== false) { continue; } throw new RangeException( 'hex2bin() only expects hexadecimal characters' ); } $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); if ($state === 0) { $c_acc = $c_val * 16; } else { $bin .= pack('C', $c_acc | $c_val); } $state ^= 1; } return $bin; } /** * Turn an array of integers into a string * * @internal You should not use this directly from another application * * @param array<int, int> $ints * @return string */ public static function intArrayToString(array $ints) { $args = $ints; foreach ($args as $i => $v) { $args[$i] = (int) ($v & 0xff); } array_unshift($args, str_repeat('C', count($ints))); return (string) (call_user_func_array('pack', $args)); } /** * Cache-timing-safe variant of ord() * * @internal You should not use this directly from another application * * @param int $int * @return string * @throws TypeError */ public static function intToChr($int) { return pack('C', $int); } /** * Load a 3 character substring into an integer * * @internal You should not use this directly from another application * * @param string $string * @return int * @throws RangeException * @throws TypeError */ public static function load_3($string) { /* Type checks: */ if (!is_string($string)) { throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); } /* Input validation: */ if (self::strlen($string) < 3) { throw new RangeException( 'String must be 3 bytes or more; ' . self::strlen($string) . ' given.' ); } /** @var array<int, int> $unpacked */ $unpacked = unpack('V', $string . "\0"); return (int) ($unpacked[1] & 0xffffff); } /** * Load a 4 character substring into an integer * * @internal You should not use this directly from another application * * @param string $string * @return int * @throws RangeException * @throws TypeError */ public static function load_4($string) { /* Type checks: */ if (!is_string($string)) { throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); } /* Input validation: */ if (self::strlen($string) < 4) { throw new RangeException( 'String must be 4 bytes or more; ' . self::strlen($string) . ' given.' ); } /** @var array<int, int> $unpacked */ $unpacked = unpack('V', $string); return (int) $unpacked[1]; } /** * Load a 8 character substring into an integer * * @internal You should not use this directly from another application * * @param string $string * @return int * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function load64_le($string) { /* Type checks: */ if (!is_string($string)) { throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); } /* Input validation: */ if (self::strlen($string) < 4) { throw new RangeException( 'String must be 4 bytes or more; ' . self::strlen($string) . ' given.' ); } if (PHP_VERSION_ID >= 50603 && PHP_INT_SIZE === 8) { /** @var array<int, int> $unpacked */ $unpacked = unpack('P', $string); return (int) $unpacked[1]; } /** @var int $result */ $result = (self::chrToInt($string[0]) & 0xff); $result |= (self::chrToInt($string[1]) & 0xff) << 8; $result |= (self::chrToInt($string[2]) & 0xff) << 16; $result |= (self::chrToInt($string[3]) & 0xff) << 24; $result |= (self::chrToInt($string[4]) & 0xff) << 32; $result |= (self::chrToInt($string[5]) & 0xff) << 40; $result |= (self::chrToInt($string[6]) & 0xff) << 48; $result |= (self::chrToInt($string[7]) & 0xff) << 56; return (int) $result; } /** * @internal You should not use this directly from another application * * @param string $left * @param string $right * @return int * @throws SodiumException * @throws TypeError */ public static function memcmp($left, $right) { if (self::hashEquals($left, $right)) { return 0; } return -1; } /** * Multiply two integers in constant-time * * Micro-architecture timing side-channels caused by how your CPU * implements multiplication are best prevented by never using the * multiplication operators and ensuring that our code always takes * the same number of operations to complete, regardless of the values * of $a and $b. * * @internal You should not use this directly from another application * * @param int $a * @param int $b * @param int $size Limits the number of operations (useful for small, * constant operands) * @return int */ public static function mul($a, $b, $size = 0) { if (ParagonIE_Sodium_Compat::$fastMult) { return (int) ($a * $b); } static $defaultSize = null; /** @var int $defaultSize */ if (!$defaultSize) { /** @var int $defaultSize */ $defaultSize = (PHP_INT_SIZE << 3) - 1; } if ($size < 1) { /** @var int $size */ $size = $defaultSize; } /** @var int $size */ $c = 0; /** * Mask is either -1 or 0. * * -1 in binary looks like 0x1111 ... 1111 * 0 in binary looks like 0x0000 ... 0000 * * @var int */ $mask = -(($b >> ((int) $defaultSize)) & 1); /** * Ensure $b is a positive integer, without creating * a branching side-channel * * @var int $b */ $b = ($b & ~$mask) | ($mask & -$b); /** * Unless $size is provided: * * This loop always runs 32 times when PHP_INT_SIZE is 4. * This loop always runs 64 times when PHP_INT_SIZE is 8. */ for ($i = $size; $i >= 0; --$i) { $c += (int) ($a & -($b & 1)); $a <<= 1; $b >>= 1; } $c = (int) @($c & -1); /** * If $b was negative, we then apply the same value to $c here. * It doesn't matter much if $a was negative; the $c += above would * have produced a negative integer to begin with. But a negative $b * makes $b >>= 1 never return 0, so we would end up with incorrect * results. * * The end result is what we'd expect from integer multiplication. */ return (int) (($c & ~$mask) | ($mask & -$c)); } /** * Convert any arbitrary numbers into two 32-bit integers that represent * a 64-bit integer. * * @internal You should not use this directly from another application * * @param int|float $num * @return array<int, int> */ public static function numericTo64BitInteger($num) { $high = 0; /** @var int $low */ if (PHP_INT_SIZE === 4) { $low = (int) $num; } else { $low = $num & 0xffffffff; } if ((+(abs($num))) >= 1) { if ($num > 0) { /** @var int $high */ $high = min((+(floor($num/4294967296))), 4294967295); } else { /** @var int $high */ $high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296)))); } } return array((int) $high, (int) $low); } /** * Store a 24-bit integer into a string, treating it as big-endian. * * @internal You should not use this directly from another application * * @param int $int * @return string * @throws TypeError */ public static function store_3($int) { /* Type checks: */ if (!is_int($int)) { if (is_numeric($int)) { $int = (int) $int; } else { throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); } } /** @var string $packed */ $packed = pack('N', $int); return self::substr($packed, 1, 3); } /** * Store a 32-bit integer into a string, treating it as little-endian. * * @internal You should not use this directly from another application * * @param int $int * @return string * @throws TypeError */ public static function store32_le($int) { /* Type checks: */ if (!is_int($int)) { if (is_numeric($int)) { $int = (int) $int; } else { throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); } } /** @var string $packed */ $packed = pack('V', $int); return $packed; } /** * Store a 32-bit integer into a string, treating it as big-endian. * * @internal You should not use this directly from another application * * @param int $int * @return string * @throws TypeError */ public static function store_4($int) { /* Type checks: */ if (!is_int($int)) { if (is_numeric($int)) { $int = (int) $int; } else { throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); } } /** @var string $packed */ $packed = pack('N', $int); return $packed; } /** * Stores a 64-bit integer as an string, treating it as little-endian. * * @internal You should not use this directly from another application * * @param int $int * @return string * @throws TypeError */ public static function store64_le($int) { /* Type checks: */ if (!is_int($int)) { if (is_numeric($int)) { $int = (int) $int; } else { throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); } } if (PHP_INT_SIZE === 8) { if (PHP_VERSION_ID >= 50603) { /** @var string $packed */ $packed = pack('P', $int); return $packed; } return self::intToChr($int & 0xff) . self::intToChr(($int >> 8) & 0xff) . self::intToChr(($int >> 16) & 0xff) . self::intToChr(($int >> 24) & 0xff) . self::intToChr(($int >> 32) & 0xff) . self::intToChr(($int >> 40) & 0xff) . self::intToChr(($int >> 48) & 0xff) . self::intToChr(($int >> 56) & 0xff); } if ($int > PHP_INT_MAX) { list($hiB, $int) = self::numericTo64BitInteger($int); } else { $hiB = 0; } return self::intToChr(($int ) & 0xff) . self::intToChr(($int >> 8) & 0xff) . self::intToChr(($int >> 16) & 0xff) . self::intToChr(($int >> 24) & 0xff) . self::intToChr($hiB & 0xff) . self::intToChr(($hiB >> 8) & 0xff) . self::intToChr(($hiB >> 16) & 0xff) . self::intToChr(($hiB >> 24) & 0xff); } /** * Safe string length * * @internal You should not use this directly from another application * * @ref mbstring.func_overload * * @param string $str * @return int * @throws TypeError */ public static function strlen($str) { /* Type checks: */ if (!is_string($str)) { throw new TypeError('String expected'); } return (int) ( self::isMbStringOverride() ? mb_strlen($str, '8bit') : strlen($str) ); } /** * Turn a string into an array of integers * * @internal You should not use this directly from another application * * @param string $string * @return array<int, int> * @throws TypeError */ public static function stringToIntArray($string) { if (!is_string($string)) { throw new TypeError('String expected'); } /** * @var array<int, int> */ $values = array_values( unpack('C*', $string) ); return $values; } /** * Safe substring * * @internal You should not use this directly from another application * * @ref mbstring.func_overload * * @param string $str * @param int $start * @param int $length * @return string * @throws TypeError */ public static function substr($str, $start = 0, $length = null) { /* Type checks: */ if (!is_string($str)) { throw new TypeError('String expected'); } if ($length === 0) { return ''; } if (self::isMbStringOverride()) { if (PHP_VERSION_ID < 50400 && $length === null) { $length = self::strlen($str); } $sub = (string) mb_substr($str, $start, $length, '8bit'); } elseif ($length === null) { $sub = (string) substr($str, $start); } else { $sub = (string) substr($str, $start, $length); } if ($sub !== '') { return $sub; } return ''; } /** * Compare a 16-character byte string in constant time. * * @internal You should not use this directly from another application * * @param string $a * @param string $b * @return bool * @throws SodiumException * @throws TypeError */ public static function verify_16($a, $b) { /* Type checks: */ if (!is_string($a)) { throw new TypeError('String expected'); } if (!is_string($b)) { throw new TypeError('String expected'); } return self::hashEquals( self::substr($a, 0, 16), self::substr($b, 0, 16) ); } /** * Compare a 32-character byte string in constant time. * * @internal You should not use this directly from another application * * @param string $a * @param string $b * @return bool * @throws SodiumException * @throws TypeError */ public static function verify_32($a, $b) { /* Type checks: */ if (!is_string($a)) { throw new TypeError('String expected'); } if (!is_string($b)) { throw new TypeError('String expected'); } return self::hashEquals( self::substr($a, 0, 32), self::substr($b, 0, 32) ); } /** * Calculate $a ^ $b for two strings. * * @internal You should not use this directly from another application * * @param string $a * @param string $b * @return string * @throws TypeError */ public static function xorStrings($a, $b) { /* Type checks: */ if (!is_string($a)) { throw new TypeError('Argument 1 must be a string'); } if (!is_string($b)) { throw new TypeError('Argument 2 must be a string'); } return (string) ($a ^ $b); } /** * Returns whether or not mbstring.func_overload is in effect. * * @internal You should not use this directly from another application * * Note: MB_OVERLOAD_STRING === 2, but we don't reference the constant * (for nuisance-free PHP 8 support) * * @return bool */ protected static function isMbStringOverride() { static $mbstring = null; if ($mbstring === null) { if (!defined('MB_OVERLOAD_STRING')) { $mbstring = false; return $mbstring; } $mbstring = extension_loaded('mbstring') && defined('MB_OVERLOAD_STRING') && ((int) (ini_get('mbstring.func_overload')) & 2); // MB_OVERLOAD_STRING === 2 } /** @var bool $mbstring */ return $mbstring; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/AEGIS128L.php����������������������������������������������������������������������������������0000644�����������������00000007124�15021200076�0007341 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (!defined('SODIUM_COMPAT_AEGIS_C0')) { define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62"); } if (!defined('SODIUM_COMPAT_AEGIS_C1')) { define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd"); } class ParagonIE_Sodium_Core_AEGIS128L extends ParagonIE_Sodium_Core_AES { /** * @param string $ct * @param string $tag * @param string $ad * @param string $key * @param string $nonce * @return string * @throws SodiumException */ public static function decrypt($ct, $tag, $ad, $key, $nonce) { $state = self::init($key, $nonce); $ad_blocks = (self::strlen($ad) + 31) >> 5; for ($i = 0; $i < $ad_blocks; ++$i) { $ai = self::substr($ad, $i << 5, 32); if (self::strlen($ai) < 32) { $ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT); } $state->absorb($ai); } $msg = ''; $cn = self::strlen($ct) & 31; $ct_blocks = self::strlen($ct) >> 5; for ($i = 0; $i < $ct_blocks; ++$i) { $msg .= $state->dec(self::substr($ct, $i << 5, 32)); } if ($cn) { $start = $ct_blocks << 5; $msg .= $state->decPartial(self::substr($ct, $start, $cn)); } $expected_tag = $state->finalize( self::strlen($ad) << 3, self::strlen($msg) << 3 ); if (!self::hashEquals($expected_tag, $tag)) { try { // The RFC says to erase msg, so we shall try: ParagonIE_Sodium_Compat::memzero($msg); } catch (SodiumException $ex) { // Do nothing if we cannot memzero } throw new SodiumException('verification failed'); } return $msg; } /** * @param string $msg * @param string $ad * @param string $key * @param string $nonce * @return array * * @throws SodiumException */ public static function encrypt($msg, $ad, $key, $nonce) { $state = self::init($key, $nonce); // ad_blocks = Split(ZeroPad(ad, 256), 256) // for ai in ad_blocks: // Absorb(ai) $ad_len = self::strlen($ad); $msg_len = self::strlen($msg); $ad_blocks = ($ad_len + 31) >> 5; for ($i = 0; $i < $ad_blocks; ++$i) { $ai = self::substr($ad, $i << 5, 32); if (self::strlen($ai) < 32) { $ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT); } $state->absorb($ai); } // msg_blocks = Split(ZeroPad(msg, 256), 256) // for xi in msg_blocks: // ct = ct || Enc(xi) $ct = ''; $msg_blocks = ($msg_len + 31) >> 5; for ($i = 0; $i < $msg_blocks; ++$i) { $xi = self::substr($msg, $i << 5, 32); if (self::strlen($xi) < 32) { $xi = str_pad($xi, 32, "\0", STR_PAD_RIGHT); } $ct .= $state->enc($xi); } // tag = Finalize(|ad|, |msg|) // ct = Truncate(ct, |msg|) $tag = $state->finalize( $ad_len << 3, $msg_len << 3 ); // return ct and tag return array( self::substr($ct, 0, $msg_len), $tag ); } /** * @param string $key * @param string $nonce * @return ParagonIE_Sodium_Core_AEGIS_State128L */ public static function init($key, $nonce) { return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core/ChaCha20.php�����������������������������������������������������������������������������������0000644�����������������00000031206�15021200076�0007411 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core_ChaCha20 */ class ParagonIE_Sodium_Core_ChaCha20 extends ParagonIE_Sodium_Core_Util { /** * Bitwise left rotation * * @internal You should not use this directly from another application * * @param int $v * @param int $n * @return int */ public static function rotate($v, $n) { $v &= 0xffffffff; $n &= 31; return (int) ( 0xffffffff & ( ($v << $n) | ($v >> (32 - $n)) ) ); } /** * The ChaCha20 quarter round function. Works on four 32-bit integers. * * @internal You should not use this directly from another application * * @param int $a * @param int $b * @param int $c * @param int $d * @return array<int, int> */ protected static function quarterRound($a, $b, $c, $d) { # a = PLUS(a,b); d = ROTATE(XOR(d,a),16); /** @var int $a */ $a = ($a + $b) & 0xffffffff; $d = self::rotate($d ^ $a, 16); # c = PLUS(c,d); b = ROTATE(XOR(b,c),12); /** @var int $c */ $c = ($c + $d) & 0xffffffff; $b = self::rotate($b ^ $c, 12); # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); /** @var int $a */ $a = ($a + $b) & 0xffffffff; $d = self::rotate($d ^ $a, 8); # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); /** @var int $c */ $c = ($c + $d) & 0xffffffff; $b = self::rotate($b ^ $c, 7); return array((int) $a, (int) $b, (int) $c, (int) $d); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx * @param string $message * * @return string * @throws TypeError * @throws SodiumException */ public static function encryptBytes( ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx, $message = '' ) { $bytes = self::strlen($message); /* j0 = ctx->input[0]; j1 = ctx->input[1]; j2 = ctx->input[2]; j3 = ctx->input[3]; j4 = ctx->input[4]; j5 = ctx->input[5]; j6 = ctx->input[6]; j7 = ctx->input[7]; j8 = ctx->input[8]; j9 = ctx->input[9]; j10 = ctx->input[10]; j11 = ctx->input[11]; j12 = ctx->input[12]; j13 = ctx->input[13]; j14 = ctx->input[14]; j15 = ctx->input[15]; */ $j0 = (int) $ctx[0]; $j1 = (int) $ctx[1]; $j2 = (int) $ctx[2]; $j3 = (int) $ctx[3]; $j4 = (int) $ctx[4]; $j5 = (int) $ctx[5]; $j6 = (int) $ctx[6]; $j7 = (int) $ctx[7]; $j8 = (int) $ctx[8]; $j9 = (int) $ctx[9]; $j10 = (int) $ctx[10]; $j11 = (int) $ctx[11]; $j12 = (int) $ctx[12]; $j13 = (int) $ctx[13]; $j14 = (int) $ctx[14]; $j15 = (int) $ctx[15]; $c = ''; for (;;) { if ($bytes < 64) { $message .= str_repeat("\x00", 64 - $bytes); } $x0 = (int) $j0; $x1 = (int) $j1; $x2 = (int) $j2; $x3 = (int) $j3; $x4 = (int) $j4; $x5 = (int) $j5; $x6 = (int) $j6; $x7 = (int) $j7; $x8 = (int) $j8; $x9 = (int) $j9; $x10 = (int) $j10; $x11 = (int) $j11; $x12 = (int) $j12; $x13 = (int) $j13; $x14 = (int) $j14; $x15 = (int) $j15; # for (i = 20; i > 0; i -= 2) { for ($i = 20; $i > 0; $i -= 2) { # QUARTERROUND( x0, x4, x8, x12) list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12); # QUARTERROUND( x1, x5, x9, x13) list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13); # QUARTERROUND( x2, x6, x10, x14) list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14); # QUARTERROUND( x3, x7, x11, x15) list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15); # QUARTERROUND( x0, x5, x10, x15) list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15); # QUARTERROUND( x1, x6, x11, x12) list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12); # QUARTERROUND( x2, x7, x8, x13) list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13); # QUARTERROUND( x3, x4, x9, x14) list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14); } /* x0 = PLUS(x0, j0); x1 = PLUS(x1, j1); x2 = PLUS(x2, j2); x3 = PLUS(x3, j3); x4 = PLUS(x4, j4); x5 = PLUS(x5, j5); x6 = PLUS(x6, j6); x7 = PLUS(x7, j7); x8 = PLUS(x8, j8); x9 = PLUS(x9, j9); x10 = PLUS(x10, j10); x11 = PLUS(x11, j11); x12 = PLUS(x12, j12); x13 = PLUS(x13, j13); x14 = PLUS(x14, j14); x15 = PLUS(x15, j15); */ /** @var int $x0 */ $x0 = ($x0 & 0xffffffff) + $j0; /** @var int $x1 */ $x1 = ($x1 & 0xffffffff) + $j1; /** @var int $x2 */ $x2 = ($x2 & 0xffffffff) + $j2; /** @var int $x3 */ $x3 = ($x3 & 0xffffffff) + $j3; /** @var int $x4 */ $x4 = ($x4 & 0xffffffff) + $j4; /** @var int $x5 */ $x5 = ($x5 & 0xffffffff) + $j5; /** @var int $x6 */ $x6 = ($x6 & 0xffffffff) + $j6; /** @var int $x7 */ $x7 = ($x7 & 0xffffffff) + $j7; /** @var int $x8 */ $x8 = ($x8 & 0xffffffff) + $j8; /** @var int $x9 */ $x9 = ($x9 & 0xffffffff) + $j9; /** @var int $x10 */ $x10 = ($x10 & 0xffffffff) + $j10; /** @var int $x11 */ $x11 = ($x11 & 0xffffffff) + $j11; /** @var int $x12 */ $x12 = ($x12 & 0xffffffff) + $j12; /** @var int $x13 */ $x13 = ($x13 & 0xffffffff) + $j13; /** @var int $x14 */ $x14 = ($x14 & 0xffffffff) + $j14; /** @var int $x15 */ $x15 = ($x15 & 0xffffffff) + $j15; /* x0 = XOR(x0, LOAD32_LE(m + 0)); x1 = XOR(x1, LOAD32_LE(m + 4)); x2 = XOR(x2, LOAD32_LE(m + 8)); x3 = XOR(x3, LOAD32_LE(m + 12)); x4 = XOR(x4, LOAD32_LE(m + 16)); x5 = XOR(x5, LOAD32_LE(m + 20)); x6 = XOR(x6, LOAD32_LE(m + 24)); x7 = XOR(x7, LOAD32_LE(m + 28)); x8 = XOR(x8, LOAD32_LE(m + 32)); x9 = XOR(x9, LOAD32_LE(m + 36)); x10 = XOR(x10, LOAD32_LE(m + 40)); x11 = XOR(x11, LOAD32_LE(m + 44)); x12 = XOR(x12, LOAD32_LE(m + 48)); x13 = XOR(x13, LOAD32_LE(m + 52)); x14 = XOR(x14, LOAD32_LE(m + 56)); x15 = XOR(x15, LOAD32_LE(m + 60)); */ $x0 ^= self::load_4(self::substr($message, 0, 4)); $x1 ^= self::load_4(self::substr($message, 4, 4)); $x2 ^= self::load_4(self::substr($message, 8, 4)); $x3 ^= self::load_4(self::substr($message, 12, 4)); $x4 ^= self::load_4(self::substr($message, 16, 4)); $x5 ^= self::load_4(self::substr($message, 20, 4)); $x6 ^= self::load_4(self::substr($message, 24, 4)); $x7 ^= self::load_4(self::substr($message, 28, 4)); $x8 ^= self::load_4(self::substr($message, 32, 4)); $x9 ^= self::load_4(self::substr($message, 36, 4)); $x10 ^= self::load_4(self::substr($message, 40, 4)); $x11 ^= self::load_4(self::substr($message, 44, 4)); $x12 ^= self::load_4(self::substr($message, 48, 4)); $x13 ^= self::load_4(self::substr($message, 52, 4)); $x14 ^= self::load_4(self::substr($message, 56, 4)); $x15 ^= self::load_4(self::substr($message, 60, 4)); /* j12 = PLUSONE(j12); if (!j12) { j13 = PLUSONE(j13); } */ ++$j12; if ($j12 & 0xf0000000) { throw new SodiumException('Overflow'); } /* STORE32_LE(c + 0, x0); STORE32_LE(c + 4, x1); STORE32_LE(c + 8, x2); STORE32_LE(c + 12, x3); STORE32_LE(c + 16, x4); STORE32_LE(c + 20, x5); STORE32_LE(c + 24, x6); STORE32_LE(c + 28, x7); STORE32_LE(c + 32, x8); STORE32_LE(c + 36, x9); STORE32_LE(c + 40, x10); STORE32_LE(c + 44, x11); STORE32_LE(c + 48, x12); STORE32_LE(c + 52, x13); STORE32_LE(c + 56, x14); STORE32_LE(c + 60, x15); */ $block = self::store32_le((int) ($x0 & 0xffffffff)) . self::store32_le((int) ($x1 & 0xffffffff)) . self::store32_le((int) ($x2 & 0xffffffff)) . self::store32_le((int) ($x3 & 0xffffffff)) . self::store32_le((int) ($x4 & 0xffffffff)) . self::store32_le((int) ($x5 & 0xffffffff)) . self::store32_le((int) ($x6 & 0xffffffff)) . self::store32_le((int) ($x7 & 0xffffffff)) . self::store32_le((int) ($x8 & 0xffffffff)) . self::store32_le((int) ($x9 & 0xffffffff)) . self::store32_le((int) ($x10 & 0xffffffff)) . self::store32_le((int) ($x11 & 0xffffffff)) . self::store32_le((int) ($x12 & 0xffffffff)) . self::store32_le((int) ($x13 & 0xffffffff)) . self::store32_le((int) ($x14 & 0xffffffff)) . self::store32_le((int) ($x15 & 0xffffffff)); /* Partial block */ if ($bytes < 64) { $c .= self::substr($block, 0, $bytes); break; } /* Full block */ $c .= $block; $bytes -= 64; if ($bytes <= 0) { break; } $message = self::substr($message, 64); } /* end for(;;) loop */ $ctx[12] = $j12; $ctx[13] = $j13; return $c; } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function stream($len = 64, $nonce = '', $key = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStream($len, $nonce = '', $key = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic), $message ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function streamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic), $message ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Crypto.php������������������������������������������������������������������������������������������0000644�����������������00000153032�15021200076�0006532 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Crypto', false)) { return; } /** * Class ParagonIE_Sodium_Crypto * * ATTENTION! * * If you are using this library, you should be using * ParagonIE_Sodium_Compat in your code, not this class. */ abstract class ParagonIE_Sodium_Crypto { const aead_chacha20poly1305_KEYBYTES = 32; const aead_chacha20poly1305_NSECBYTES = 0; const aead_chacha20poly1305_NPUBBYTES = 8; const aead_chacha20poly1305_ABYTES = 16; const aead_chacha20poly1305_IETF_KEYBYTES = 32; const aead_chacha20poly1305_IETF_NSECBYTES = 0; const aead_chacha20poly1305_IETF_NPUBBYTES = 12; const aead_chacha20poly1305_IETF_ABYTES = 16; const aead_xchacha20poly1305_IETF_KEYBYTES = 32; const aead_xchacha20poly1305_IETF_NSECBYTES = 0; const aead_xchacha20poly1305_IETF_NPUBBYTES = 24; const aead_xchacha20poly1305_IETF_ABYTES = 16; const box_curve25519xsalsa20poly1305_SEEDBYTES = 32; const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32; const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32; const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32; const box_curve25519xsalsa20poly1305_NONCEBYTES = 24; const box_curve25519xsalsa20poly1305_MACBYTES = 16; const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16; const box_curve25519xsalsa20poly1305_ZEROBYTES = 32; const onetimeauth_poly1305_BYTES = 16; const onetimeauth_poly1305_KEYBYTES = 32; const secretbox_xsalsa20poly1305_KEYBYTES = 32; const secretbox_xsalsa20poly1305_NONCEBYTES = 24; const secretbox_xsalsa20poly1305_MACBYTES = 16; const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16; const secretbox_xsalsa20poly1305_ZEROBYTES = 32; const secretbox_xchacha20poly1305_KEYBYTES = 32; const secretbox_xchacha20poly1305_NONCEBYTES = 24; const secretbox_xchacha20poly1305_MACBYTES = 16; const secretbox_xchacha20poly1305_BOXZEROBYTES = 16; const secretbox_xchacha20poly1305_ZEROBYTES = 32; const stream_salsa20_KEYBYTES = 32; /** * AEAD Decryption with ChaCha20-Poly1305 * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_decrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $len - Length of message (ciphertext + MAC) */ $len = ParagonIE_Sodium_Core_Util::strlen($message); /** @var int $clen - Length of ciphertext */ $clen = $len - self::aead_chacha20poly1305_ABYTES; /** @var int $adlen - Length of associated data */ $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); /** @var string $mac - Message authentication code */ $mac = ParagonIE_Sodium_Core_Util::substr( $message, $clen, self::aead_chacha20poly1305_ABYTES ); /** @var string $ciphertext - The encrypted message (sans MAC) */ $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 0, $clen); /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( 32, $nonce, $key ); /* Recalculate the Poly1305 authentication tag (MAC): */ $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } $state->update($ad); $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); $state->update($ciphertext); $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen)); $computed_mac = $state->finish(); /* Compare the given MAC with the recalculated MAC: */ if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) { throw new SodiumException('Invalid MAC'); } // Here, we know that the MAC is valid, so we decrypt and return the plaintext return ParagonIE_Sodium_Core_ChaCha20::streamXorIc( $ciphertext, $nonce, $key, ParagonIE_Sodium_Core_Util::store64_le(1) ); } /** * AEAD Encryption with ChaCha20-Poly1305 * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_encrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $len - Length of the plaintext message */ $len = ParagonIE_Sodium_Core_Util::strlen($message); /** @var int $adlen - Length of the associated data */ $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( 32, $nonce, $key ); $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } /** @var string $ciphertext - Raw encrypted data */ $ciphertext = ParagonIE_Sodium_Core_ChaCha20::streamXorIc( $message, $nonce, $key, ParagonIE_Sodium_Core_Util::store64_le(1) ); $state->update($ad); $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); $state->update($ciphertext); $state->update(ParagonIE_Sodium_Core_Util::store64_le($len)); return $ciphertext . $state->finish(); } /** * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_ietf_decrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $adlen - Length of associated data */ $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); /** @var int $len - Length of message (ciphertext + MAC) */ $len = ParagonIE_Sodium_Core_Util::strlen($message); /** @var int $clen - Length of ciphertext */ $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES; /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream( 32, $nonce, $key ); /** @var string $mac - Message authentication code */ $mac = ParagonIE_Sodium_Core_Util::substr( $message, $len - self::aead_chacha20poly1305_IETF_ABYTES, self::aead_chacha20poly1305_IETF_ABYTES ); /** @var string $ciphertext - The encrypted message (sans MAC) */ $ciphertext = ParagonIE_Sodium_Core_Util::substr( $message, 0, $len - self::aead_chacha20poly1305_IETF_ABYTES ); /* Recalculate the Poly1305 authentication tag (MAC): */ $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } $state->update($ad); $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); $state->update($ciphertext); $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf)); $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen)); $computed_mac = $state->finish(); /* Compare the given MAC with the recalculated MAC: */ if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) { throw new SodiumException('Invalid MAC'); } // Here, we know that the MAC is valid, so we decrypt and return the plaintext return ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( $ciphertext, $nonce, $key, ParagonIE_Sodium_Core_Util::store64_le(1) ); } /** * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_chacha20poly1305_ietf_encrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { /** @var int $len - Length of the plaintext message */ $len = ParagonIE_Sodium_Core_Util::strlen($message); /** @var int $adlen - Length of the associated data */ $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream( 32, $nonce, $key ); $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); try { ParagonIE_Sodium_Compat::memzero($block0); } catch (SodiumException $ex) { $block0 = null; } /** @var string $ciphertext - Raw encrypted data */ $ciphertext = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( $message, $nonce, $key, ParagonIE_Sodium_Core_Util::store64_le(1) ); $state->update($ad); $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); $state->update($ciphertext); $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf))); $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); $state->update(ParagonIE_Sodium_Core_Util::store64_le($len)); return $ciphertext . $state->finish(); } /** * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_xchacha20poly1305_ietf_decrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), $key ); $nonceLast = "\x00\x00\x00\x00" . ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey); } /** * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $ad * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function aead_xchacha20poly1305_ietf_encrypt( $message = '', $ad = '', $nonce = '', $key = '' ) { $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), $key ); $nonceLast = "\x00\x00\x00\x00" . ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey); } /** * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $key * @return string * @throws TypeError */ public static function auth($message, $key) { return ParagonIE_Sodium_Core_Util::substr( hash_hmac('sha512', $message, $key, true), 0, 32 ); } /** * HMAC-SHA-512-256 validation. Constant-time via hash_equals(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $mac * @param string $message * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ public static function auth_verify($mac, $message, $key) { return ParagonIE_Sodium_Core_Util::hashEquals( $mac, self::auth($message, $key) ); } /** * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $plaintext * @param string $nonce * @param string $keypair * @return string * @throws SodiumException * @throws TypeError */ public static function box($plaintext, $nonce, $keypair) { $c = self::secretbox( $plaintext, $nonce, self::box_beforenm( self::box_secretkey($keypair), self::box_publickey($keypair) ) ); return $c; } /** * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $publicKey * @return string * @throws SodiumException * @throws TypeError */ public static function box_seal($message, $publicKey) { /** @var string $ephemeralKeypair */ $ephemeralKeypair = self::box_keypair(); /** @var string $ephemeralSK */ $ephemeralSK = self::box_secretkey($ephemeralKeypair); /** @var string $ephemeralPK */ $ephemeralPK = self::box_publickey($ephemeralKeypair); /** @var string $nonce */ $nonce = self::generichash( $ephemeralPK . $publicKey, '', 24 ); /** @var string $keypair - The combined keypair used in crypto_box() */ $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey); /** @var string $ciphertext Ciphertext + MAC from crypto_box */ $ciphertext = self::box($message, $nonce, $keypair); try { ParagonIE_Sodium_Compat::memzero($ephemeralKeypair); ParagonIE_Sodium_Compat::memzero($ephemeralSK); ParagonIE_Sodium_Compat::memzero($nonce); } catch (SodiumException $ex) { $ephemeralKeypair = null; $ephemeralSK = null; $nonce = null; } return $ephemeralPK . $ciphertext; } /** * Opens a message encrypted via box_seal(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $keypair * @return string * @throws SodiumException * @throws TypeError */ public static function box_seal_open($message, $keypair) { /** @var string $ephemeralPK */ $ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32); /** @var string $ciphertext (ciphertext + MAC) */ $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32); /** @var string $secretKey */ $secretKey = self::box_secretkey($keypair); /** @var string $publicKey */ $publicKey = self::box_publickey($keypair); /** @var string $nonce */ $nonce = self::generichash( $ephemeralPK . $publicKey, '', 24 ); /** @var string $keypair */ $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK); /** @var string $m */ $m = self::box_open($ciphertext, $nonce, $keypair); try { ParagonIE_Sodium_Compat::memzero($secretKey); ParagonIE_Sodium_Compat::memzero($ephemeralPK); ParagonIE_Sodium_Compat::memzero($nonce); } catch (SodiumException $ex) { $secretKey = null; $ephemeralPK = null; $nonce = null; } return $m; } /** * Used by crypto_box() to get the crypto_secretbox() key. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sk * @param string $pk * @return string * @throws SodiumException * @throws TypeError */ public static function box_beforenm($sk, $pk) { return ParagonIE_Sodium_Core_HSalsa20::hsalsa20( str_repeat("\x00", 16), self::scalarmult($sk, $pk) ); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @return string * @throws Exception * @throws SodiumException * @throws TypeError */ public static function box_keypair() { $sKey = random_bytes(32); $pKey = self::scalarmult_base($sKey); return $sKey . $pKey; } /** * @param string $seed * @return string * @throws SodiumException * @throws TypeError */ public static function box_seed_keypair($seed) { $sKey = ParagonIE_Sodium_Core_Util::substr( hash('sha512', $seed, true), 0, 32 ); $pKey = self::scalarmult_base($sKey); return $sKey . $pKey; } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sKey * @param string $pKey * @return string * @throws TypeError */ public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey) { return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) . ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $keypair * @return string * @throws RangeException * @throws TypeError */ public static function box_secretkey($keypair) { if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) { throw new RangeException( 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' ); } return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $keypair * @return string * @throws RangeException * @throws TypeError */ public static function box_publickey($keypair) { if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { throw new RangeException( 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' ); } return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32); } /** * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sKey * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function box_publickey_from_secretkey($sKey) { if (ParagonIE_Sodium_Core_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) { throw new RangeException( 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.' ); } return self::scalarmult_base($sKey); } /** * Decrypt a message encrypted with box(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ciphertext * @param string $nonce * @param string $keypair * @return string * @throws SodiumException * @throws TypeError */ public static function box_open($ciphertext, $nonce, $keypair) { return self::secretbox_open( $ciphertext, $nonce, self::box_beforenm( self::box_secretkey($keypair), self::box_publickey($keypair) ) ); } /** * Calculate a BLAKE2b hash. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string|null $key * @param int $outlen * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function generichash($message, $key = '', $outlen = 32) { // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); $k = null; if (!empty($key)) { /** @var SplFixedArray $k */ $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { throw new RangeException('Invalid key size'); } } /** @var SplFixedArray $in */ $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message); /** @var SplFixedArray $ctx */ $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen); ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count()); /** @var SplFixedArray $out */ $out = new SplFixedArray($outlen); $out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out); /** @var array<int, int> */ $outArray = $out->toArray(); return ParagonIE_Sodium_Core_Util::intArrayToString($outArray); } /** * Finalize a BLAKE2b hashing context, returning the hash. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ctx * @param int $outlen * @return string * @throws SodiumException * @throws TypeError */ public static function generichash_final($ctx, $outlen = 32) { if (!is_string($ctx)) { throw new TypeError('Context must be a string'); } $out = new SplFixedArray($outlen); /** @var SplFixedArray $context */ $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx); /** @var SplFixedArray $out */ $out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out); /** @var array<int, int> */ $outArray = $out->toArray(); return ParagonIE_Sodium_Core_Util::intArrayToString($outArray); } /** * Initialize a hashing context for BLAKE2b. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $key * @param int $outputLength * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function generichash_init($key = '', $outputLength = 32) { // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); $k = null; if (!empty($key)) { $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { throw new RangeException('Invalid key size'); } } /** @var SplFixedArray $ctx */ $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength); return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx); } /** * Initialize a hashing context for BLAKE2b. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $key * @param int $outputLength * @param string $salt * @param string $personal * @return string * @throws RangeException * @throws SodiumException * @throws TypeError */ public static function generichash_init_salt_personal( $key = '', $outputLength = 32, $salt = '', $personal = '' ) { // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); $k = null; if (!empty($key)) { $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { throw new RangeException('Invalid key size'); } } if (!empty($salt)) { $s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt); } else { $s = null; } if (!empty($salt)) { $p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal); } else { $p = null; } /** @var SplFixedArray $ctx */ $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p); return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx); } /** * Update a hashing context for BLAKE2b with $message * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ctx * @param string $message * @return string * @throws SodiumException * @throws TypeError */ public static function generichash_update($ctx, $message) { // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); /** @var SplFixedArray $context */ $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx); /** @var SplFixedArray $in */ $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message); ParagonIE_Sodium_Core_BLAKE2b::update($context, $in, $in->count()); return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context); } /** * Libsodium's crypto_kx(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $my_sk * @param string $their_pk * @param string $client_pk * @param string $server_pk * @return string * @throws SodiumException * @throws TypeError */ public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) { return ParagonIE_Sodium_Compat::crypto_generichash( ParagonIE_Sodium_Compat::crypto_scalarmult($my_sk, $their_pk) . $client_pk . $server_pk ); } /** * ECDH over Curve25519 * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $sKey * @param string $pKey * @return string * * @throws SodiumException * @throws TypeError */ public static function scalarmult($sKey, $pKey) { $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); self::scalarmult_throw_if_zero($q); return $q; } /** * ECDH over Curve25519, using the basepoint. * Used to get a secret key from a public key. * * @param string $secret * @return string * * @throws SodiumException * @throws TypeError */ public static function scalarmult_base($secret) { $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret); self::scalarmult_throw_if_zero($q); return $q; } /** * This throws an Error if a zero public key was passed to the function. * * @param string $q * @return void * @throws SodiumException * @throws TypeError */ protected static function scalarmult_throw_if_zero($q) { $d = 0; for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { $d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]); } /* branch-free variant of === 0 */ if (-(1 & (($d - 1) >> 8))) { throw new SodiumException('Zero public key is not allowed'); } } /** * XSalsa20-Poly1305 authenticated symmetric-key encryption. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $plaintext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox($plaintext, $nonce, $key) { /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); /** @var string $block0 */ $block0 = str_repeat("\x00", 32); /** @var int $mlen - Length of the plaintext message */ $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext); $mlen0 = $mlen; if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) { $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES; } $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( $block0, ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), $subkey ); /** @var string $c */ $c = ParagonIE_Sodium_Core_Util::substr( $block0, self::secretbox_xsalsa20poly1305_ZEROBYTES ); if ($mlen > $mlen0) { $c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( ParagonIE_Sodium_Core_Util::substr( $plaintext, self::secretbox_xsalsa20poly1305_ZEROBYTES ), ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), 1, $subkey ); } $state = new ParagonIE_Sodium_Core_Poly1305_State( ParagonIE_Sodium_Core_Util::substr( $block0, 0, self::onetimeauth_poly1305_KEYBYTES ) ); try { ParagonIE_Sodium_Compat::memzero($block0); ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $block0 = null; $subkey = null; } $state->update($c); /** @var string $c - MAC || ciphertext */ $c = $state->finish() . $c; unset($state); return $c; } /** * Decrypt a ciphertext generated via secretbox(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ciphertext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox_open($ciphertext, $nonce, $key) { /** @var string $mac */ $mac = ParagonIE_Sodium_Core_Util::substr( $ciphertext, 0, self::secretbox_xsalsa20poly1305_MACBYTES ); /** @var string $c */ $c = ParagonIE_Sodium_Core_Util::substr( $ciphertext, self::secretbox_xsalsa20poly1305_MACBYTES ); /** @var int $clen */ $clen = ParagonIE_Sodium_Core_Util::strlen($c); /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( 64, ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), $subkey ); $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify( $mac, $c, ParagonIE_Sodium_Core_Util::substr($block0, 0, 32) ); if (!$verified) { try { ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $subkey = null; } throw new SodiumException('Invalid MAC'); } /** @var string $m - Decrypted message */ $m = ParagonIE_Sodium_Core_Util::xorStrings( ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) ); if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { // We had more than 1 block, so let's continue to decrypt the rest. $m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( ParagonIE_Sodium_Core_Util::substr( $c, self::secretbox_xsalsa20poly1305_ZEROBYTES ), ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), 1, (string) $subkey ); } return $m; } /** * XChaCha20-Poly1305 authenticated symmetric-key encryption. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $plaintext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) { /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), $key ); $nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); /** @var string $block0 */ $block0 = str_repeat("\x00", 32); /** @var int $mlen - Length of the plaintext message */ $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext); $mlen0 = $mlen; if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; } $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc( $block0, $nonceLast, $subkey ); /** @var string $c */ $c = ParagonIE_Sodium_Core_Util::substr( $block0, self::secretbox_xchacha20poly1305_ZEROBYTES ); if ($mlen > $mlen0) { $c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc( ParagonIE_Sodium_Core_Util::substr( $plaintext, self::secretbox_xchacha20poly1305_ZEROBYTES ), $nonceLast, $subkey, ParagonIE_Sodium_Core_Util::store64_le(1) ); } $state = new ParagonIE_Sodium_Core_Poly1305_State( ParagonIE_Sodium_Core_Util::substr( $block0, 0, self::onetimeauth_poly1305_KEYBYTES ) ); try { ParagonIE_Sodium_Compat::memzero($block0); ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $block0 = null; $subkey = null; } $state->update($c); /** @var string $c - MAC || ciphertext */ $c = $state->finish() . $c; unset($state); return $c; } /** * Decrypt a ciphertext generated via secretbox_xchacha20poly1305(). * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $ciphertext * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) { /** @var string $mac */ $mac = ParagonIE_Sodium_Core_Util::substr( $ciphertext, 0, self::secretbox_xchacha20poly1305_MACBYTES ); /** @var string $c */ $c = ParagonIE_Sodium_Core_Util::substr( $ciphertext, self::secretbox_xchacha20poly1305_MACBYTES ); /** @var int $clen */ $clen = ParagonIE_Sodium_Core_Util::strlen($c); /** @var string $subkey */ $subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key); /** @var string $block0 */ $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( 64, ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), $subkey ); $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify( $mac, $c, ParagonIE_Sodium_Core_Util::substr($block0, 0, 32) ); if (!$verified) { try { ParagonIE_Sodium_Compat::memzero($subkey); } catch (SodiumException $ex) { $subkey = null; } throw new SodiumException('Invalid MAC'); } /** @var string $m - Decrypted message */ $m = ParagonIE_Sodium_Core_Util::xorStrings( ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) ); if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { // We had more than 1 block, so let's continue to decrypt the rest. $m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc( ParagonIE_Sodium_Core_Util::substr( $c, self::secretbox_xchacha20poly1305_ZEROBYTES ), ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), (string) $subkey, ParagonIE_Sodium_Core_Util::store64_le(1) ); } return $m; } /** * @param string $key * @return array<int, string> Returns a state and a header. * @throws Exception * @throws SodiumException */ public static function secretstream_xchacha20poly1305_init_push($key) { # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES); $out = random_bytes(24); # crypto_core_hchacha20(state->k, out, k, NULL); $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key); $state = new ParagonIE_Sodium_Core_SecretStream_State( $subkey, ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4) ); # _crypto_secretstream_xchacha20poly1305_counter_reset(state); $state->counterReset(); # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); # memset(state->_pad, 0, sizeof state->_pad); return array( $state->toString(), $out ); } /** * @param string $key * @param string $header * @return string Returns a state. * @throws Exception */ public static function secretstream_xchacha20poly1305_init_pull($key, $header) { # crypto_core_hchacha20(state->k, in, k, NULL); $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( ParagonIE_Sodium_Core_Util::substr($header, 0, 16), $key ); $state = new ParagonIE_Sodium_Core_SecretStream_State( $subkey, ParagonIE_Sodium_Core_Util::substr($header, 16) ); $state->counterReset(); # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); # memset(state->_pad, 0, sizeof state->_pad); # return 0; return $state->toString(); } /** * @param string $state * @param string $msg * @param string $aad * @param int $tag * @return string * @throws SodiumException */ public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) { $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state); # crypto_onetimeauth_poly1305_state poly1305_state; # unsigned char block[64U]; # unsigned char slen[8U]; # unsigned char *c; # unsigned char *mac; $msglen = ParagonIE_Sodium_Core_Util::strlen($msg); $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad); if ((($msglen + 63) >> 6) > 0xfffffffe) { throw new SodiumException( 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' ); } # if (outlen_p != NULL) { # *outlen_p = 0U; # } # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { # sodium_misuse(); # } # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); # crypto_onetimeauth_poly1305_init(&poly1305_state, block); # sodium_memzero(block, sizeof block); $auth = new ParagonIE_Sodium_Core_Poly1305_State( ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); $auth->update($aad); # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, # (0x10 - adlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); # memset(block, 0, sizeof block); # block[0] = tag; # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, # state->nonce, 1U, state->k); $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63), $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core_Util::store64_le(1) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); $auth->update($block); # out[0] = block[0]; $out = $block[0]; # c = out + (sizeof tag); # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); $cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( $msg, $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core_Util::store64_le(2) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); $auth->update($cipher); $out .= $cipher; unset($cipher); # crypto_onetimeauth_poly1305_update # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); # STORE64_LE(slen, (uint64_t) adlen); $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $auth->update($slen); # STORE64_LE(slen, (sizeof block) + mlen); $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $auth->update($slen); # mac = c + mlen; # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); $mac = $auth->finish(); $out .= $mac; # sodium_memzero(&poly1305_state, sizeof poly1305_state); unset($auth); # XOR_BUF(STATE_INONCE(state), mac, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); $st->xorNonce($mac); # sodium_increment(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); $st->incrementCounter(); // Overwrite by reference: $state = $st->toString(); /** @var bool $rekey */ $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || # sodium_is_zero(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { # crypto_secretstream_xchacha20poly1305_rekey(state); # } if ($rekey || $st->needsRekey()) { // DO REKEY self::secretstream_xchacha20poly1305_rekey($state); } # if (outlen_p != NULL) { # *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; # } return $out; } /** * @param string $state * @param string $cipher * @param string $aad * @return bool|array{0: string, 1: int} * @throws SodiumException */ public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '') { $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state); $cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher); # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad); # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { # sodium_misuse(); # } if ((($msglen + 63) >> 6) > 0xfffffffe) { throw new SodiumException( 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' ); } # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); # crypto_onetimeauth_poly1305_init(&poly1305_state, block); # sodium_memzero(block, sizeof block); $auth = new ParagonIE_Sodium_Core_Poly1305_State( ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) ); # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); $auth->update($aad); # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, # (0x10 - adlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); # memset(block, 0, sizeof block); # block[0] = in[0]; # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, # state->nonce, 1U, state->k); $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( $cipher[0] . str_repeat("\0", 63), $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core_Util::store64_le(1) ); # tag = block[0]; # block[0] = in[0]; # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); $tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]); $block[0] = $cipher[0]; $auth->update($block); # c = in + (sizeof tag); # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); $auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen)); # crypto_onetimeauth_poly1305_update # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); # STORE64_LE(slen, (uint64_t) adlen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen); $auth->update($slen); # STORE64_LE(slen, (sizeof block) + mlen); # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen); $auth->update($slen); # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); # sodium_memzero(&poly1305_state, sizeof poly1305_state); $mac = $auth->finish(); # stored_mac = c + mlen; # if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { # sodium_memzero(mac, sizeof mac); # return -1; # } $stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16); if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) { return false; } # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); $out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen), $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core_Util::store64_le(2) ); # XOR_BUF(STATE_INONCE(state), mac, # crypto_secretstream_xchacha20poly1305_INONCEBYTES); $st->xorNonce($mac); # sodium_increment(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); $st->incrementCounter(); # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || # sodium_is_zero(STATE_COUNTER(state), # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { # crypto_secretstream_xchacha20poly1305_rekey(state); # } // Overwrite by reference: $state = $st->toString(); /** @var bool $rekey */ $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; if ($rekey || $st->needsRekey()) { // DO REKEY self::secretstream_xchacha20poly1305_rekey($state); } return array($out, $tag); } /** * @param string $state * @return void * @throws SodiumException */ public static function secretstream_xchacha20poly1305_rekey(&$state) { $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state); # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + # crypto_secretstream_xchacha20poly1305_INONCEBYTES]; # size_t i; # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { # new_key_and_inonce[i] = state->k[i]; # } $new_key_and_inonce = $st->getKey(); # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = # STATE_INONCE(state)[i]; # } $new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8); # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, # sizeof new_key_and_inonce, # state->nonce, state->k); $st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( $new_key_and_inonce, $st->getCombinedNonce(), $st->getKey(), ParagonIE_Sodium_Core_Util::store64_le(0) )); # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { # state->k[i] = new_key_and_inonce[i]; # } # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { # STATE_INONCE(state)[i] = # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]; # } # _crypto_secretstream_xchacha20poly1305_counter_reset(state); $st->counterReset(); $state = $st->toString(); } /** * Detached Ed25519 signature. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign_detached($message, $sk) { return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk); } /** * Attached Ed25519 signature. (Returns a signed message.) * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign($message, $sk) { return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk); } /** * Opens a signed message. If valid, returns the message. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $signedMessage * @param string $pk * @return string * @throws SodiumException * @throws TypeError */ public static function sign_open($signedMessage, $pk) { return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage, $pk); } /** * Verify a detached signature of a given message and public key. * * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. * * @param string $signature * @param string $message * @param string $pk * @return bool * @throws SodiumException * @throws TypeError */ public static function sign_verify_detached($signature, $message, $pk) { return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature, $message, $pk); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Int32.php������������������������������������������������������������������������������������0000644�����������������00000060004�15021200076�0007202 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core32_Int32 * * Encapsulates a 32-bit integer. * * These are immutable. It always returns a new instance. */ class ParagonIE_Sodium_Core32_Int32 { /** * @var array<int, int> - two 16-bit integers * * 0 is the higher 16 bits * 1 is the lower 16 bits */ public $limbs = array(0, 0); /** * @var int */ public $overflow = 0; /** * @var bool */ public $unsignedInt = false; /** * ParagonIE_Sodium_Core32_Int32 constructor. * @param array $array * @param bool $unsignedInt */ public function __construct($array = array(0, 0), $unsignedInt = false) { $this->limbs = array( (int) $array[0], (int) $array[1] ); $this->overflow = 0; $this->unsignedInt = $unsignedInt; } /** * Adds two int32 objects * * @param ParagonIE_Sodium_Core32_Int32 $addend * @return ParagonIE_Sodium_Core32_Int32 */ public function addInt32(ParagonIE_Sodium_Core32_Int32 $addend) { $i0 = $this->limbs[0]; $i1 = $this->limbs[1]; $j0 = $addend->limbs[0]; $j1 = $addend->limbs[1]; $r1 = $i1 + ($j1 & 0xffff); $carry = $r1 >> 16; $r0 = $i0 + ($j0 & 0xffff) + $carry; $carry = $r0 >> 16; $r0 &= 0xffff; $r1 &= 0xffff; $return = new ParagonIE_Sodium_Core32_Int32( array($r0, $r1) ); $return->overflow = $carry; $return->unsignedInt = $this->unsignedInt; return $return; } /** * Adds a normal integer to an int32 object * * @param int $int * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError */ public function addInt($int) { ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); /** @var int $int */ $int = (int) $int; $int = (int) $int; $i0 = $this->limbs[0]; $i1 = $this->limbs[1]; $r1 = $i1 + ($int & 0xffff); $carry = $r1 >> 16; $r0 = $i0 + (($int >> 16) & 0xffff) + $carry; $carry = $r0 >> 16; $r0 &= 0xffff; $r1 &= 0xffff; $return = new ParagonIE_Sodium_Core32_Int32( array($r0, $r1) ); $return->overflow = $carry; $return->unsignedInt = $this->unsignedInt; return $return; } /** * @param int $b * @return int */ public function compareInt($b = 0) { $gt = 0; $eq = 1; $i = 2; $j = 0; while ($i > 0) { --$i; /** @var int $x1 */ $x1 = $this->limbs[$i]; /** @var int $x2 */ $x2 = ($b >> ($j << 4)) & 0xffff; /** @var int $gt */ $gt |= (($x2 - $x1) >> 8) & $eq; /** @var int $eq */ $eq &= (($x2 ^ $x1) - 1) >> 8; } return ($gt + $gt - $eq) + 1; } /** * @param int $m * @return ParagonIE_Sodium_Core32_Int32 */ public function mask($m = 0) { /** @var int $hi */ $hi = ((int) $m >> 16); $hi &= 0xffff; /** @var int $lo */ $lo = ((int) $m) & 0xffff; return new ParagonIE_Sodium_Core32_Int32( array( (int) ($this->limbs[0] & $hi), (int) ($this->limbs[1] & $lo) ), $this->unsignedInt ); } /** * @param array<int, int> $a * @param array<int, int> $b * @param int $baseLog2 * @return array<int, int> */ public function multiplyLong(array $a, array $b, $baseLog2 = 16) { $a_l = count($a); $b_l = count($b); /** @var array<int, int> $r */ $r = array_fill(0, $a_l + $b_l + 1, 0); $base = 1 << $baseLog2; for ($i = 0; $i < $a_l; ++$i) { $a_i = $a[$i]; for ($j = 0; $j < $a_l; ++$j) { $b_j = $b[$j]; $product = ($a_i * $b_j) + $r[$i + $j]; $carry = ((int) $product >> $baseLog2 & 0xffff); $r[$i + $j] = ((int) $product - (int) ($carry * $base)) & 0xffff; $r[$i + $j + 1] += $carry; } } return array_slice($r, 0, 5); } /** * @param int $int * @return ParagonIE_Sodium_Core32_Int32 */ public function mulIntFast($int) { // Handle negative numbers $aNeg = ($this->limbs[0] >> 15) & 1; $bNeg = ($int >> 31) & 1; $a = array_reverse($this->limbs); $b = array( $int & 0xffff, ($int >> 16) & 0xffff ); if ($aNeg) { for ($i = 0; $i < 2; ++$i) { $a[$i] = ($a[$i] ^ 0xffff) & 0xffff; } ++$a[0]; } if ($bNeg) { for ($i = 0; $i < 2; ++$i) { $b[$i] = ($b[$i] ^ 0xffff) & 0xffff; } ++$b[0]; } // Multiply $res = $this->multiplyLong($a, $b); // Re-apply negation to results if ($aNeg !== $bNeg) { for ($i = 0; $i < 2; ++$i) { $res[$i] = (0xffff ^ $res[$i]) & 0xffff; } // Handle integer overflow $c = 1; for ($i = 0; $i < 2; ++$i) { $res[$i] += $c; $c = $res[$i] >> 16; $res[$i] &= 0xffff; } } // Return our values $return = new ParagonIE_Sodium_Core32_Int32(); $return->limbs = array( $res[1] & 0xffff, $res[0] & 0xffff ); if (count($res) > 2) { $return->overflow = $res[2] & 0xffff; } $return->unsignedInt = $this->unsignedInt; return $return; } /** * @param ParagonIE_Sodium_Core32_Int32 $right * @return ParagonIE_Sodium_Core32_Int32 */ public function mulInt32Fast(ParagonIE_Sodium_Core32_Int32 $right) { $aNeg = ($this->limbs[0] >> 15) & 1; $bNeg = ($right->limbs[0] >> 15) & 1; $a = array_reverse($this->limbs); $b = array_reverse($right->limbs); if ($aNeg) { for ($i = 0; $i < 2; ++$i) { $a[$i] = ($a[$i] ^ 0xffff) & 0xffff; } ++$a[0]; } if ($bNeg) { for ($i = 0; $i < 2; ++$i) { $b[$i] = ($b[$i] ^ 0xffff) & 0xffff; } ++$b[0]; } $res = $this->multiplyLong($a, $b); if ($aNeg !== $bNeg) { if ($aNeg !== $bNeg) { for ($i = 0; $i < 2; ++$i) { $res[$i] = ($res[$i] ^ 0xffff) & 0xffff; } $c = 1; for ($i = 0; $i < 2; ++$i) { $res[$i] += $c; $c = $res[$i] >> 16; $res[$i] &= 0xffff; } } } $return = new ParagonIE_Sodium_Core32_Int32(); $return->limbs = array( $res[1] & 0xffff, $res[0] & 0xffff ); if (count($res) > 2) { $return->overflow = $res[2]; } return $return; } /** * @param int $int * @param int $size * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError */ public function mulInt($int = 0, $size = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2); if (ParagonIE_Sodium_Compat::$fastMult) { return $this->mulIntFast((int) $int); } /** @var int $int */ $int = (int) $int; /** @var int $size */ $size = (int) $size; if (!$size) { $size = 31; } /** @var int $size */ $a = clone $this; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; // Initialize: $ret0 = 0; $ret1 = 0; $a0 = $a->limbs[0]; $a1 = $a->limbs[1]; /** @var int $size */ /** @var int $i */ for ($i = $size; $i >= 0; --$i) { $m = (int) (-($int & 1)); $x0 = $a0 & $m; $x1 = $a1 & $m; $ret1 += $x1; $c = $ret1 >> 16; $ret0 += $x0 + $c; $ret0 &= 0xffff; $ret1 &= 0xffff; $a1 = ($a1 << 1); $x1 = $a1 >> 16; $a0 = ($a0 << 1) | $x1; $a0 &= 0xffff; $a1 &= 0xffff; $int >>= 1; } $return->limbs[0] = $ret0; $return->limbs[1] = $ret1; return $return; } /** * @param ParagonIE_Sodium_Core32_Int32 $int * @param int $size * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError */ public function mulInt32(ParagonIE_Sodium_Core32_Int32 $int, $size = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2); if (ParagonIE_Sodium_Compat::$fastMult) { return $this->mulInt32Fast($int); } if (!$size) { $size = 31; } /** @var int $size */ $a = clone $this; $b = clone $int; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; // Initialize: $ret0 = 0; $ret1 = 0; $a0 = $a->limbs[0]; $a1 = $a->limbs[1]; $b0 = $b->limbs[0]; $b1 = $b->limbs[1]; /** @var int $size */ /** @var int $i */ for ($i = $size; $i >= 0; --$i) { $m = (int) (-($b1 & 1)); $x0 = $a0 & $m; $x1 = $a1 & $m; $ret1 += $x1; $c = $ret1 >> 16; $ret0 += $x0 + $c; $ret0 &= 0xffff; $ret1 &= 0xffff; $a1 = ($a1 << 1); $x1 = $a1 >> 16; $a0 = ($a0 << 1) | $x1; $a0 &= 0xffff; $a1 &= 0xffff; $x0 = ($b0 & 1) << 16; $b0 = ($b0 >> 1); $b1 = (($b1 | $x0) >> 1); $b0 &= 0xffff; $b1 &= 0xffff; } $return->limbs[0] = $ret0; $return->limbs[1] = $ret1; return $return; } /** * OR this 32-bit integer with another. * * @param ParagonIE_Sodium_Core32_Int32 $b * @return ParagonIE_Sodium_Core32_Int32 */ public function orInt32(ParagonIE_Sodium_Core32_Int32 $b) { $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; $return->limbs = array( (int) ($this->limbs[0] | $b->limbs[0]), (int) ($this->limbs[1] | $b->limbs[1]) ); /** @var int overflow */ $return->overflow = $this->overflow | $b->overflow; return $return; } /** * @param int $b * @return bool */ public function isGreaterThan($b = 0) { return $this->compareInt($b) > 0; } /** * @param int $b * @return bool */ public function isLessThanInt($b = 0) { return $this->compareInt($b) < 0; } /** * @param int $c * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess */ public function rotateLeft($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; $c &= 31; if ($c === 0) { // NOP, but we want a copy. $return->limbs = $this->limbs; } else { /** @var int $c */ /** @var int $idx_shift */ $idx_shift = ($c >> 4) & 1; /** @var int $sub_shift */ $sub_shift = $c & 15; /** @var array<int, int> $limbs */ $limbs =& $return->limbs; /** @var array<int, int> $myLimbs */ $myLimbs =& $this->limbs; for ($i = 1; $i >= 0; --$i) { /** @var int $j */ $j = ($i + $idx_shift) & 1; /** @var int $k */ $k = ($i + $idx_shift + 1) & 1; $limbs[$i] = (int) ( ( ((int) ($myLimbs[$j]) << $sub_shift) | ((int) ($myLimbs[$k]) >> (16 - $sub_shift)) ) & 0xffff ); } } return $return; } /** * Rotate to the right * * @param int $c * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess */ public function rotateRight($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; $c &= 31; /** @var int $c */ if ($c === 0) { // NOP, but we want a copy. $return->limbs = $this->limbs; } else { /** @var int $c */ /** @var int $idx_shift */ $idx_shift = ($c >> 4) & 1; /** @var int $sub_shift */ $sub_shift = $c & 15; /** @var array<int, int> $limbs */ $limbs =& $return->limbs; /** @var array<int, int> $myLimbs */ $myLimbs =& $this->limbs; for ($i = 1; $i >= 0; --$i) { /** @var int $j */ $j = ($i - $idx_shift) & 1; /** @var int $k */ $k = ($i - $idx_shift - 1) & 1; $limbs[$i] = (int) ( ( ((int) ($myLimbs[$j]) >> (int) ($sub_shift)) | ((int) ($myLimbs[$k]) << (16 - (int) ($sub_shift))) ) & 0xffff ); } } return $return; } /** * @param bool $bool * @return self */ public function setUnsignedInt($bool = false) { $this->unsignedInt = !empty($bool); return $this; } /** * @param int $c * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError */ public function shiftLeft($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; $c &= 63; /** @var int $c */ if ($c === 0) { $return->limbs = $this->limbs; } elseif ($c < 0) { /** @var int $c */ return $this->shiftRight(-$c); } else { /** @var int $c */ /** @var int $tmp */ $tmp = $this->limbs[1] << $c; $return->limbs[1] = (int)($tmp & 0xffff); /** @var int $carry */ $carry = $tmp >> 16; /** @var int $tmp */ $tmp = ($this->limbs[0] << $c) | ($carry & 0xffff); $return->limbs[0] = (int) ($tmp & 0xffff); } return $return; } /** * @param int $c * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand */ public function shiftRight($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; $c &= 63; /** @var int $c */ if ($c >= 16) { $return->limbs = array( (int) ($this->overflow & 0xffff), (int) ($this->limbs[0]) ); $return->overflow = $this->overflow >> 16; return $return->shiftRight($c & 15); } if ($c === 0) { $return->limbs = $this->limbs; } elseif ($c < 0) { /** @var int $c */ return $this->shiftLeft(-$c); } else { if (!is_int($c)) { throw new TypeError(); } /** @var int $c */ // $return->limbs[0] = (int) (($this->limbs[0] >> $c) & 0xffff); $carryLeft = (int) ($this->overflow & ((1 << ($c + 1)) - 1)); $return->limbs[0] = (int) ((($this->limbs[0] >> $c) | ($carryLeft << (16 - $c))) & 0xffff); $carryRight = (int) ($this->limbs[0] & ((1 << ($c + 1)) - 1)); $return->limbs[1] = (int) ((($this->limbs[1] >> $c) | ($carryRight << (16 - $c))) & 0xffff); $return->overflow >>= $c; } return $return; } /** * Subtract a normal integer from an int32 object. * * @param int $int * @return ParagonIE_Sodium_Core32_Int32 * @throws SodiumException * @throws TypeError */ public function subInt($int) { ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); /** @var int $int */ $int = (int) $int; $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; /** @var int $tmp */ $tmp = $this->limbs[1] - ($int & 0xffff); /** @var int $carry */ $carry = $tmp >> 16; $return->limbs[1] = (int) ($tmp & 0xffff); /** @var int $tmp */ $tmp = $this->limbs[0] - (($int >> 16) & 0xffff) + $carry; $return->limbs[0] = (int) ($tmp & 0xffff); return $return; } /** * Subtract two int32 objects from each other * * @param ParagonIE_Sodium_Core32_Int32 $b * @return ParagonIE_Sodium_Core32_Int32 */ public function subInt32(ParagonIE_Sodium_Core32_Int32 $b) { $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; /** @var int $tmp */ $tmp = $this->limbs[1] - ($b->limbs[1] & 0xffff); /** @var int $carry */ $carry = $tmp >> 16; $return->limbs[1] = (int) ($tmp & 0xffff); /** @var int $tmp */ $tmp = $this->limbs[0] - ($b->limbs[0] & 0xffff) + $carry; $return->limbs[0] = (int) ($tmp & 0xffff); return $return; } /** * XOR this 32-bit integer with another. * * @param ParagonIE_Sodium_Core32_Int32 $b * @return ParagonIE_Sodium_Core32_Int32 */ public function xorInt32(ParagonIE_Sodium_Core32_Int32 $b) { $return = new ParagonIE_Sodium_Core32_Int32(); $return->unsignedInt = $this->unsignedInt; $return->limbs = array( (int) ($this->limbs[0] ^ $b->limbs[0]), (int) ($this->limbs[1] ^ $b->limbs[1]) ); return $return; } /** * @param int $signed * @return self * @throws SodiumException * @throws TypeError */ public static function fromInt($signed) { ParagonIE_Sodium_Core32_Util::declareScalarType($signed, 'int', 1);; /** @var int $signed */ $signed = (int) $signed; return new ParagonIE_Sodium_Core32_Int32( array( (int) (($signed >> 16) & 0xffff), (int) ($signed & 0xffff) ) ); } /** * @param string $string * @return self * @throws SodiumException * @throws TypeError */ public static function fromString($string) { ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1); $string = (string) $string; if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) { throw new RangeException( 'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.' ); } $return = new ParagonIE_Sodium_Core32_Int32(); $return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8); $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff); $return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8); $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff); return $return; } /** * @param string $string * @return self * @throws SodiumException * @throws TypeError */ public static function fromReverseString($string) { ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1); $string = (string) $string; if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) { throw new RangeException( 'String must be 4 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.' ); } $return = new ParagonIE_Sodium_Core32_Int32(); $return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8); $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff); $return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8); $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff); return $return; } /** * @return array<int, int> */ public function toArray() { return array((int) ($this->limbs[0] << 16 | $this->limbs[1])); } /** * @return string * @throws TypeError */ public function toString() { return ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff); } /** * @return int */ public function toInt() { return (int) ( (($this->limbs[0] & 0xffff) << 16) | ($this->limbs[1] & 0xffff) ); } /** * @return ParagonIE_Sodium_Core32_Int32 */ public function toInt32() { $return = new ParagonIE_Sodium_Core32_Int32(); $return->limbs[0] = (int) ($this->limbs[0] & 0xffff); $return->limbs[1] = (int) ($this->limbs[1] & 0xffff); $return->unsignedInt = $this->unsignedInt; $return->overflow = (int) ($this->overflow & 0x7fffffff); return $return; } /** * @return ParagonIE_Sodium_Core32_Int64 */ public function toInt64() { $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; if ($this->unsignedInt) { $return->limbs[0] += (($this->overflow >> 16) & 0xffff); $return->limbs[1] += (($this->overflow) & 0xffff); } else { $neg = -(($this->limbs[0] >> 15) & 1); $return->limbs[0] = (int)($neg & 0xffff); $return->limbs[1] = (int)($neg & 0xffff); } $return->limbs[2] = (int) ($this->limbs[0] & 0xffff); $return->limbs[3] = (int) ($this->limbs[1] & 0xffff); return $return; } /** * @return string * @throws TypeError */ public function toReverseString() { return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff); } /** * @return string */ public function __toString() { try { return $this->toString(); } catch (TypeError $ex) { // PHP engine can't handle exceptions from __toString() return ''; } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/SecretStream/State.php�����������������������������������������������������������������������0000644�����������������00000007110�15021200076�0011763 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core32_SecretStream_State */ class ParagonIE_Sodium_Core32_SecretStream_State { /** @var string $key */ protected $key; /** @var int $counter */ protected $counter; /** @var string $nonce */ protected $nonce; /** @var string $_pad */ protected $_pad; /** * ParagonIE_Sodium_Core32_SecretStream_State constructor. * @param string $key * @param string|null $nonce */ public function __construct($key, $nonce = null) { $this->key = $key; $this->counter = 1; if (is_null($nonce)) { $nonce = str_repeat("\0", 12); } $this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);; $this->_pad = str_repeat("\0", 4); } /** * @return self */ public function counterReset() { $this->counter = 1; $this->_pad = str_repeat("\0", 4); return $this; } /** * @return string */ public function getKey() { return $this->key; } /** * @return string */ public function getCounter() { return ParagonIE_Sodium_Core32_Util::store32_le($this->counter); } /** * @return string */ public function getNonce() { if (!is_string($this->nonce)) { $this->nonce = str_repeat("\0", 12); } if (ParagonIE_Sodium_Core32_Util::strlen($this->nonce) !== 12) { $this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT); } return $this->nonce; } /** * @return string */ public function getCombinedNonce() { return $this->getCounter() . ParagonIE_Sodium_Core32_Util::substr($this->getNonce(), 0, 8); } /** * @return self */ public function incrementCounter() { ++$this->counter; return $this; } /** * @return bool */ public function needsRekey() { return ($this->counter & 0xffff) === 0; } /** * @param string $newKeyAndNonce * @return self */ public function rekey($newKeyAndNonce) { $this->key = ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 0, 32); $this->nonce = str_pad( ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 32), 12, "\0", STR_PAD_RIGHT ); return $this; } /** * @param string $str * @return self */ public function xorNonce($str) { $this->nonce = ParagonIE_Sodium_Core32_Util::xorStrings( $this->getNonce(), str_pad( ParagonIE_Sodium_Core32_Util::substr($str, 0, 8), 12, "\0", STR_PAD_RIGHT ) ); return $this; } /** * @param string $string * @return self */ public static function fromString($string) { $state = new ParagonIE_Sodium_Core32_SecretStream_State( ParagonIE_Sodium_Core32_Util::substr($string, 0, 32) ); $state->counter = ParagonIE_Sodium_Core32_Util::load_4( ParagonIE_Sodium_Core32_Util::substr($string, 32, 4) ); $state->nonce = ParagonIE_Sodium_Core32_Util::substr($string, 36, 12); $state->_pad = ParagonIE_Sodium_Core32_Util::substr($string, 48, 8); return $state; } /** * @return string */ public function toString() { return $this->key . $this->getCounter() . $this->nonce . $this->_pad; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/SipHash.php����������������������������������������������������������������������������������0000644�����������������00000014725�15021200076�0007653 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_SipHash', false)) { return; } /** * Class ParagonIE_SodiumCompat_Core32_SipHash * * Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers */ class ParagonIE_Sodium_Core32_SipHash extends ParagonIE_Sodium_Core32_Util { /** * @internal You should not use this directly from another application * * @param array<int, ParagonIE_Sodium_Core32_Int64> $v * @return array<int, ParagonIE_Sodium_Core32_Int64> */ public static function sipRound(array $v) { # v0 += v1; $v[0] = $v[0]->addInt64($v[1]); # v1 = ROTL(v1, 13); $v[1] = $v[1]->rotateLeft(13); # v1 ^= v0; $v[1] = $v[1]->xorInt64($v[0]); # v0=ROTL(v0,32); $v[0] = $v[0]->rotateLeft(32); # v2 += v3; $v[2] = $v[2]->addInt64($v[3]); # v3=ROTL(v3,16); $v[3] = $v[3]->rotateLeft(16); # v3 ^= v2; $v[3] = $v[3]->xorInt64($v[2]); # v0 += v3; $v[0] = $v[0]->addInt64($v[3]); # v3=ROTL(v3,21); $v[3] = $v[3]->rotateLeft(21); # v3 ^= v0; $v[3] = $v[3]->xorInt64($v[0]); # v2 += v1; $v[2] = $v[2]->addInt64($v[1]); # v1=ROTL(v1,17); $v[1] = $v[1]->rotateLeft(17); # v1 ^= v2; $v[1] = $v[1]->xorInt64($v[2]); # v2=ROTL(v2,32) $v[2] = $v[2]->rotateLeft(32); return $v; } /** * @internal You should not use this directly from another application * * @param string $in * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function sipHash24($in, $key) { $inlen = self::strlen($in); # /* "somepseudorandomlygeneratedbytes" */ # u64 v0 = 0x736f6d6570736575ULL; # u64 v1 = 0x646f72616e646f6dULL; # u64 v2 = 0x6c7967656e657261ULL; # u64 v3 = 0x7465646279746573ULL; $v = array( new ParagonIE_Sodium_Core32_Int64( array(0x736f, 0x6d65, 0x7073, 0x6575) ), new ParagonIE_Sodium_Core32_Int64( array(0x646f, 0x7261, 0x6e64, 0x6f6d) ), new ParagonIE_Sodium_Core32_Int64( array(0x6c79, 0x6765, 0x6e65, 0x7261) ), new ParagonIE_Sodium_Core32_Int64( array(0x7465, 0x6462, 0x7974, 0x6573) ) ); # u64 k0 = LOAD64_LE( k ); # u64 k1 = LOAD64_LE( k + 8 ); $k = array( ParagonIE_Sodium_Core32_Int64::fromReverseString( self::substr($key, 0, 8) ), ParagonIE_Sodium_Core32_Int64::fromReverseString( self::substr($key, 8, 8) ) ); # b = ( ( u64 )inlen ) << 56; $b = new ParagonIE_Sodium_Core32_Int64( array(($inlen << 8) & 0xffff, 0, 0, 0) ); # v3 ^= k1; $v[3] = $v[3]->xorInt64($k[1]); # v2 ^= k0; $v[2] = $v[2]->xorInt64($k[0]); # v1 ^= k1; $v[1] = $v[1]->xorInt64($k[1]); # v0 ^= k0; $v[0] = $v[0]->xorInt64($k[0]); $left = $inlen; # for ( ; in != end; in += 8 ) while ($left >= 8) { # m = LOAD64_LE( in ); $m = ParagonIE_Sodium_Core32_Int64::fromReverseString( self::substr($in, 0, 8) ); # v3 ^= m; $v[3] = $v[3]->xorInt64($m); # SIPROUND; # SIPROUND; $v = self::sipRound($v); $v = self::sipRound($v); # v0 ^= m; $v[0] = $v[0]->xorInt64($m); $in = self::substr($in, 8); $left -= 8; } # switch( left ) # { # case 7: b |= ( ( u64 )in[ 6] ) << 48; # case 6: b |= ( ( u64 )in[ 5] ) << 40; # case 5: b |= ( ( u64 )in[ 4] ) << 32; # case 4: b |= ( ( u64 )in[ 3] ) << 24; # case 3: b |= ( ( u64 )in[ 2] ) << 16; # case 2: b |= ( ( u64 )in[ 1] ) << 8; # case 1: b |= ( ( u64 )in[ 0] ); break; # case 0: break; # } switch ($left) { case 7: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( 0, self::chrToInt($in[6]) << 16 ) ); case 6: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( 0, self::chrToInt($in[5]) << 8 ) ); case 5: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( 0, self::chrToInt($in[4]) ) ); case 4: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( self::chrToInt($in[3]) << 24, 0 ) ); case 3: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( self::chrToInt($in[2]) << 16, 0 ) ); case 2: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( self::chrToInt($in[1]) << 8, 0 ) ); case 1: $b = $b->orInt64( ParagonIE_Sodium_Core32_Int64::fromInts( self::chrToInt($in[0]), 0 ) ); case 0: break; } # v3 ^= b; $v[3] = $v[3]->xorInt64($b); # SIPROUND; # SIPROUND; $v = self::sipRound($v); $v = self::sipRound($v); # v0 ^= b; $v[0] = $v[0]->xorInt64($b); // Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation # v2 ^= 0xff; $v[2]->limbs[3] ^= 0xff; # SIPROUND; # SIPROUND; # SIPROUND; # SIPROUND; $v = self::sipRound($v); $v = self::sipRound($v); $v = self::sipRound($v); $v = self::sipRound($v); # b = v0 ^ v1 ^ v2 ^ v3; # STORE64_LE( out, b ); return $v[0] ->xorInt64($v[1]) ->xorInt64($v[2]) ->xorInt64($v[3]) ->toReverseString(); } } �������������������������������������������Core32/Poly1305/State.php���������������������������������������������������������������������������0000644�����������������00000037135�15021200076�0010630 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Poly1305_State', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Poly1305_State */ class ParagonIE_Sodium_Core32_Poly1305_State extends ParagonIE_Sodium_Core32_Util { /** * @var array<int, int> */ protected $buffer = array(); /** * @var bool */ protected $final = false; /** * @var array<int, ParagonIE_Sodium_Core32_Int32> */ public $h; /** * @var int */ protected $leftover = 0; /** * @var array<int, ParagonIE_Sodium_Core32_Int32> */ public $r; /** * @var array<int, ParagonIE_Sodium_Core32_Int64> */ public $pad; /** * ParagonIE_Sodium_Core32_Poly1305_State constructor. * * @internal You should not use this directly from another application * * @param string $key * @throws InvalidArgumentException * @throws SodiumException * @throws TypeError */ public function __construct($key = '') { if (self::strlen($key) < 32) { throw new InvalidArgumentException( 'Poly1305 requires a 32-byte key' ); } /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ $this->r = array( // st->r[0] = ... ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4)) ->setUnsignedInt(true) ->mask(0x3ffffff), // st->r[1] = ... ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 3, 4)) ->setUnsignedInt(true) ->shiftRight(2) ->mask(0x3ffff03), // st->r[2] = ... ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 6, 4)) ->setUnsignedInt(true) ->shiftRight(4) ->mask(0x3ffc0ff), // st->r[3] = ... ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 9, 4)) ->setUnsignedInt(true) ->shiftRight(6) ->mask(0x3f03fff), // st->r[4] = ... ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4)) ->setUnsignedInt(true) ->shiftRight(8) ->mask(0x00fffff) ); /* h = 0 */ $this->h = array( new ParagonIE_Sodium_Core32_Int32(array(0, 0), true), new ParagonIE_Sodium_Core32_Int32(array(0, 0), true), new ParagonIE_Sodium_Core32_Int32(array(0, 0), true), new ParagonIE_Sodium_Core32_Int32(array(0, 0), true), new ParagonIE_Sodium_Core32_Int32(array(0, 0), true) ); /* save pad for later */ $this->pad = array( ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4)) ->setUnsignedInt(true)->toInt64(), ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4)) ->setUnsignedInt(true)->toInt64(), ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4)) ->setUnsignedInt(true)->toInt64(), ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4)) ->setUnsignedInt(true)->toInt64(), ); $this->leftover = 0; $this->final = false; } /** * @internal You should not use this directly from another application * * @param string $message * @return self * @throws SodiumException * @throws TypeError */ public function update($message = '') { $bytes = self::strlen($message); /* handle leftover */ if ($this->leftover) { /** @var int $want */ $want = ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - $this->leftover; if ($want > $bytes) { $want = $bytes; } for ($i = 0; $i < $want; ++$i) { $mi = self::chrToInt($message[$i]); $this->buffer[$this->leftover + $i] = $mi; } // We snip off the leftmost bytes. $message = self::substr($message, $want); $bytes = self::strlen($message); $this->leftover += $want; if ($this->leftover < ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) { // We still don't have enough to run $this->blocks() return $this; } $this->blocks( self::intArrayToString($this->buffer), ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE ); $this->leftover = 0; } /* process full blocks */ if ($bytes >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) { /** @var int $want */ $want = $bytes & ~(ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - 1); if ($want >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) { /** @var string $block */ $block = self::substr($message, 0, $want); if (self::strlen($block) >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) { $this->blocks($block, $want); $message = self::substr($message, $want); $bytes = self::strlen($message); } } } /* store leftover */ if ($bytes) { for ($i = 0; $i < $bytes; ++$i) { $mi = self::chrToInt($message[$i]); $this->buffer[$this->leftover + $i] = $mi; } $this->leftover = (int) $this->leftover + $bytes; } return $this; } /** * @internal You should not use this directly from another application * * @param string $message * @param int $bytes * @return self * @throws SodiumException * @throws TypeError */ public function blocks($message, $bytes) { if (self::strlen($message) < 16) { $message = str_pad($message, 16, "\x00", STR_PAD_RIGHT); } $hibit = ParagonIE_Sodium_Core32_Int32::fromInt((int) ($this->final ? 0 : 1 << 24)); /* 1 << 128 */ $hibit->setUnsignedInt(true); $zero = new ParagonIE_Sodium_Core32_Int64(array(0, 0, 0, 0), true); /** * @var ParagonIE_Sodium_Core32_Int64 $d0 * @var ParagonIE_Sodium_Core32_Int64 $d1 * @var ParagonIE_Sodium_Core32_Int64 $d2 * @var ParagonIE_Sodium_Core32_Int64 $d3 * @var ParagonIE_Sodium_Core32_Int64 $d4 * @var ParagonIE_Sodium_Core32_Int64 $r0 * @var ParagonIE_Sodium_Core32_Int64 $r1 * @var ParagonIE_Sodium_Core32_Int64 $r2 * @var ParagonIE_Sodium_Core32_Int64 $r3 * @var ParagonIE_Sodium_Core32_Int64 $r4 * * @var ParagonIE_Sodium_Core32_Int32 $h0 * @var ParagonIE_Sodium_Core32_Int32 $h1 * @var ParagonIE_Sodium_Core32_Int32 $h2 * @var ParagonIE_Sodium_Core32_Int32 $h3 * @var ParagonIE_Sodium_Core32_Int32 $h4 */ $r0 = $this->r[0]->toInt64(); $r1 = $this->r[1]->toInt64(); $r2 = $this->r[2]->toInt64(); $r3 = $this->r[3]->toInt64(); $r4 = $this->r[4]->toInt64(); $s1 = $r1->toInt64()->mulInt(5, 3); $s2 = $r2->toInt64()->mulInt(5, 3); $s3 = $r3->toInt64()->mulInt(5, 3); $s4 = $r4->toInt64()->mulInt(5, 3); $h0 = $this->h[0]; $h1 = $this->h[1]; $h2 = $this->h[2]; $h3 = $this->h[3]; $h4 = $this->h[4]; while ($bytes >= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) { /* h += m[i] */ $h0 = $h0->addInt32( ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4)) ->mask(0x3ffffff) )->toInt64(); $h1 = $h1->addInt32( ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 3, 4)) ->shiftRight(2) ->mask(0x3ffffff) )->toInt64(); $h2 = $h2->addInt32( ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 6, 4)) ->shiftRight(4) ->mask(0x3ffffff) )->toInt64(); $h3 = $h3->addInt32( ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 9, 4)) ->shiftRight(6) ->mask(0x3ffffff) )->toInt64(); $h4 = $h4->addInt32( ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4)) ->shiftRight(8) ->orInt32($hibit) )->toInt64(); /* h *= r */ $d0 = $zero ->addInt64($h0->mulInt64($r0, 27)) ->addInt64($s4->mulInt64($h1, 27)) ->addInt64($s3->mulInt64($h2, 27)) ->addInt64($s2->mulInt64($h3, 27)) ->addInt64($s1->mulInt64($h4, 27)); $d1 = $zero ->addInt64($h0->mulInt64($r1, 27)) ->addInt64($h1->mulInt64($r0, 27)) ->addInt64($s4->mulInt64($h2, 27)) ->addInt64($s3->mulInt64($h3, 27)) ->addInt64($s2->mulInt64($h4, 27)); $d2 = $zero ->addInt64($h0->mulInt64($r2, 27)) ->addInt64($h1->mulInt64($r1, 27)) ->addInt64($h2->mulInt64($r0, 27)) ->addInt64($s4->mulInt64($h3, 27)) ->addInt64($s3->mulInt64($h4, 27)); $d3 = $zero ->addInt64($h0->mulInt64($r3, 27)) ->addInt64($h1->mulInt64($r2, 27)) ->addInt64($h2->mulInt64($r1, 27)) ->addInt64($h3->mulInt64($r0, 27)) ->addInt64($s4->mulInt64($h4, 27)); $d4 = $zero ->addInt64($h0->mulInt64($r4, 27)) ->addInt64($h1->mulInt64($r3, 27)) ->addInt64($h2->mulInt64($r2, 27)) ->addInt64($h3->mulInt64($r1, 27)) ->addInt64($h4->mulInt64($r0, 27)); /* (partial) h %= p */ $c = $d0->shiftRight(26); $h0 = $d0->toInt32()->mask(0x3ffffff); $d1 = $d1->addInt64($c); $c = $d1->shiftRight(26); $h1 = $d1->toInt32()->mask(0x3ffffff); $d2 = $d2->addInt64($c); $c = $d2->shiftRight(26); $h2 = $d2->toInt32()->mask(0x3ffffff); $d3 = $d3->addInt64($c); $c = $d3->shiftRight(26); $h3 = $d3->toInt32()->mask(0x3ffffff); $d4 = $d4->addInt64($c); $c = $d4->shiftRight(26); $h4 = $d4->toInt32()->mask(0x3ffffff); $h0 = $h0->addInt32($c->toInt32()->mulInt(5, 3)); $c = $h0->shiftRight(26); $h0 = $h0->mask(0x3ffffff); $h1 = $h1->addInt32($c); // Chop off the left 32 bytes. $message = self::substr( $message, ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE ); $bytes -= ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE; } /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */ $this->h = array($h0, $h1, $h2, $h3, $h4); return $this; } /** * @internal You should not use this directly from another application * * @return string * @throws SodiumException * @throws TypeError */ public function finish() { /* process the remaining block */ if ($this->leftover) { $i = $this->leftover; $this->buffer[$i++] = 1; for (; $i < ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE; ++$i) { $this->buffer[$i] = 0; } $this->final = true; $this->blocks( self::substr( self::intArrayToString($this->buffer), 0, ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE ), $b = ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE ); } /** * @var ParagonIE_Sodium_Core32_Int32 $f * @var ParagonIE_Sodium_Core32_Int32 $g0 * @var ParagonIE_Sodium_Core32_Int32 $g1 * @var ParagonIE_Sodium_Core32_Int32 $g2 * @var ParagonIE_Sodium_Core32_Int32 $g3 * @var ParagonIE_Sodium_Core32_Int32 $g4 * @var ParagonIE_Sodium_Core32_Int32 $h0 * @var ParagonIE_Sodium_Core32_Int32 $h1 * @var ParagonIE_Sodium_Core32_Int32 $h2 * @var ParagonIE_Sodium_Core32_Int32 $h3 * @var ParagonIE_Sodium_Core32_Int32 $h4 */ $h0 = $this->h[0]; $h1 = $this->h[1]; $h2 = $this->h[2]; $h3 = $this->h[3]; $h4 = $this->h[4]; $c = $h1->shiftRight(26); # $c = $h1 >> 26; $h1 = $h1->mask(0x3ffffff); # $h1 &= 0x3ffffff; $h2 = $h2->addInt32($c); # $h2 += $c; $c = $h2->shiftRight(26); # $c = $h2 >> 26; $h2 = $h2->mask(0x3ffffff); # $h2 &= 0x3ffffff; $h3 = $h3->addInt32($c); # $h3 += $c; $c = $h3->shiftRight(26); # $c = $h3 >> 26; $h3 = $h3->mask(0x3ffffff); # $h3 &= 0x3ffffff; $h4 = $h4->addInt32($c); # $h4 += $c; $c = $h4->shiftRight(26); # $c = $h4 >> 26; $h4 = $h4->mask(0x3ffffff); # $h4 &= 0x3ffffff; $h0 = $h0->addInt32($c->mulInt(5, 3)); # $h0 += self::mul($c, 5); $c = $h0->shiftRight(26); # $c = $h0 >> 26; $h0 = $h0->mask(0x3ffffff); # $h0 &= 0x3ffffff; $h1 = $h1->addInt32($c); # $h1 += $c; /* compute h + -p */ $g0 = $h0->addInt(5); $c = $g0->shiftRight(26); $g0 = $g0->mask(0x3ffffff); $g1 = $h1->addInt32($c); $c = $g1->shiftRight(26); $g1 = $g1->mask(0x3ffffff); $g2 = $h2->addInt32($c); $c = $g2->shiftRight(26); $g2 = $g2->mask(0x3ffffff); $g3 = $h3->addInt32($c); $c = $g3->shiftRight(26); $g3 = $g3->mask(0x3ffffff); $g4 = $h4->addInt32($c)->subInt(1 << 26); # $mask = ($g4 >> 31) - 1; /* select h if h < p, or h + -p if h >= p */ $mask = (int) (($g4->toInt() >> 31) + 1); $g0 = $g0->mask($mask); $g1 = $g1->mask($mask); $g2 = $g2->mask($mask); $g3 = $g3->mask($mask); $g4 = $g4->mask($mask); /** @var int $mask */ $mask = ~$mask; $h0 = $h0->mask($mask)->orInt32($g0); $h1 = $h1->mask($mask)->orInt32($g1); $h2 = $h2->mask($mask)->orInt32($g2); $h3 = $h3->mask($mask)->orInt32($g3); $h4 = $h4->mask($mask)->orInt32($g4); /* h = h % (2^128) */ $h0 = $h0->orInt32($h1->shiftLeft(26)); $h1 = $h1->shiftRight(6)->orInt32($h2->shiftLeft(20)); $h2 = $h2->shiftRight(12)->orInt32($h3->shiftLeft(14)); $h3 = $h3->shiftRight(18)->orInt32($h4->shiftLeft(8)); /* mac = (h + pad) % (2^128) */ $f = $h0->toInt64()->addInt64($this->pad[0]); $h0 = $f->toInt32(); $f = $h1->toInt64()->addInt64($this->pad[1])->addInt($h0->overflow); $h1 = $f->toInt32(); $f = $h2->toInt64()->addInt64($this->pad[2])->addInt($h1->overflow); $h2 = $f->toInt32(); $f = $h3->toInt64()->addInt64($this->pad[3])->addInt($h2->overflow); $h3 = $f->toInt32(); return $h0->toReverseString() . $h1->toReverseString() . $h2->toReverseString() . $h3->toReverseString(); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519.php�������������������������������������������������������������������������������0000644�����������������00000403556�15021200076�0010012 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519 * * Implements Curve25519 core functions * * Based on the ref10 curve25519 code provided by libsodium * * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c */ abstract class ParagonIE_Sodium_Core32_Curve25519 extends ParagonIE_Sodium_Core32_Curve25519_H { /** * Get a field element of size 10 with a value of 0 * * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError */ public static function fe_0() { return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32() ) ); } /** * Get a field element of size 10 with a value of 1 * * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError */ public static function fe_1() { return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt(1), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32(), new ParagonIE_Sodium_Core32_Int32() ) ); } /** * Add two field elements. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedMethodCall */ public static function fe_add( ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g ) { $arr = array(); for ($i = 0; $i < 10; ++$i) { $arr[$i] = $f[$i]->addInt32($g[$i]); } /** @var array<int, ParagonIE_Sodium_Core32_Int32> $arr */ return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($arr); } /** * Constant-time conditional move. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g * @param int $b * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedMethodCall */ public static function fe_cmov( ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g, $b = 0 ) { /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */ $h = array(); for ($i = 0; $i < 10; ++$i) { if (!($f[$i] instanceof ParagonIE_Sodium_Core32_Int32)) { throw new TypeError('Expected Int32'); } if (!($g[$i] instanceof ParagonIE_Sodium_Core32_Int32)) { throw new TypeError('Expected Int32'); } $h[$i] = $f[$i]->xorInt32( $f[$i]->xorInt32($g[$i])->mask($b) ); } /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */ return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h); } /** * Create a copy of a field element. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return ParagonIE_Sodium_Core32_Curve25519_Fe */ public static function fe_copy(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { $h = clone $f; return $h; } /** * Give: 32-byte string. * Receive: A field element object to use for internal calculations. * * @internal You should not use this directly from another application * * @param string $s * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws RangeException * @throws SodiumException * @throws TypeError * @psalm-suppress MixedMethodCall */ public static function fe_frombytes($s) { if (self::strlen($s) !== 32) { throw new RangeException('Expected a 32-byte string.'); } /** @var ParagonIE_Sodium_Core32_Int32 $h0 */ $h0 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_4($s) ); /** @var ParagonIE_Sodium_Core32_Int32 $h1 */ $h1 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 4, 3)) << 6 ); /** @var ParagonIE_Sodium_Core32_Int32 $h2 */ $h2 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 7, 3)) << 5 ); /** @var ParagonIE_Sodium_Core32_Int32 $h3 */ $h3 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 10, 3)) << 3 ); /** @var ParagonIE_Sodium_Core32_Int32 $h4 */ $h4 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 13, 3)) << 2 ); /** @var ParagonIE_Sodium_Core32_Int32 $h5 */ $h5 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_4(self::substr($s, 16, 4)) ); /** @var ParagonIE_Sodium_Core32_Int32 $h6 */ $h6 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 20, 3)) << 7 ); /** @var ParagonIE_Sodium_Core32_Int32 $h7 */ $h7 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 23, 3)) << 5 ); /** @var ParagonIE_Sodium_Core32_Int32 $h8 */ $h8 = ParagonIE_Sodium_Core32_Int32::fromInt( self::load_3(self::substr($s, 26, 3)) << 4 ); /** @var ParagonIE_Sodium_Core32_Int32 $h9 */ $h9 = ParagonIE_Sodium_Core32_Int32::fromInt( (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2 ); $carry9 = $h9->addInt(1 << 24)->shiftRight(25); $h0 = $h0->addInt32($carry9->mulInt(19, 5)); $h9 = $h9->subInt32($carry9->shiftLeft(25)); $carry1 = $h1->addInt(1 << 24)->shiftRight(25); $h2 = $h2->addInt32($carry1); $h1 = $h1->subInt32($carry1->shiftLeft(25)); $carry3 = $h3->addInt(1 << 24)->shiftRight(25); $h4 = $h4->addInt32($carry3); $h3 = $h3->subInt32($carry3->shiftLeft(25)); $carry5 = $h5->addInt(1 << 24)->shiftRight(25); $h6 = $h6->addInt32($carry5); $h5 = $h5->subInt32($carry5->shiftLeft(25)); $carry7 = $h7->addInt(1 << 24)->shiftRight(25); $h8 = $h8->addInt32($carry7); $h7 = $h7->subInt32($carry7->shiftLeft(25)); $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt32($carry0); $h0 = $h0->subInt32($carry0->shiftLeft(26)); $carry2 = $h2->addInt(1 << 25)->shiftRight(26); $h3 = $h3->addInt32($carry2); $h2 = $h2->subInt32($carry2->shiftLeft(26)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt32($carry4); $h4 = $h4->subInt32($carry4->shiftLeft(26)); $carry6 = $h6->addInt(1 << 25)->shiftRight(26); $h7 = $h7->addInt32($carry6); $h6 = $h6->subInt32($carry6->shiftLeft(26)); $carry8 = $h8->addInt(1 << 25)->shiftRight(26); $h9 = $h9->addInt32($carry8); $h8 = $h8->subInt32($carry8->shiftLeft(26)); return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array($h0, $h1, $h2,$h3, $h4, $h5, $h6, $h7, $h8, $h9) ); } /** * Convert a field element to a byte string. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $h * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedMethodCall */ public static function fe_tobytes(ParagonIE_Sodium_Core32_Curve25519_Fe $h) { /** * @var ParagonIE_Sodium_Core32_Int64[] $f * @var ParagonIE_Sodium_Core32_Int64 $q */ $f = array(); for ($i = 0; $i < 10; ++$i) { $f[$i] = $h[$i]->toInt64(); } $q = $f[9]->mulInt(19, 5)->addInt(1 << 14)->shiftRight(25) ->addInt64($f[0])->shiftRight(26) ->addInt64($f[1])->shiftRight(25) ->addInt64($f[2])->shiftRight(26) ->addInt64($f[3])->shiftRight(25) ->addInt64($f[4])->shiftRight(26) ->addInt64($f[5])->shiftRight(25) ->addInt64($f[6])->shiftRight(26) ->addInt64($f[7])->shiftRight(25) ->addInt64($f[8])->shiftRight(26) ->addInt64($f[9])->shiftRight(25); $f[0] = $f[0]->addInt64($q->mulInt(19, 5)); $carry0 = $f[0]->shiftRight(26); $f[1] = $f[1]->addInt64($carry0); $f[0] = $f[0]->subInt64($carry0->shiftLeft(26)); $carry1 = $f[1]->shiftRight(25); $f[2] = $f[2]->addInt64($carry1); $f[1] = $f[1]->subInt64($carry1->shiftLeft(25)); $carry2 = $f[2]->shiftRight(26); $f[3] = $f[3]->addInt64($carry2); $f[2] = $f[2]->subInt64($carry2->shiftLeft(26)); $carry3 = $f[3]->shiftRight(25); $f[4] = $f[4]->addInt64($carry3); $f[3] = $f[3]->subInt64($carry3->shiftLeft(25)); $carry4 = $f[4]->shiftRight(26); $f[5] = $f[5]->addInt64($carry4); $f[4] = $f[4]->subInt64($carry4->shiftLeft(26)); $carry5 = $f[5]->shiftRight(25); $f[6] = $f[6]->addInt64($carry5); $f[5] = $f[5]->subInt64($carry5->shiftLeft(25)); $carry6 = $f[6]->shiftRight(26); $f[7] = $f[7]->addInt64($carry6); $f[6] = $f[6]->subInt64($carry6->shiftLeft(26)); $carry7 = $f[7]->shiftRight(25); $f[8] = $f[8]->addInt64($carry7); $f[7] = $f[7]->subInt64($carry7->shiftLeft(25)); $carry8 = $f[8]->shiftRight(26); $f[9] = $f[9]->addInt64($carry8); $f[8] = $f[8]->subInt64($carry8->shiftLeft(26)); $carry9 = $f[9]->shiftRight(25); $f[9] = $f[9]->subInt64($carry9->shiftLeft(25)); $h0 = $f[0]->toInt32()->toInt(); $h1 = $f[1]->toInt32()->toInt(); $h2 = $f[2]->toInt32()->toInt(); $h3 = $f[3]->toInt32()->toInt(); $h4 = $f[4]->toInt32()->toInt(); $h5 = $f[5]->toInt32()->toInt(); $h6 = $f[6]->toInt32()->toInt(); $h7 = $f[7]->toInt32()->toInt(); $h8 = $f[8]->toInt32()->toInt(); $h9 = $f[9]->toInt32()->toInt(); /** * @var array<int, int> */ $s = array( (int) (($h0 >> 0) & 0xff), (int) (($h0 >> 8) & 0xff), (int) (($h0 >> 16) & 0xff), (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff), (int) (($h1 >> 6) & 0xff), (int) (($h1 >> 14) & 0xff), (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff), (int) (($h2 >> 5) & 0xff), (int) (($h2 >> 13) & 0xff), (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff), (int) (($h3 >> 3) & 0xff), (int) (($h3 >> 11) & 0xff), (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff), (int) (($h4 >> 2) & 0xff), (int) (($h4 >> 10) & 0xff), (int) (($h4 >> 18) & 0xff), (int) (($h5 >> 0) & 0xff), (int) (($h5 >> 8) & 0xff), (int) (($h5 >> 16) & 0xff), (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff), (int) (($h6 >> 7) & 0xff), (int) (($h6 >> 15) & 0xff), (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff), (int) (($h7 >> 5) & 0xff), (int) (($h7 >> 13) & 0xff), (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff), (int) (($h8 >> 4) & 0xff), (int) (($h8 >> 12) & 0xff), (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff), (int) (($h9 >> 2) & 0xff), (int) (($h9 >> 10) & 0xff), (int) (($h9 >> 18) & 0xff) ); return self::intArrayToString($s); } /** * Is a field element negative? (1 = yes, 0 = no. Used in calculations.) * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return int * @throws SodiumException * @throws TypeError */ public static function fe_isnegative(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { $str = self::fe_tobytes($f); return (int) (self::chrToInt($str[0]) & 1); } /** * Returns 0 if this field element results in all NUL bytes. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return bool * @throws SodiumException * @throws TypeError */ public static function fe_isnonzero(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { static $zero; if ($zero === null) { $zero = str_repeat("\x00", 32); } $str = self::fe_tobytes($f); /** @var string $zero */ return !self::verify_32($str, $zero); } /** * Multiply two field elements * * h = f * g * * @internal You should not use this directly from another application * * @security Is multiplication a source of timing leaks? If so, can we do * anything to prevent that from happening? * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError */ public static function fe_mul( ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g ) { /** * @var ParagonIE_Sodium_Core32_Int32[] $f * @var ParagonIE_Sodium_Core32_Int32[] $g * @var ParagonIE_Sodium_Core32_Int64 $f0 * @var ParagonIE_Sodium_Core32_Int64 $f1 * @var ParagonIE_Sodium_Core32_Int64 $f2 * @var ParagonIE_Sodium_Core32_Int64 $f3 * @var ParagonIE_Sodium_Core32_Int64 $f4 * @var ParagonIE_Sodium_Core32_Int64 $f5 * @var ParagonIE_Sodium_Core32_Int64 $f6 * @var ParagonIE_Sodium_Core32_Int64 $f7 * @var ParagonIE_Sodium_Core32_Int64 $f8 * @var ParagonIE_Sodium_Core32_Int64 $f9 * @var ParagonIE_Sodium_Core32_Int64 $g0 * @var ParagonIE_Sodium_Core32_Int64 $g1 * @var ParagonIE_Sodium_Core32_Int64 $g2 * @var ParagonIE_Sodium_Core32_Int64 $g3 * @var ParagonIE_Sodium_Core32_Int64 $g4 * @var ParagonIE_Sodium_Core32_Int64 $g5 * @var ParagonIE_Sodium_Core32_Int64 $g6 * @var ParagonIE_Sodium_Core32_Int64 $g7 * @var ParagonIE_Sodium_Core32_Int64 $g8 * @var ParagonIE_Sodium_Core32_Int64 $g9 */ $f0 = $f[0]->toInt64(); $f1 = $f[1]->toInt64(); $f2 = $f[2]->toInt64(); $f3 = $f[3]->toInt64(); $f4 = $f[4]->toInt64(); $f5 = $f[5]->toInt64(); $f6 = $f[6]->toInt64(); $f7 = $f[7]->toInt64(); $f8 = $f[8]->toInt64(); $f9 = $f[9]->toInt64(); $g0 = $g[0]->toInt64(); $g1 = $g[1]->toInt64(); $g2 = $g[2]->toInt64(); $g3 = $g[3]->toInt64(); $g4 = $g[4]->toInt64(); $g5 = $g[5]->toInt64(); $g6 = $g[6]->toInt64(); $g7 = $g[7]->toInt64(); $g8 = $g[8]->toInt64(); $g9 = $g[9]->toInt64(); $g1_19 = $g1->mulInt(19, 5); /* 2^4 <= 19 <= 2^5, but we only want 5 bits */ $g2_19 = $g2->mulInt(19, 5); $g3_19 = $g3->mulInt(19, 5); $g4_19 = $g4->mulInt(19, 5); $g5_19 = $g5->mulInt(19, 5); $g6_19 = $g6->mulInt(19, 5); $g7_19 = $g7->mulInt(19, 5); $g8_19 = $g8->mulInt(19, 5); $g9_19 = $g9->mulInt(19, 5); $f1_2 = $f1->shiftLeft(1); $f3_2 = $f3->shiftLeft(1); $f5_2 = $f5->shiftLeft(1); $f7_2 = $f7->shiftLeft(1); $f9_2 = $f9->shiftLeft(1); $f0g0 = $f0->mulInt64($g0, 27); $f0g1 = $f0->mulInt64($g1, 27); $f0g2 = $f0->mulInt64($g2, 27); $f0g3 = $f0->mulInt64($g3, 27); $f0g4 = $f0->mulInt64($g4, 27); $f0g5 = $f0->mulInt64($g5, 27); $f0g6 = $f0->mulInt64($g6, 27); $f0g7 = $f0->mulInt64($g7, 27); $f0g8 = $f0->mulInt64($g8, 27); $f0g9 = $f0->mulInt64($g9, 27); $f1g0 = $f1->mulInt64($g0, 27); $f1g1_2 = $f1_2->mulInt64($g1, 27); $f1g2 = $f1->mulInt64($g2, 27); $f1g3_2 = $f1_2->mulInt64($g3, 27); $f1g4 = $f1->mulInt64($g4, 30); $f1g5_2 = $f1_2->mulInt64($g5, 30); $f1g6 = $f1->mulInt64($g6, 30); $f1g7_2 = $f1_2->mulInt64($g7, 30); $f1g8 = $f1->mulInt64($g8, 30); $f1g9_38 = $g9_19->mulInt64($f1_2, 30); $f2g0 = $f2->mulInt64($g0, 30); $f2g1 = $f2->mulInt64($g1, 29); $f2g2 = $f2->mulInt64($g2, 30); $f2g3 = $f2->mulInt64($g3, 29); $f2g4 = $f2->mulInt64($g4, 30); $f2g5 = $f2->mulInt64($g5, 29); $f2g6 = $f2->mulInt64($g6, 30); $f2g7 = $f2->mulInt64($g7, 29); $f2g8_19 = $g8_19->mulInt64($f2, 30); $f2g9_19 = $g9_19->mulInt64($f2, 30); $f3g0 = $f3->mulInt64($g0, 30); $f3g1_2 = $f3_2->mulInt64($g1, 30); $f3g2 = $f3->mulInt64($g2, 30); $f3g3_2 = $f3_2->mulInt64($g3, 30); $f3g4 = $f3->mulInt64($g4, 30); $f3g5_2 = $f3_2->mulInt64($g5, 30); $f3g6 = $f3->mulInt64($g6, 30); $f3g7_38 = $g7_19->mulInt64($f3_2, 30); $f3g8_19 = $g8_19->mulInt64($f3, 30); $f3g9_38 = $g9_19->mulInt64($f3_2, 30); $f4g0 = $f4->mulInt64($g0, 30); $f4g1 = $f4->mulInt64($g1, 30); $f4g2 = $f4->mulInt64($g2, 30); $f4g3 = $f4->mulInt64($g3, 30); $f4g4 = $f4->mulInt64($g4, 30); $f4g5 = $f4->mulInt64($g5, 30); $f4g6_19 = $g6_19->mulInt64($f4, 30); $f4g7_19 = $g7_19->mulInt64($f4, 30); $f4g8_19 = $g8_19->mulInt64($f4, 30); $f4g9_19 = $g9_19->mulInt64($f4, 30); $f5g0 = $f5->mulInt64($g0, 30); $f5g1_2 = $f5_2->mulInt64($g1, 30); $f5g2 = $f5->mulInt64($g2, 30); $f5g3_2 = $f5_2->mulInt64($g3, 30); $f5g4 = $f5->mulInt64($g4, 30); $f5g5_38 = $g5_19->mulInt64($f5_2, 30); $f5g6_19 = $g6_19->mulInt64($f5, 30); $f5g7_38 = $g7_19->mulInt64($f5_2, 30); $f5g8_19 = $g8_19->mulInt64($f5, 30); $f5g9_38 = $g9_19->mulInt64($f5_2, 30); $f6g0 = $f6->mulInt64($g0, 30); $f6g1 = $f6->mulInt64($g1, 30); $f6g2 = $f6->mulInt64($g2, 30); $f6g3 = $f6->mulInt64($g3, 30); $f6g4_19 = $g4_19->mulInt64($f6, 30); $f6g5_19 = $g5_19->mulInt64($f6, 30); $f6g6_19 = $g6_19->mulInt64($f6, 30); $f6g7_19 = $g7_19->mulInt64($f6, 30); $f6g8_19 = $g8_19->mulInt64($f6, 30); $f6g9_19 = $g9_19->mulInt64($f6, 30); $f7g0 = $f7->mulInt64($g0, 30); $f7g1_2 = $g1->mulInt64($f7_2, 30); $f7g2 = $f7->mulInt64($g2, 30); $f7g3_38 = $g3_19->mulInt64($f7_2, 30); $f7g4_19 = $g4_19->mulInt64($f7, 30); $f7g5_38 = $g5_19->mulInt64($f7_2, 30); $f7g6_19 = $g6_19->mulInt64($f7, 30); $f7g7_38 = $g7_19->mulInt64($f7_2, 30); $f7g8_19 = $g8_19->mulInt64($f7, 30); $f7g9_38 = $g9_19->mulInt64($f7_2, 30); $f8g0 = $f8->mulInt64($g0, 30); $f8g1 = $f8->mulInt64($g1, 29); $f8g2_19 = $g2_19->mulInt64($f8, 30); $f8g3_19 = $g3_19->mulInt64($f8, 30); $f8g4_19 = $g4_19->mulInt64($f8, 30); $f8g5_19 = $g5_19->mulInt64($f8, 30); $f8g6_19 = $g6_19->mulInt64($f8, 30); $f8g7_19 = $g7_19->mulInt64($f8, 30); $f8g8_19 = $g8_19->mulInt64($f8, 30); $f8g9_19 = $g9_19->mulInt64($f8, 30); $f9g0 = $f9->mulInt64($g0, 30); $f9g1_38 = $g1_19->mulInt64($f9_2, 30); $f9g2_19 = $g2_19->mulInt64($f9, 30); $f9g3_38 = $g3_19->mulInt64($f9_2, 30); $f9g4_19 = $g4_19->mulInt64($f9, 30); $f9g5_38 = $g5_19->mulInt64($f9_2, 30); $f9g6_19 = $g6_19->mulInt64($f9, 30); $f9g7_38 = $g7_19->mulInt64($f9_2, 30); $f9g8_19 = $g8_19->mulInt64($f9, 30); $f9g9_38 = $g9_19->mulInt64($f9_2, 30); // $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38; $h0 = $f0g0->addInt64($f1g9_38)->addInt64($f2g8_19)->addInt64($f3g7_38) ->addInt64($f4g6_19)->addInt64($f5g5_38)->addInt64($f6g4_19) ->addInt64($f7g3_38)->addInt64($f8g2_19)->addInt64($f9g1_38); // $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19; $h1 = $f0g1->addInt64($f1g0)->addInt64($f2g9_19)->addInt64($f3g8_19) ->addInt64($f4g7_19)->addInt64($f5g6_19)->addInt64($f6g5_19) ->addInt64($f7g4_19)->addInt64($f8g3_19)->addInt64($f9g2_19); // $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38; $h2 = $f0g2->addInt64($f1g1_2)->addInt64($f2g0)->addInt64($f3g9_38) ->addInt64($f4g8_19)->addInt64($f5g7_38)->addInt64($f6g6_19) ->addInt64($f7g5_38)->addInt64($f8g4_19)->addInt64($f9g3_38); // $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19; $h3 = $f0g3->addInt64($f1g2)->addInt64($f2g1)->addInt64($f3g0) ->addInt64($f4g9_19)->addInt64($f5g8_19)->addInt64($f6g7_19) ->addInt64($f7g6_19)->addInt64($f8g5_19)->addInt64($f9g4_19); // $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38; $h4 = $f0g4->addInt64($f1g3_2)->addInt64($f2g2)->addInt64($f3g1_2) ->addInt64($f4g0)->addInt64($f5g9_38)->addInt64($f6g8_19) ->addInt64($f7g7_38)->addInt64($f8g6_19)->addInt64($f9g5_38); // $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19; $h5 = $f0g5->addInt64($f1g4)->addInt64($f2g3)->addInt64($f3g2) ->addInt64($f4g1)->addInt64($f5g0)->addInt64($f6g9_19) ->addInt64($f7g8_19)->addInt64($f8g7_19)->addInt64($f9g6_19); // $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38; $h6 = $f0g6->addInt64($f1g5_2)->addInt64($f2g4)->addInt64($f3g3_2) ->addInt64($f4g2)->addInt64($f5g1_2)->addInt64($f6g0) ->addInt64($f7g9_38)->addInt64($f8g8_19)->addInt64($f9g7_38); // $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19; $h7 = $f0g7->addInt64($f1g6)->addInt64($f2g5)->addInt64($f3g4) ->addInt64($f4g3)->addInt64($f5g2)->addInt64($f6g1) ->addInt64($f7g0)->addInt64($f8g9_19)->addInt64($f9g8_19); // $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38; $h8 = $f0g8->addInt64($f1g7_2)->addInt64($f2g6)->addInt64($f3g5_2) ->addInt64($f4g4)->addInt64($f5g3_2)->addInt64($f6g2) ->addInt64($f7g1_2)->addInt64($f8g0)->addInt64($f9g9_38); // $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ; $h9 = $f0g9->addInt64($f1g8)->addInt64($f2g7)->addInt64($f3g6) ->addInt64($f4g5)->addInt64($f5g4)->addInt64($f6g3) ->addInt64($f7g2)->addInt64($f8g1)->addInt64($f9g0); /** * @var ParagonIE_Sodium_Core32_Int64 $h0 * @var ParagonIE_Sodium_Core32_Int64 $h1 * @var ParagonIE_Sodium_Core32_Int64 $h2 * @var ParagonIE_Sodium_Core32_Int64 $h3 * @var ParagonIE_Sodium_Core32_Int64 $h4 * @var ParagonIE_Sodium_Core32_Int64 $h5 * @var ParagonIE_Sodium_Core32_Int64 $h6 * @var ParagonIE_Sodium_Core32_Int64 $h7 * @var ParagonIE_Sodium_Core32_Int64 $h8 * @var ParagonIE_Sodium_Core32_Int64 $h9 * @var ParagonIE_Sodium_Core32_Int64 $carry0 * @var ParagonIE_Sodium_Core32_Int64 $carry1 * @var ParagonIE_Sodium_Core32_Int64 $carry2 * @var ParagonIE_Sodium_Core32_Int64 $carry3 * @var ParagonIE_Sodium_Core32_Int64 $carry4 * @var ParagonIE_Sodium_Core32_Int64 $carry5 * @var ParagonIE_Sodium_Core32_Int64 $carry6 * @var ParagonIE_Sodium_Core32_Int64 $carry7 * @var ParagonIE_Sodium_Core32_Int64 $carry8 * @var ParagonIE_Sodium_Core32_Int64 $carry9 */ $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt64($carry0); $h0 = $h0->subInt64($carry0->shiftLeft(26)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt64($carry4); $h4 = $h4->subInt64($carry4->shiftLeft(26)); $carry1 = $h1->addInt(1 << 24)->shiftRight(25); $h2 = $h2->addInt64($carry1); $h1 = $h1->subInt64($carry1->shiftLeft(25)); $carry5 = $h5->addInt(1 << 24)->shiftRight(25); $h6 = $h6->addInt64($carry5); $h5 = $h5->subInt64($carry5->shiftLeft(25)); $carry2 = $h2->addInt(1 << 25)->shiftRight(26); $h3 = $h3->addInt64($carry2); $h2 = $h2->subInt64($carry2->shiftLeft(26)); $carry6 = $h6->addInt(1 << 25)->shiftRight(26); $h7 = $h7->addInt64($carry6); $h6 = $h6->subInt64($carry6->shiftLeft(26)); $carry3 = $h3->addInt(1 << 24)->shiftRight(25); $h4 = $h4->addInt64($carry3); $h3 = $h3->subInt64($carry3->shiftLeft(25)); $carry7 = $h7->addInt(1 << 24)->shiftRight(25); $h8 = $h8->addInt64($carry7); $h7 = $h7->subInt64($carry7->shiftLeft(25)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt64($carry4); $h4 = $h4->subInt64($carry4->shiftLeft(26)); $carry8 = $h8->addInt(1 << 25)->shiftRight(26); $h9 = $h9->addInt64($carry8); $h8 = $h8->subInt64($carry8->shiftLeft(26)); $carry9 = $h9->addInt(1 << 24)->shiftRight(25); $h0 = $h0->addInt64($carry9->mulInt(19, 5)); $h9 = $h9->subInt64($carry9->shiftLeft(25)); $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt64($carry0); $h0 = $h0->subInt64($carry0->shiftLeft(26)); return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( $h0->toInt32(), $h1->toInt32(), $h2->toInt32(), $h3->toInt32(), $h4->toInt32(), $h5->toInt32(), $h6->toInt32(), $h7->toInt32(), $h8->toInt32(), $h9->toInt32() ) ); } /** * Get the negative values for each piece of the field element. * * h = -f * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @psalm-suppress MixedAssignment * @psalm-suppress MixedMethodCall */ public static function fe_neg(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { $h = new ParagonIE_Sodium_Core32_Curve25519_Fe(); for ($i = 0; $i < 10; ++$i) { $h[$i] = $h[$i]->subInt32($f[$i]); } return $h; } /** * Square a field element * * h = f * f * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError * @psalm-suppress MixedMethodCall */ public static function fe_sq(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { $f0 = $f[0]->toInt64(); $f1 = $f[1]->toInt64(); $f2 = $f[2]->toInt64(); $f3 = $f[3]->toInt64(); $f4 = $f[4]->toInt64(); $f5 = $f[5]->toInt64(); $f6 = $f[6]->toInt64(); $f7 = $f[7]->toInt64(); $f8 = $f[8]->toInt64(); $f9 = $f[9]->toInt64(); $f0_2 = $f0->shiftLeft(1); $f1_2 = $f1->shiftLeft(1); $f2_2 = $f2->shiftLeft(1); $f3_2 = $f3->shiftLeft(1); $f4_2 = $f4->shiftLeft(1); $f5_2 = $f5->shiftLeft(1); $f6_2 = $f6->shiftLeft(1); $f7_2 = $f7->shiftLeft(1); $f5_38 = $f5->mulInt(38, 6); $f6_19 = $f6->mulInt(19, 5); $f7_38 = $f7->mulInt(38, 6); $f8_19 = $f8->mulInt(19, 5); $f9_38 = $f9->mulInt(38, 6); $f0f0 = $f0->mulInt64($f0, 28); $f0f1_2 = $f0_2->mulInt64($f1, 28); $f0f2_2 = $f0_2->mulInt64($f2, 28); $f0f3_2 = $f0_2->mulInt64($f3, 28); $f0f4_2 = $f0_2->mulInt64($f4, 28); $f0f5_2 = $f0_2->mulInt64($f5, 28); $f0f6_2 = $f0_2->mulInt64($f6, 28); $f0f7_2 = $f0_2->mulInt64($f7, 28); $f0f8_2 = $f0_2->mulInt64($f8, 28); $f0f9_2 = $f0_2->mulInt64($f9, 28); $f1f1_2 = $f1_2->mulInt64($f1, 28); $f1f2_2 = $f1_2->mulInt64($f2, 28); $f1f3_4 = $f1_2->mulInt64($f3_2, 28); $f1f4_2 = $f1_2->mulInt64($f4, 28); $f1f5_4 = $f1_2->mulInt64($f5_2, 30); $f1f6_2 = $f1_2->mulInt64($f6, 28); $f1f7_4 = $f1_2->mulInt64($f7_2, 28); $f1f8_2 = $f1_2->mulInt64($f8, 28); $f1f9_76 = $f9_38->mulInt64($f1_2, 30); $f2f2 = $f2->mulInt64($f2, 28); $f2f3_2 = $f2_2->mulInt64($f3, 28); $f2f4_2 = $f2_2->mulInt64($f4, 28); $f2f5_2 = $f2_2->mulInt64($f5, 28); $f2f6_2 = $f2_2->mulInt64($f6, 28); $f2f7_2 = $f2_2->mulInt64($f7, 28); $f2f8_38 = $f8_19->mulInt64($f2_2, 30); $f2f9_38 = $f9_38->mulInt64($f2, 30); $f3f3_2 = $f3_2->mulInt64($f3, 28); $f3f4_2 = $f3_2->mulInt64($f4, 28); $f3f5_4 = $f3_2->mulInt64($f5_2, 30); $f3f6_2 = $f3_2->mulInt64($f6, 28); $f3f7_76 = $f7_38->mulInt64($f3_2, 30); $f3f8_38 = $f8_19->mulInt64($f3_2, 30); $f3f9_76 = $f9_38->mulInt64($f3_2, 30); $f4f4 = $f4->mulInt64($f4, 28); $f4f5_2 = $f4_2->mulInt64($f5, 28); $f4f6_38 = $f6_19->mulInt64($f4_2, 30); $f4f7_38 = $f7_38->mulInt64($f4, 30); $f4f8_38 = $f8_19->mulInt64($f4_2, 30); $f4f9_38 = $f9_38->mulInt64($f4, 30); $f5f5_38 = $f5_38->mulInt64($f5, 30); $f5f6_38 = $f6_19->mulInt64($f5_2, 30); $f5f7_76 = $f7_38->mulInt64($f5_2, 30); $f5f8_38 = $f8_19->mulInt64($f5_2, 30); $f5f9_76 = $f9_38->mulInt64($f5_2, 30); $f6f6_19 = $f6_19->mulInt64($f6, 30); $f6f7_38 = $f7_38->mulInt64($f6, 30); $f6f8_38 = $f8_19->mulInt64($f6_2, 30); $f6f9_38 = $f9_38->mulInt64($f6, 30); $f7f7_38 = $f7_38->mulInt64($f7, 28); $f7f8_38 = $f8_19->mulInt64($f7_2, 30); $f7f9_76 = $f9_38->mulInt64($f7_2, 30); $f8f8_19 = $f8_19->mulInt64($f8, 30); $f8f9_38 = $f9_38->mulInt64($f8, 30); $f9f9_38 = $f9_38->mulInt64($f9, 28); $h0 = $f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38); $h1 = $f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38); $h2 = $f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19); $h3 = $f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38); $h4 = $f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38); $h5 = $f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38); $h6 = $f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19); $h7 = $f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38); $h8 = $f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38); $h9 = $f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2); /** * @var ParagonIE_Sodium_Core32_Int64 $h0 * @var ParagonIE_Sodium_Core32_Int64 $h1 * @var ParagonIE_Sodium_Core32_Int64 $h2 * @var ParagonIE_Sodium_Core32_Int64 $h3 * @var ParagonIE_Sodium_Core32_Int64 $h4 * @var ParagonIE_Sodium_Core32_Int64 $h5 * @var ParagonIE_Sodium_Core32_Int64 $h6 * @var ParagonIE_Sodium_Core32_Int64 $h7 * @var ParagonIE_Sodium_Core32_Int64 $h8 * @var ParagonIE_Sodium_Core32_Int64 $h9 */ $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt64($carry0); $h0 = $h0->subInt64($carry0->shiftLeft(26)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt64($carry4); $h4 = $h4->subInt64($carry4->shiftLeft(26)); $carry1 = $h1->addInt(1 << 24)->shiftRight(25); $h2 = $h2->addInt64($carry1); $h1 = $h1->subInt64($carry1->shiftLeft(25)); $carry5 = $h5->addInt(1 << 24)->shiftRight(25); $h6 = $h6->addInt64($carry5); $h5 = $h5->subInt64($carry5->shiftLeft(25)); $carry2 = $h2->addInt(1 << 25)->shiftRight(26); $h3 = $h3->addInt64($carry2); $h2 = $h2->subInt64($carry2->shiftLeft(26)); $carry6 = $h6->addInt(1 << 25)->shiftRight(26); $h7 = $h7->addInt64($carry6); $h6 = $h6->subInt64($carry6->shiftLeft(26)); $carry3 = $h3->addInt(1 << 24)->shiftRight(25); $h4 = $h4->addInt64($carry3); $h3 = $h3->subInt64($carry3->shiftLeft(25)); $carry7 = $h7->addInt(1 << 24)->shiftRight(25); $h8 = $h8->addInt64($carry7); $h7 = $h7->subInt64($carry7->shiftLeft(25)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt64($carry4); $h4 = $h4->subInt64($carry4->shiftLeft(26)); $carry8 = $h8->addInt(1 << 25)->shiftRight(26); $h9 = $h9->addInt64($carry8); $h8 = $h8->subInt64($carry8->shiftLeft(26)); $carry9 = $h9->addInt(1 << 24)->shiftRight(25); $h0 = $h0->addInt64($carry9->mulInt(19, 5)); $h9 = $h9->subInt64($carry9->shiftLeft(25)); $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt64($carry0); $h0 = $h0->subInt64($carry0->shiftLeft(26)); return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( $h0->toInt32(), $h1->toInt32(), $h2->toInt32(), $h3->toInt32(), $h4->toInt32(), $h5->toInt32(), $h6->toInt32(), $h7->toInt32(), $h8->toInt32(), $h9->toInt32() ) ); } /** * Square and double a field element * * h = 2 * f * f * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError * @psalm-suppress MixedMethodCall */ public static function fe_sq2(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { $f0 = $f[0]->toInt64(); $f1 = $f[1]->toInt64(); $f2 = $f[2]->toInt64(); $f3 = $f[3]->toInt64(); $f4 = $f[4]->toInt64(); $f5 = $f[5]->toInt64(); $f6 = $f[6]->toInt64(); $f7 = $f[7]->toInt64(); $f8 = $f[8]->toInt64(); $f9 = $f[9]->toInt64(); $f0_2 = $f0->shiftLeft(1); $f1_2 = $f1->shiftLeft(1); $f2_2 = $f2->shiftLeft(1); $f3_2 = $f3->shiftLeft(1); $f4_2 = $f4->shiftLeft(1); $f5_2 = $f5->shiftLeft(1); $f6_2 = $f6->shiftLeft(1); $f7_2 = $f7->shiftLeft(1); $f5_38 = $f5->mulInt(38, 6); /* 1.959375*2^30 */ $f6_19 = $f6->mulInt(19, 5); /* 1.959375*2^30 */ $f7_38 = $f7->mulInt(38, 6); /* 1.959375*2^30 */ $f8_19 = $f8->mulInt(19, 5); /* 1.959375*2^30 */ $f9_38 = $f9->mulInt(38, 6); /* 1.959375*2^30 */ $f0f0 = $f0->mulInt64($f0, 28); $f0f1_2 = $f0_2->mulInt64($f1, 28); $f0f2_2 = $f0_2->mulInt64($f2, 28); $f0f3_2 = $f0_2->mulInt64($f3, 28); $f0f4_2 = $f0_2->mulInt64($f4, 28); $f0f5_2 = $f0_2->mulInt64($f5, 28); $f0f6_2 = $f0_2->mulInt64($f6, 28); $f0f7_2 = $f0_2->mulInt64($f7, 28); $f0f8_2 = $f0_2->mulInt64($f8, 28); $f0f9_2 = $f0_2->mulInt64($f9, 28); $f1f1_2 = $f1_2->mulInt64($f1, 28); $f1f2_2 = $f1_2->mulInt64($f2, 28); $f1f3_4 = $f1_2->mulInt64($f3_2, 29); $f1f4_2 = $f1_2->mulInt64($f4, 28); $f1f5_4 = $f1_2->mulInt64($f5_2, 29); $f1f6_2 = $f1_2->mulInt64($f6, 28); $f1f7_4 = $f1_2->mulInt64($f7_2, 29); $f1f8_2 = $f1_2->mulInt64($f8, 28); $f1f9_76 = $f9_38->mulInt64($f1_2, 29); $f2f2 = $f2->mulInt64($f2, 28); $f2f3_2 = $f2_2->mulInt64($f3, 28); $f2f4_2 = $f2_2->mulInt64($f4, 28); $f2f5_2 = $f2_2->mulInt64($f5, 28); $f2f6_2 = $f2_2->mulInt64($f6, 28); $f2f7_2 = $f2_2->mulInt64($f7, 28); $f2f8_38 = $f8_19->mulInt64($f2_2, 29); $f2f9_38 = $f9_38->mulInt64($f2, 29); $f3f3_2 = $f3_2->mulInt64($f3, 28); $f3f4_2 = $f3_2->mulInt64($f4, 28); $f3f5_4 = $f3_2->mulInt64($f5_2, 28); $f3f6_2 = $f3_2->mulInt64($f6, 28); $f3f7_76 = $f7_38->mulInt64($f3_2, 29); $f3f8_38 = $f8_19->mulInt64($f3_2, 29); $f3f9_76 = $f9_38->mulInt64($f3_2, 29); $f4f4 = $f4->mulInt64($f4, 28); $f4f5_2 = $f4_2->mulInt64($f5, 28); $f4f6_38 = $f6_19->mulInt64($f4_2, 29); $f4f7_38 = $f7_38->mulInt64($f4, 29); $f4f8_38 = $f8_19->mulInt64($f4_2, 29); $f4f9_38 = $f9_38->mulInt64($f4, 29); $f5f5_38 = $f5_38->mulInt64($f5, 29); $f5f6_38 = $f6_19->mulInt64($f5_2, 29); $f5f7_76 = $f7_38->mulInt64($f5_2, 29); $f5f8_38 = $f8_19->mulInt64($f5_2, 29); $f5f9_76 = $f9_38->mulInt64($f5_2, 29); $f6f6_19 = $f6_19->mulInt64($f6, 29); $f6f7_38 = $f7_38->mulInt64($f6, 29); $f6f8_38 = $f8_19->mulInt64($f6_2, 29); $f6f9_38 = $f9_38->mulInt64($f6, 29); $f7f7_38 = $f7_38->mulInt64($f7, 29); $f7f8_38 = $f8_19->mulInt64($f7_2, 29); $f7f9_76 = $f9_38->mulInt64($f7_2, 29); $f8f8_19 = $f8_19->mulInt64($f8, 29); $f8f9_38 = $f9_38->mulInt64($f8, 29); $f9f9_38 = $f9_38->mulInt64($f9, 29); $h0 = $f0f0->addInt64($f1f9_76)->addInt64($f2f8_38)->addInt64($f3f7_76)->addInt64($f4f6_38)->addInt64($f5f5_38); $h1 = $f0f1_2->addInt64($f2f9_38)->addInt64($f3f8_38)->addInt64($f4f7_38)->addInt64($f5f6_38); $h2 = $f0f2_2->addInt64($f1f1_2)->addInt64($f3f9_76)->addInt64($f4f8_38)->addInt64($f5f7_76)->addInt64($f6f6_19); $h3 = $f0f3_2->addInt64($f1f2_2)->addInt64($f4f9_38)->addInt64($f5f8_38)->addInt64($f6f7_38); $h4 = $f0f4_2->addInt64($f1f3_4)->addInt64($f2f2)->addInt64($f5f9_76)->addInt64($f6f8_38)->addInt64($f7f7_38); $h5 = $f0f5_2->addInt64($f1f4_2)->addInt64($f2f3_2)->addInt64($f6f9_38)->addInt64($f7f8_38); $h6 = $f0f6_2->addInt64($f1f5_4)->addInt64($f2f4_2)->addInt64($f3f3_2)->addInt64($f7f9_76)->addInt64($f8f8_19); $h7 = $f0f7_2->addInt64($f1f6_2)->addInt64($f2f5_2)->addInt64($f3f4_2)->addInt64($f8f9_38); $h8 = $f0f8_2->addInt64($f1f7_4)->addInt64($f2f6_2)->addInt64($f3f5_4)->addInt64($f4f4)->addInt64($f9f9_38); $h9 = $f0f9_2->addInt64($f1f8_2)->addInt64($f2f7_2)->addInt64($f3f6_2)->addInt64($f4f5_2); /** * @var ParagonIE_Sodium_Core32_Int64 $h0 * @var ParagonIE_Sodium_Core32_Int64 $h1 * @var ParagonIE_Sodium_Core32_Int64 $h2 * @var ParagonIE_Sodium_Core32_Int64 $h3 * @var ParagonIE_Sodium_Core32_Int64 $h4 * @var ParagonIE_Sodium_Core32_Int64 $h5 * @var ParagonIE_Sodium_Core32_Int64 $h6 * @var ParagonIE_Sodium_Core32_Int64 $h7 * @var ParagonIE_Sodium_Core32_Int64 $h8 * @var ParagonIE_Sodium_Core32_Int64 $h9 */ $h0 = $h0->shiftLeft(1); $h1 = $h1->shiftLeft(1); $h2 = $h2->shiftLeft(1); $h3 = $h3->shiftLeft(1); $h4 = $h4->shiftLeft(1); $h5 = $h5->shiftLeft(1); $h6 = $h6->shiftLeft(1); $h7 = $h7->shiftLeft(1); $h8 = $h8->shiftLeft(1); $h9 = $h9->shiftLeft(1); $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt64($carry0); $h0 = $h0->subInt64($carry0->shiftLeft(26)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt64($carry4); $h4 = $h4->subInt64($carry4->shiftLeft(26)); $carry1 = $h1->addInt(1 << 24)->shiftRight(25); $h2 = $h2->addInt64($carry1); $h1 = $h1->subInt64($carry1->shiftLeft(25)); $carry5 = $h5->addInt(1 << 24)->shiftRight(25); $h6 = $h6->addInt64($carry5); $h5 = $h5->subInt64($carry5->shiftLeft(25)); $carry2 = $h2->addInt(1 << 25)->shiftRight(26); $h3 = $h3->addInt64($carry2); $h2 = $h2->subInt64($carry2->shiftLeft(26)); $carry6 = $h6->addInt(1 << 25)->shiftRight(26); $h7 = $h7->addInt64($carry6); $h6 = $h6->subInt64($carry6->shiftLeft(26)); $carry3 = $h3->addInt(1 << 24)->shiftRight(25); $h4 = $h4->addInt64($carry3); $h3 = $h3->subInt64($carry3->shiftLeft(25)); $carry7 = $h7->addInt(1 << 24)->shiftRight(25); $h8 = $h8->addInt64($carry7); $h7 = $h7->subInt64($carry7->shiftLeft(25)); $carry4 = $h4->addInt(1 << 25)->shiftRight(26); $h5 = $h5->addInt64($carry4); $h4 = $h4->subInt64($carry4->shiftLeft(26)); $carry8 = $h8->addInt(1 << 25)->shiftRight(26); $h9 = $h9->addInt64($carry8); $h8 = $h8->subInt64($carry8->shiftLeft(26)); $carry9 = $h9->addInt(1 << 24)->shiftRight(25); $h0 = $h0->addInt64($carry9->mulInt(19, 5)); $h9 = $h9->subInt64($carry9->shiftLeft(25)); $carry0 = $h0->addInt(1 << 25)->shiftRight(26); $h1 = $h1->addInt64($carry0); $h0 = $h0->subInt64($carry0->shiftLeft(26)); return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( $h0->toInt32(), $h1->toInt32(), $h2->toInt32(), $h3->toInt32(), $h4->toInt32(), $h5->toInt32(), $h6->toInt32(), $h7->toInt32(), $h8->toInt32(), $h9->toInt32() ) ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $Z * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError */ public static function fe_invert(ParagonIE_Sodium_Core32_Curve25519_Fe $Z) { $z = clone $Z; $t0 = self::fe_sq($z); $t1 = self::fe_sq($t0); $t1 = self::fe_sq($t1); $t1 = self::fe_mul($z, $t1); $t0 = self::fe_mul($t0, $t1); $t2 = self::fe_sq($t0); $t1 = self::fe_mul($t1, $t2); $t2 = self::fe_sq($t1); for ($i = 1; $i < 5; ++$i) { $t2 = self::fe_sq($t2); } $t1 = self::fe_mul($t2, $t1); $t2 = self::fe_sq($t1); for ($i = 1; $i < 10; ++$i) { $t2 = self::fe_sq($t2); } $t2 = self::fe_mul($t2, $t1); $t3 = self::fe_sq($t2); for ($i = 1; $i < 20; ++$i) { $t3 = self::fe_sq($t3); } $t2 = self::fe_mul($t3, $t2); $t2 = self::fe_sq($t2); for ($i = 1; $i < 10; ++$i) { $t2 = self::fe_sq($t2); } $t1 = self::fe_mul($t2, $t1); $t2 = self::fe_sq($t1); for ($i = 1; $i < 50; ++$i) { $t2 = self::fe_sq($t2); } $t2 = self::fe_mul($t2, $t1); $t3 = self::fe_sq($t2); for ($i = 1; $i < 100; ++$i) { $t3 = self::fe_sq($t3); } $t2 = self::fe_mul($t3, $t2); $t2 = self::fe_sq($t2); for ($i = 1; $i < 50; ++$i) { $t2 = self::fe_sq($t2); } $t1 = self::fe_mul($t2, $t1); $t1 = self::fe_sq($t1); for ($i = 1; $i < 5; ++$i) { $t1 = self::fe_sq($t1); } return self::fe_mul($t1, $t0); } /** * @internal You should not use this directly from another application * * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106 * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $z * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError */ public static function fe_pow22523(ParagonIE_Sodium_Core32_Curve25519_Fe $z) { # fe_sq(t0, z); # fe_sq(t1, t0); # fe_sq(t1, t1); # fe_mul(t1, z, t1); # fe_mul(t0, t0, t1); # fe_sq(t0, t0); # fe_mul(t0, t1, t0); # fe_sq(t1, t0); $t0 = self::fe_sq($z); $t1 = self::fe_sq($t0); $t1 = self::fe_sq($t1); $t1 = self::fe_mul($z, $t1); $t0 = self::fe_mul($t0, $t1); $t0 = self::fe_sq($t0); $t0 = self::fe_mul($t1, $t0); $t1 = self::fe_sq($t0); # for (i = 1; i < 5; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 5; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t0, t1, t0); # fe_sq(t1, t0); $t0 = self::fe_mul($t1, $t0); $t1 = self::fe_sq($t0); # for (i = 1; i < 10; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 10; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t1, t1, t0); # fe_sq(t2, t1); $t1 = self::fe_mul($t1, $t0); $t2 = self::fe_sq($t1); # for (i = 1; i < 20; ++i) { # fe_sq(t2, t2); # } for ($i = 1; $i < 20; ++$i) { $t2 = self::fe_sq($t2); } # fe_mul(t1, t2, t1); # fe_sq(t1, t1); $t1 = self::fe_mul($t2, $t1); $t1 = self::fe_sq($t1); # for (i = 1; i < 10; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 10; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t0, t1, t0); # fe_sq(t1, t0); $t0 = self::fe_mul($t1, $t0); $t1 = self::fe_sq($t0); # for (i = 1; i < 50; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 50; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t1, t1, t0); # fe_sq(t2, t1); $t1 = self::fe_mul($t1, $t0); $t2 = self::fe_sq($t1); # for (i = 1; i < 100; ++i) { # fe_sq(t2, t2); # } for ($i = 1; $i < 100; ++$i) { $t2 = self::fe_sq($t2); } # fe_mul(t1, t2, t1); # fe_sq(t1, t1); $t1 = self::fe_mul($t2, $t1); $t1 = self::fe_sq($t1); # for (i = 1; i < 50; ++i) { # fe_sq(t1, t1); # } for ($i = 1; $i < 50; ++$i) { $t1 = self::fe_sq($t1); } # fe_mul(t0, t1, t0); # fe_sq(t0, t0); # fe_sq(t0, t0); # fe_mul(out, t0, z); $t0 = self::fe_mul($t1, $t0); $t0 = self::fe_sq($t0); $t0 = self::fe_sq($t0); return self::fe_mul($t0, $z); } /** * Subtract two field elements. * * h = f - g * * Preconditions: * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * * Postconditions: * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError * @psalm-suppress MixedMethodCall * @psalm-suppress MixedTypeCoercion */ public static function fe_sub(ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g) { return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( $f[0]->subInt32($g[0]), $f[1]->subInt32($g[1]), $f[2]->subInt32($g[2]), $f[3]->subInt32($g[3]), $f[4]->subInt32($g[4]), $f[5]->subInt32($g[5]), $f[6]->subInt32($g[6]), $f[7]->subInt32($g[7]), $f[8]->subInt32($g[8]), $f[9]->subInt32($g[9]) ) ); } /** * Add two group elements. * * r = p + q * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 * @throws SodiumException * @throws TypeError */ public static function ge_add( ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q ) { $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1(); $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->YplusX); $r->Y = self::fe_mul($r->Y, $q->YminusX); $r->T = self::fe_mul($q->T2d, $p->T); $r->X = self::fe_mul($p->Z, $q->Z); $t0 = self::fe_add($r->X, $r->X); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_add($t0, $r->T); $r->T = self::fe_sub($t0, $r->T); return $r; } /** * @internal You should not use this directly from another application * * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215 * @param string $a * @return array<int, mixed> * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayOffset */ public static function slide($a) { if (self::strlen($a) < 256) { if (self::strlen($a) < 16) { $a = str_pad($a, 256, '0', STR_PAD_RIGHT); } } /** @var array<int, int> $r */ $r = array(); for ($i = 0; $i < 256; ++$i) { $r[$i] = (int) (1 & ( self::chrToInt($a[$i >> 3]) >> ($i & 7) ) ); } for ($i = 0;$i < 256;++$i) { if ($r[$i]) { for ($b = 1;$b <= 6 && $i + $b < 256;++$b) { if ($r[$i + $b]) { if ($r[$i] + ($r[$i + $b] << $b) <= 15) { $r[$i] += $r[$i + $b] << $b; $r[$i + $b] = 0; } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) { $r[$i] -= $r[$i + $b] << $b; for ($k = $i + $b; $k < 256; ++$k) { if (!$r[$k]) { $r[$k] = 1; break; } $r[$k] = 0; } } else { break; } } } } } return $r; } /** * @internal You should not use this directly from another application * * @param string $s * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError */ public static function ge_frombytes_negate_vartime($s) { static $d = null; if (!$d) { $d = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[0]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[1]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[2]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[3]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[4]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[5]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[6]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[7]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[8]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d[9]) ) ); } /** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */ # fe_frombytes(h->Y,s); # fe_1(h->Z); $h = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3( self::fe_0(), self::fe_frombytes($s), self::fe_1() ); # fe_sq(u,h->Y); # fe_mul(v,u,d); # fe_sub(u,u,h->Z); /* u = y^2-1 */ # fe_add(v,v,h->Z); /* v = dy^2+1 */ $u = self::fe_sq($h->Y); /** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d */ $v = self::fe_mul($u, $d); $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */ $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */ # fe_sq(v3,v); # fe_mul(v3,v3,v); /* v3 = v^3 */ # fe_sq(h->X,v3); # fe_mul(h->X,h->X,v); # fe_mul(h->X,h->X,u); /* x = uv^7 */ $v3 = self::fe_sq($v); $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */ $h->X = self::fe_sq($v3); $h->X = self::fe_mul($h->X, $v); $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */ # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ # fe_mul(h->X,h->X,v3); # fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */ $h->X = self::fe_mul($h->X, $v3); $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */ # fe_sq(vxx,h->X); # fe_mul(vxx,vxx,v); # fe_sub(check,vxx,u); /* vx^2-u */ $vxx = self::fe_sq($h->X); $vxx = self::fe_mul($vxx, $v); $check = self::fe_sub($vxx, $u); /* vx^2 - u */ # if (fe_isnonzero(check)) { # fe_add(check,vxx,u); /* vx^2+u */ # if (fe_isnonzero(check)) { # return -1; # } # fe_mul(h->X,h->X,sqrtm1); # } if (self::fe_isnonzero($check)) { $check = self::fe_add($vxx, $u); /* vx^2 + u */ if (self::fe_isnonzero($check)) { throw new RangeException('Internal check failed.'); } $h->X = self::fe_mul( $h->X, ParagonIE_Sodium_Core32_Curve25519_Fe::fromIntArray(self::$sqrtm1) ); } # if (fe_isnegative(h->X) == (s[31] >> 7)) { # fe_neg(h->X,h->X); # } $i = self::chrToInt($s[31]); if (self::fe_isnegative($h->X) === ($i >> 7)) { $h->X = self::fe_neg($h->X); } # fe_mul(h->T,h->X,h->Y); $h->T = self::fe_mul($h->X, $h->Y); return $h; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 * @throws SodiumException * @throws TypeError */ public static function ge_madd( ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R, ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q ) { $r = clone $R; $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->yplusx); $r->Y = self::fe_mul($r->Y, $q->yminusx); $r->T = self::fe_mul($q->xy2d, $p->T); $t0 = self::fe_add(clone $p->Z, clone $p->Z); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_add($t0, $r->T); $r->T = self::fe_sub($t0, $r->T); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 * @throws SodiumException * @throws TypeError */ public static function ge_msub( ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $R, ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $q ) { $r = clone $R; $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->yminusx); $r->Y = self::fe_mul($r->Y, $q->yplusx); $r->T = self::fe_mul($q->xy2d, $p->T); $t0 = self::fe_add($p->Z, $p->Z); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_sub($t0, $r->T); $r->T = self::fe_add($t0, $r->T); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2 * @throws SodiumException * @throws TypeError */ public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p) { $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P2(); $r->X = self::fe_mul($p->X, $p->T); $r->Y = self::fe_mul($p->Y, $p->Z); $r->Z = self::fe_mul($p->Z, $p->T); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError */ public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 $p) { $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P3(); $r->X = self::fe_mul($p->X, $p->T); $r->Y = self::fe_mul($p->Y, $p->Z); $r->Z = self::fe_mul($p->Z, $p->T); $r->T = self::fe_mul($p->X, $p->Y); return $r; } /** * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2 * @throws SodiumException * @throws TypeError */ public static function ge_p2_0() { return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2( self::fe_0(), self::fe_1(), self::fe_1() ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 * @throws SodiumException * @throws TypeError */ public static function ge_p2_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $p) { $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1(); $r->X = self::fe_sq($p->X); $r->Z = self::fe_sq($p->Y); $r->T = self::fe_sq2($p->Z); $r->Y = self::fe_add($p->X, $p->Y); $t0 = self::fe_sq($r->Y); $r->Y = self::fe_add($r->Z, $r->X); $r->Z = self::fe_sub($r->Z, $r->X); $r->X = self::fe_sub($t0, $r->Y); $r->T = self::fe_sub($r->T, $r->Z); return $r; } /** * @internal You should not use this directly from another application * * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError */ public static function ge_p3_0() { return new ParagonIE_Sodium_Core32_Curve25519_Ge_P3( self::fe_0(), self::fe_1(), self::fe_1(), self::fe_0() ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Cached * @throws SodiumException * @throws TypeError */ public static function ge_p3_to_cached(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p) { static $d2 = null; if ($d2 === null) { $d2 = ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[0]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[1]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[2]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[3]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[4]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[5]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[6]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[7]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[8]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$d2[9]) ) ); } /** @var ParagonIE_Sodium_Core32_Curve25519_Fe $d2 */ $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached(); $r->YplusX = self::fe_add($p->Y, $p->X); $r->YminusX = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_copy($p->Z); $r->T2d = self::fe_mul($p->T, $d2); return $r; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2 */ public static function ge_p3_to_p2(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p) { return new ParagonIE_Sodium_Core32_Curve25519_Ge_P2( $p->X, $p->Y, $p->Z ); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h * @return string * @throws SodiumException * @throws TypeError */ public static function ge_p3_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $h) { $recip = self::fe_invert($h->Z); $x = self::fe_mul($h->X, $recip); $y = self::fe_mul($h->Y, $recip); $s = self::fe_tobytes($y); $s[31] = self::intToChr( self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) ); return $s; } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 * @throws SodiumException * @throws TypeError */ public static function ge_p3_dbl(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p) { $q = self::ge_p3_to_p2($p); return self::ge_p2_dbl($q); } /** * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp * @throws SodiumException * @throws TypeError */ public static function ge_precomp_0() { return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp( self::fe_1(), self::fe_1(), self::fe_0() ); } /** * @internal You should not use this directly from another application * * @param int $b * @param int $c * @return int * @psalm-suppress MixedReturnStatement */ public static function equal($b, $c) { $b0 = $b & 0xffff; $b1 = ($b >> 16) & 0xffff; $c0 = $c & 0xffff; $c1 = ($c >> 16) & 0xffff; $d0 = (($b0 ^ $c0) - 1) >> 31; $d1 = (($b1 ^ $c1) - 1) >> 31; return ($d0 & $d1) & 1; } /** * @internal You should not use this directly from another application * * @param string|int $char * @return int (1 = yes, 0 = no) * @throws SodiumException * @throws TypeError */ public static function negative($char) { if (is_int($char)) { return $char < 0 ? 1 : 0; } /** @var string $char */ $x = self::chrToInt(self::substr($char, 0, 1)); return (int) ($x >> 31); } /** * Conditional move * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u * @param int $b * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp * @throws SodiumException * @throws TypeError */ public static function cmov( ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $t, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $u, $b ) { if (!is_int($b)) { throw new InvalidArgumentException('Expected an integer.'); } return new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp( self::fe_cmov($t->yplusx, $u->yplusx, $b), self::fe_cmov($t->yminusx, $u->yminusx, $b), self::fe_cmov($t->xy2d, $u->xy2d, $b) ); } /** * @internal You should not use this directly from another application * * @param int $pos * @param int $b * @return ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedArgument */ public static function ge_select($pos = 0, $b = 0) { static $base = null; if ($base === null) { $base = array(); foreach (self::$base as $i => $bas) { for ($j = 0; $j < 8; ++$j) { $base[$i][$j] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp( ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][0]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][1]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][2]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][3]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][4]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][5]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][6]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][7]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][8]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][0][9]) ) ), ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][0]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][1]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][2]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][3]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][4]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][5]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][6]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][7]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][8]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][1][9]) ) ), ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][0]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][1]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][2]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][3]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][4]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][5]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][6]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][7]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][8]), ParagonIE_Sodium_Core32_Int32::fromInt($bas[$j][2][9]) ) ) ); } } } if (!is_int($pos)) { throw new InvalidArgumentException('Position must be an integer'); } if ($pos < 0 || $pos > 31) { throw new RangeException('Position is out of range [0, 31]'); } $bnegative = self::negative($b); $babs = $b - (((-$bnegative) & $b) << 1); $t = self::ge_precomp_0(); for ($i = 0; $i < 8; ++$i) { $t = self::cmov( $t, $base[$pos][$i], -self::equal($babs, $i + 1) ); } $minusT = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp( self::fe_copy($t->yminusx), self::fe_copy($t->yplusx), self::fe_neg($t->xy2d) ); return self::cmov($t, $minusT, -$bnegative); } /** * Subtract two group elements. * * r = p - q * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p * @param ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 * @throws SodiumException * @throws TypeError */ public static function ge_sub( ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $p, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached $q ) { $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1(); $r->X = self::fe_add($p->Y, $p->X); $r->Y = self::fe_sub($p->Y, $p->X); $r->Z = self::fe_mul($r->X, $q->YminusX); $r->Y = self::fe_mul($r->Y, $q->YplusX); $r->T = self::fe_mul($q->T2d, $p->T); $r->X = self::fe_mul($p->Z, $q->Z); $t0 = self::fe_add($r->X, $r->X); $r->X = self::fe_sub($r->Z, $r->Y); $r->Y = self::fe_add($r->Z, $r->Y); $r->Z = self::fe_sub($t0, $r->T); $r->T = self::fe_add($t0, $r->T); return $r; } /** * Convert a group element to a byte string. * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h * @return string * @throws SodiumException * @throws TypeError */ public static function ge_tobytes(ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $h) { $recip = self::fe_invert($h->Z); $x = self::fe_mul($h->X, $recip); $y = self::fe_mul($h->Y, $recip); $s = self::fe_tobytes($y); $s[31] = self::intToChr( self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) ); return $s; } /** * @internal You should not use this directly from another application * * @param string $a * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A * @param string $b * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P2 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess */ public static function ge_double_scalarmult_vartime( $a, ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A, $b ) { /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */ $Ai = array(); static $Bi = array(); /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */ if (!$Bi) { for ($i = 0; $i < 8; ++$i) { $Bi[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp( ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][0]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][1]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][2]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][3]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][4]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][5]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][6]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][7]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][8]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][0][9]) ) ), ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][0]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][1]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][2]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][3]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][4]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][5]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][6]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][7]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][8]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][1][9]) ) ), ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray( array( ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][0]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][1]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][2]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][3]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][4]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][5]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][6]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][7]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][8]), ParagonIE_Sodium_Core32_Int32::fromInt(self::$base2[$i][2][9]) ) ) ); } } for ($i = 0; $i < 8; ++$i) { $Ai[$i] = new ParagonIE_Sodium_Core32_Curve25519_Ge_Cached( self::fe_0(), self::fe_0(), self::fe_0(), self::fe_0() ); } /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai */ # slide(aslide,a); # slide(bslide,b); /** @var array<int, int> $aslide */ $aslide = self::slide($a); /** @var array<int, int> $bslide */ $bslide = self::slide($b); # ge_p3_to_cached(&Ai[0],A); # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); $Ai[0] = self::ge_p3_to_cached($A); $t = self::ge_p3_dbl($A); $A2 = self::ge_p1p1_to_p3($t); # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); for ($i = 0; $i < 7; ++$i) { $t = self::ge_add($A2, $Ai[$i]); $u = self::ge_p1p1_to_p3($t); $Ai[$i + 1] = self::ge_p3_to_cached($u); } # ge_p2_0(r); $r = self::ge_p2_0(); # for (i = 255;i >= 0;--i) { # if (aslide[i] || bslide[i]) break; # } $i = 255; for (; $i >= 0; --$i) { if ($aslide[$i] || $bslide[$i]) { break; } } # for (;i >= 0;--i) { for (; $i >= 0; --$i) { # ge_p2_dbl(&t,r); $t = self::ge_p2_dbl($r); # if (aslide[i] > 0) { if ($aslide[$i] > 0) { # ge_p1p1_to_p3(&u,&t); # ge_add(&t,&u,&Ai[aslide[i]/2]); $u = self::ge_p1p1_to_p3($t); $t = self::ge_add( $u, $Ai[(int) floor($aslide[$i] / 2)] ); # } else if (aslide[i] < 0) { } elseif ($aslide[$i] < 0) { # ge_p1p1_to_p3(&u,&t); # ge_sub(&t,&u,&Ai[(-aslide[i])/2]); $u = self::ge_p1p1_to_p3($t); $t = self::ge_sub( $u, $Ai[(int) floor(-$aslide[$i] / 2)] ); } /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp> $Bi */ # if (bslide[i] > 0) { if ($bslide[$i] > 0) { # ge_p1p1_to_p3(&u,&t); # ge_madd(&t,&u,&Bi[bslide[i]/2]); $u = self::ge_p1p1_to_p3($t); /** @var int $index */ $index = (int) floor($bslide[$i] / 2); /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $thisB */ $thisB = $Bi[$index]; $t = self::ge_madd($t, $u, $thisB); # } else if (bslide[i] < 0) { } elseif ($bslide[$i] < 0) { # ge_p1p1_to_p3(&u,&t); # ge_msub(&t,&u,&Bi[(-bslide[i])/2]); $u = self::ge_p1p1_to_p3($t); /** @var int $index */ $index = (int) floor(-$bslide[$i] / 2); /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp $thisB */ $thisB = $Bi[$index]; $t = self::ge_msub($t, $u, $thisB); } # ge_p1p1_to_p2(r,&t); $r = self::ge_p1p1_to_p2($t); } return $r; } /** * @internal You should not use this directly from another application * * @param string $a * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3 * @psalm-suppress MixedAssignment * @psalm-suppress MixedOperand * @throws SodiumException * @throws TypeError */ public static function ge_scalarmult_base($a) { /** @var array<int, int> $e */ $e = array(); $r = new ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1(); for ($i = 0; $i < 32; ++$i) { /** @var int $dbl */ $dbl = (int) $i << 1; $e[$dbl] = (int) self::chrToInt($a[$i]) & 15; $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15; } /** @var int $carry */ $carry = 0; for ($i = 0; $i < 63; ++$i) { $e[$i] += $carry; $carry = $e[$i] + 8; $carry >>= 4; $e[$i] -= $carry << 4; } /** @var array<int, int> $e */ $e[63] += (int) $carry; $h = self::ge_p3_0(); for ($i = 1; $i < 64; $i += 2) { $t = self::ge_select((int) floor($i / 2), (int) $e[$i]); $r = self::ge_madd($r, $h, $t); $h = self::ge_p1p1_to_p3($r); } $r = self::ge_p3_dbl($h); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $s = self::ge_p1p1_to_p2($r); $r = self::ge_p2_dbl($s); $h = self::ge_p1p1_to_p3($r); for ($i = 0; $i < 64; $i += 2) { $t = self::ge_select($i >> 1, (int) $e[$i]); $r = self::ge_madd($r, $h, $t); $h = self::ge_p1p1_to_p3($r); } return $h; } /** * Calculates (ab + c) mod l * where l = 2^252 + 27742317777372353535851937790883648493 * * @internal You should not use this directly from another application * * @param string $a * @param string $b * @param string $c * @return string * @throws SodiumException * @throws TypeError */ public static function sc_muladd($a, $b, $c) { $a0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($a, 0, 3))); $a1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5)); $a2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2)); $a3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7)); $a4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4)); $a5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1)); $a6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6)); $a7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3)); $a8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($a, 21, 3))); $a9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5)); $a10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2)); $a11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($a, 28, 4)) >> 7)); $b0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($b, 0, 3))); $b1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5)); $b2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2)); $b3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7)); $b4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4)); $b5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1)); $b6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6)); $b7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3)); $b8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($b, 21, 3))); $b9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5)); $b10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2)); $b11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($b, 28, 4)) >> 7)); $c0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($c, 0, 3))); $c1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5)); $c2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2)); $c3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7)); $c4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4)); $c5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1)); $c6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6)); $c7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3)); $c8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($c, 21, 3))); $c9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5)); $c10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2)); $c11 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($c, 28, 4)) >> 7)); /* Can't really avoid the pyramid here: */ /** * @var ParagonIE_Sodium_Core32_Int64 $s0 * @var ParagonIE_Sodium_Core32_Int64 $s1 * @var ParagonIE_Sodium_Core32_Int64 $s2 * @var ParagonIE_Sodium_Core32_Int64 $s3 * @var ParagonIE_Sodium_Core32_Int64 $s4 * @var ParagonIE_Sodium_Core32_Int64 $s5 * @var ParagonIE_Sodium_Core32_Int64 $s6 * @var ParagonIE_Sodium_Core32_Int64 $s7 * @var ParagonIE_Sodium_Core32_Int64 $s8 * @var ParagonIE_Sodium_Core32_Int64 $s9 * @var ParagonIE_Sodium_Core32_Int64 $s10 * @var ParagonIE_Sodium_Core32_Int64 $s11 * @var ParagonIE_Sodium_Core32_Int64 $s12 * @var ParagonIE_Sodium_Core32_Int64 $s13 * @var ParagonIE_Sodium_Core32_Int64 $s14 * @var ParagonIE_Sodium_Core32_Int64 $s15 * @var ParagonIE_Sodium_Core32_Int64 $s16 * @var ParagonIE_Sodium_Core32_Int64 $s17 * @var ParagonIE_Sodium_Core32_Int64 $s18 * @var ParagonIE_Sodium_Core32_Int64 $s19 * @var ParagonIE_Sodium_Core32_Int64 $s20 * @var ParagonIE_Sodium_Core32_Int64 $s21 * @var ParagonIE_Sodium_Core32_Int64 $s22 * @var ParagonIE_Sodium_Core32_Int64 $s23 */ $s0 = $c0->addInt64($a0->mulInt64($b0, 24)); $s1 = $c1->addInt64($a0->mulInt64($b1, 24))->addInt64($a1->mulInt64($b0, 24)); $s2 = $c2->addInt64($a0->mulInt64($b2, 24))->addInt64($a1->mulInt64($b1, 24))->addInt64($a2->mulInt64($b0, 24)); $s3 = $c3->addInt64($a0->mulInt64($b3, 24))->addInt64($a1->mulInt64($b2, 24))->addInt64($a2->mulInt64($b1, 24)) ->addInt64($a3->mulInt64($b0, 24)); $s4 = $c4->addInt64($a0->mulInt64($b4, 24))->addInt64($a1->mulInt64($b3, 24))->addInt64($a2->mulInt64($b2, 24)) ->addInt64($a3->mulInt64($b1, 24))->addInt64($a4->mulInt64($b0, 24)); $s5 = $c5->addInt64($a0->mulInt64($b5, 24))->addInt64($a1->mulInt64($b4, 24))->addInt64($a2->mulInt64($b3, 24)) ->addInt64($a3->mulInt64($b2, 24))->addInt64($a4->mulInt64($b1, 24))->addInt64($a5->mulInt64($b0, 24)); $s6 = $c6->addInt64($a0->mulInt64($b6, 24))->addInt64($a1->mulInt64($b5, 24))->addInt64($a2->mulInt64($b4, 24)) ->addInt64($a3->mulInt64($b3, 24))->addInt64($a4->mulInt64($b2, 24))->addInt64($a5->mulInt64($b1, 24)) ->addInt64($a6->mulInt64($b0, 24)); $s7 = $c7->addInt64($a0->mulInt64($b7, 24))->addInt64($a1->mulInt64($b6, 24))->addInt64($a2->mulInt64($b5, 24)) ->addInt64($a3->mulInt64($b4, 24))->addInt64($a4->mulInt64($b3, 24))->addInt64($a5->mulInt64($b2, 24)) ->addInt64($a6->mulInt64($b1, 24))->addInt64($a7->mulInt64($b0, 24)); $s8 = $c8->addInt64($a0->mulInt64($b8, 24))->addInt64($a1->mulInt64($b7, 24))->addInt64($a2->mulInt64($b6, 24)) ->addInt64($a3->mulInt64($b5, 24))->addInt64($a4->mulInt64($b4, 24))->addInt64($a5->mulInt64($b3, 24)) ->addInt64($a6->mulInt64($b2, 24))->addInt64($a7->mulInt64($b1, 24))->addInt64($a8->mulInt64($b0, 24)); $s9 = $c9->addInt64($a0->mulInt64($b9, 24))->addInt64($a1->mulInt64($b8, 24))->addInt64($a2->mulInt64($b7, 24)) ->addInt64($a3->mulInt64($b6, 24))->addInt64($a4->mulInt64($b5, 24))->addInt64($a5->mulInt64($b4, 24)) ->addInt64($a6->mulInt64($b3, 24))->addInt64($a7->mulInt64($b2, 24))->addInt64($a8->mulInt64($b1, 24)) ->addInt64($a9->mulInt64($b0, 24)); $s10 = $c10->addInt64($a0->mulInt64($b10, 24))->addInt64($a1->mulInt64($b9, 24))->addInt64($a2->mulInt64($b8, 24)) ->addInt64($a3->mulInt64($b7, 24))->addInt64($a4->mulInt64($b6, 24))->addInt64($a5->mulInt64($b5, 24)) ->addInt64($a6->mulInt64($b4, 24))->addInt64($a7->mulInt64($b3, 24))->addInt64($a8->mulInt64($b2, 24)) ->addInt64($a9->mulInt64($b1, 24))->addInt64($a10->mulInt64($b0, 24)); $s11 = $c11->addInt64($a0->mulInt64($b11, 24))->addInt64($a1->mulInt64($b10, 24))->addInt64($a2->mulInt64($b9, 24)) ->addInt64($a3->mulInt64($b8, 24))->addInt64($a4->mulInt64($b7, 24))->addInt64($a5->mulInt64($b6, 24)) ->addInt64($a6->mulInt64($b5, 24))->addInt64($a7->mulInt64($b4, 24))->addInt64($a8->mulInt64($b3, 24)) ->addInt64($a9->mulInt64($b2, 24))->addInt64($a10->mulInt64($b1, 24))->addInt64($a11->mulInt64($b0, 24)); $s12 = $a1->mulInt64($b11, 24)->addInt64($a2->mulInt64($b10, 24))->addInt64($a3->mulInt64($b9, 24)) ->addInt64($a4->mulInt64($b8, 24))->addInt64($a5->mulInt64($b7, 24))->addInt64($a6->mulInt64($b6, 24)) ->addInt64($a7->mulInt64($b5, 24))->addInt64($a8->mulInt64($b4, 24))->addInt64($a9->mulInt64($b3, 24)) ->addInt64($a10->mulInt64($b2, 24))->addInt64($a11->mulInt64($b1, 24)); $s13 = $a2->mulInt64($b11, 24)->addInt64($a3->mulInt64($b10, 24))->addInt64($a4->mulInt64($b9, 24)) ->addInt64($a5->mulInt64($b8, 24))->addInt64($a6->mulInt64($b7, 24))->addInt64($a7->mulInt64($b6, 24)) ->addInt64($a8->mulInt64($b5, 24))->addInt64($a9->mulInt64($b4, 24))->addInt64($a10->mulInt64($b3, 24)) ->addInt64($a11->mulInt64($b2, 24)); $s14 = $a3->mulInt64($b11, 24)->addInt64($a4->mulInt64($b10, 24))->addInt64($a5->mulInt64($b9, 24)) ->addInt64($a6->mulInt64($b8, 24))->addInt64($a7->mulInt64($b7, 24))->addInt64($a8->mulInt64($b6, 24)) ->addInt64($a9->mulInt64($b5, 24))->addInt64($a10->mulInt64($b4, 24))->addInt64($a11->mulInt64($b3, 24)); $s15 = $a4->mulInt64($b11, 24)->addInt64($a5->mulInt64($b10, 24))->addInt64($a6->mulInt64($b9, 24)) ->addInt64($a7->mulInt64($b8, 24))->addInt64($a8->mulInt64($b7, 24))->addInt64($a9->mulInt64($b6, 24)) ->addInt64($a10->mulInt64($b5, 24))->addInt64($a11->mulInt64($b4, 24)); $s16 = $a5->mulInt64($b11, 24)->addInt64($a6->mulInt64($b10, 24))->addInt64($a7->mulInt64($b9, 24)) ->addInt64($a8->mulInt64($b8, 24))->addInt64($a9->mulInt64($b7, 24))->addInt64($a10->mulInt64($b6, 24)) ->addInt64($a11->mulInt64($b5, 24)); $s17 = $a6->mulInt64($b11, 24)->addInt64($a7->mulInt64($b10, 24))->addInt64($a8->mulInt64($b9, 24)) ->addInt64($a9->mulInt64($b8, 24))->addInt64($a10->mulInt64($b7, 24))->addInt64($a11->mulInt64($b6, 24)); $s18 = $a7->mulInt64($b11, 24)->addInt64($a8->mulInt64($b10, 24))->addInt64($a9->mulInt64($b9, 24)) ->addInt64($a10->mulInt64($b8, 24))->addInt64($a11->mulInt64($b7, 24)); $s19 = $a8->mulInt64($b11, 24)->addInt64($a9->mulInt64($b10, 24))->addInt64($a10->mulInt64($b9, 24)) ->addInt64($a11->mulInt64($b8, 24)); $s20 = $a9->mulInt64($b11, 24)->addInt64($a10->mulInt64($b10, 24))->addInt64($a11->mulInt64($b9, 24)); $s21 = $a10->mulInt64($b11, 24)->addInt64($a11->mulInt64($b10, 24)); $s22 = $a11->mulInt64($b11, 24); $s23 = new ParagonIE_Sodium_Core32_Int64(); $carry0 = $s0->addInt(1 << 20)->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry2 = $s2->addInt(1 << 20)->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry4 = $s4->addInt(1 << 20)->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry6 = $s6->addInt(1 << 20)->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry8 = $s8->addInt(1 << 20)->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry10 = $s10->addInt(1 << 20)->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry12 = $s12->addInt(1 << 20)->shiftRight(21); $s13 = $s13->addInt64($carry12); $s12 = $s12->subInt64($carry12->shiftLeft(21)); $carry14 = $s14->addInt(1 << 20)->shiftRight(21); $s15 = $s15->addInt64($carry14); $s14 = $s14->subInt64($carry14->shiftLeft(21)); $carry16 = $s16->addInt(1 << 20)->shiftRight(21); $s17 = $s17->addInt64($carry16); $s16 = $s16->subInt64($carry16->shiftLeft(21)); $carry18 = $s18->addInt(1 << 20)->shiftRight(21); $s19 = $s19->addInt64($carry18); $s18 = $s18->subInt64($carry18->shiftLeft(21)); $carry20 = $s20->addInt(1 << 20)->shiftRight(21); $s21 = $s21->addInt64($carry20); $s20 = $s20->subInt64($carry20->shiftLeft(21)); $carry22 = $s22->addInt(1 << 20)->shiftRight(21); $s23 = $s23->addInt64($carry22); $s22 = $s22->subInt64($carry22->shiftLeft(21)); $carry1 = $s1->addInt(1 << 20)->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry3 = $s3->addInt(1 << 20)->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry5 = $s5->addInt(1 << 20)->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry7 = $s7->addInt(1 << 20)->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry9 = $s9->addInt(1 << 20)->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry11 = $s11->addInt(1 << 20)->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $carry13 = $s13->addInt(1 << 20)->shiftRight(21); $s14 = $s14->addInt64($carry13); $s13 = $s13->subInt64($carry13->shiftLeft(21)); $carry15 = $s15->addInt(1 << 20)->shiftRight(21); $s16 = $s16->addInt64($carry15); $s15 = $s15->subInt64($carry15->shiftLeft(21)); $carry17 = $s17->addInt(1 << 20)->shiftRight(21); $s18 = $s18->addInt64($carry17); $s17 = $s17->subInt64($carry17->shiftLeft(21)); $carry19 = $s19->addInt(1 << 20)->shiftRight(21); $s20 = $s20->addInt64($carry19); $s19 = $s19->subInt64($carry19->shiftLeft(21)); $carry21 = $s21->addInt(1 << 20)->shiftRight(21); $s22 = $s22->addInt64($carry21); $s21 = $s21->subInt64($carry21->shiftLeft(21)); $s11 = $s11->addInt64($s23->mulInt(666643, 20)); $s12 = $s12->addInt64($s23->mulInt(470296, 19)); $s13 = $s13->addInt64($s23->mulInt(654183, 20)); $s14 = $s14->subInt64($s23->mulInt(997805, 20)); $s15 = $s15->addInt64($s23->mulInt(136657, 18)); $s16 = $s16->subInt64($s23->mulInt(683901, 20)); $s10 = $s10->addInt64($s22->mulInt(666643, 20)); $s11 = $s11->addInt64($s22->mulInt(470296, 19)); $s12 = $s12->addInt64($s22->mulInt(654183, 20)); $s13 = $s13->subInt64($s22->mulInt(997805, 20)); $s14 = $s14->addInt64($s22->mulInt(136657, 18)); $s15 = $s15->subInt64($s22->mulInt(683901, 20)); $s9 = $s9->addInt64($s21->mulInt(666643, 20)); $s10 = $s10->addInt64($s21->mulInt(470296, 19)); $s11 = $s11->addInt64($s21->mulInt(654183, 20)); $s12 = $s12->subInt64($s21->mulInt(997805, 20)); $s13 = $s13->addInt64($s21->mulInt(136657, 18)); $s14 = $s14->subInt64($s21->mulInt(683901, 20)); $s8 = $s8->addInt64($s20->mulInt(666643, 20)); $s9 = $s9->addInt64($s20->mulInt(470296, 19)); $s10 = $s10->addInt64($s20->mulInt(654183, 20)); $s11 = $s11->subInt64($s20->mulInt(997805, 20)); $s12 = $s12->addInt64($s20->mulInt(136657, 18)); $s13 = $s13->subInt64($s20->mulInt(683901, 20)); $s7 = $s7->addInt64($s19->mulInt(666643, 20)); $s8 = $s8->addInt64($s19->mulInt(470296, 19)); $s9 = $s9->addInt64($s19->mulInt(654183, 20)); $s10 = $s10->subInt64($s19->mulInt(997805, 20)); $s11 = $s11->addInt64($s19->mulInt(136657, 18)); $s12 = $s12->subInt64($s19->mulInt(683901, 20)); $s6 = $s6->addInt64($s18->mulInt(666643, 20)); $s7 = $s7->addInt64($s18->mulInt(470296, 19)); $s8 = $s8->addInt64($s18->mulInt(654183, 20)); $s9 = $s9->subInt64($s18->mulInt(997805, 20)); $s10 = $s10->addInt64($s18->mulInt(136657, 18)); $s11 = $s11->subInt64($s18->mulInt(683901, 20)); $carry6 = $s6->addInt(1 << 20)->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry8 = $s8->addInt(1 << 20)->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry10 = $s10->addInt(1 << 20)->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry12 = $s12->addInt(1 << 20)->shiftRight(21); $s13 = $s13->addInt64($carry12); $s12 = $s12->subInt64($carry12->shiftLeft(21)); $carry14 = $s14->addInt(1 << 20)->shiftRight(21); $s15 = $s15->addInt64($carry14); $s14 = $s14->subInt64($carry14->shiftLeft(21)); $carry16 = $s16->addInt(1 << 20)->shiftRight(21); $s17 = $s17->addInt64($carry16); $s16 = $s16->subInt64($carry16->shiftLeft(21)); $carry7 = $s7->addInt(1 << 20)->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry9 = $s9->addInt(1 << 20)->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry11 = $s11->addInt(1 << 20)->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $carry13 = $s13->addInt(1 << 20)->shiftRight(21); $s14 = $s14->addInt64($carry13); $s13 = $s13->subInt64($carry13->shiftLeft(21)); $carry15 = $s15->addInt(1 << 20)->shiftRight(21); $s16 = $s16->addInt64($carry15); $s15 = $s15->subInt64($carry15->shiftLeft(21)); $s5 = $s5->addInt64($s17->mulInt(666643, 20)); $s6 = $s6->addInt64($s17->mulInt(470296, 19)); $s7 = $s7->addInt64($s17->mulInt(654183, 20)); $s8 = $s8->subInt64($s17->mulInt(997805, 20)); $s9 = $s9->addInt64($s17->mulInt(136657, 18)); $s10 = $s10->subInt64($s17->mulInt(683901, 20)); $s4 = $s4->addInt64($s16->mulInt(666643, 20)); $s5 = $s5->addInt64($s16->mulInt(470296, 19)); $s6 = $s6->addInt64($s16->mulInt(654183, 20)); $s7 = $s7->subInt64($s16->mulInt(997805, 20)); $s8 = $s8->addInt64($s16->mulInt(136657, 18)); $s9 = $s9->subInt64($s16->mulInt(683901, 20)); $s3 = $s3->addInt64($s15->mulInt(666643, 20)); $s4 = $s4->addInt64($s15->mulInt(470296, 19)); $s5 = $s5->addInt64($s15->mulInt(654183, 20)); $s6 = $s6->subInt64($s15->mulInt(997805, 20)); $s7 = $s7->addInt64($s15->mulInt(136657, 18)); $s8 = $s8->subInt64($s15->mulInt(683901, 20)); $s2 = $s2->addInt64($s14->mulInt(666643, 20)); $s3 = $s3->addInt64($s14->mulInt(470296, 19)); $s4 = $s4->addInt64($s14->mulInt(654183, 20)); $s5 = $s5->subInt64($s14->mulInt(997805, 20)); $s6 = $s6->addInt64($s14->mulInt(136657, 18)); $s7 = $s7->subInt64($s14->mulInt(683901, 20)); $s1 = $s1->addInt64($s13->mulInt(666643, 20)); $s2 = $s2->addInt64($s13->mulInt(470296, 19)); $s3 = $s3->addInt64($s13->mulInt(654183, 20)); $s4 = $s4->subInt64($s13->mulInt(997805, 20)); $s5 = $s5->addInt64($s13->mulInt(136657, 18)); $s6 = $s6->subInt64($s13->mulInt(683901, 20)); $s0 = $s0->addInt64($s12->mulInt(666643, 20)); $s1 = $s1->addInt64($s12->mulInt(470296, 19)); $s2 = $s2->addInt64($s12->mulInt(654183, 20)); $s3 = $s3->subInt64($s12->mulInt(997805, 20)); $s4 = $s4->addInt64($s12->mulInt(136657, 18)); $s5 = $s5->subInt64($s12->mulInt(683901, 20)); $s12 = new ParagonIE_Sodium_Core32_Int64(); $carry0 = $s0->addInt(1 << 20)->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry2 = $s2->addInt(1 << 20)->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry4 = $s4->addInt(1 << 20)->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry6 = $s6->addInt(1 << 20)->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry8 = $s8->addInt(1 << 20)->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry10 = $s10->addInt(1 << 20)->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry1 = $s1->addInt(1 << 20)->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry3 = $s3->addInt(1 << 20)->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry5 = $s5->addInt(1 << 20)->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry7 = $s7->addInt(1 << 20)->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry9 = $s9->addInt(1 << 20)->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry11 = $s11->addInt(1 << 20)->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $s0 = $s0->addInt64($s12->mulInt(666643, 20)); $s1 = $s1->addInt64($s12->mulInt(470296, 19)); $s2 = $s2->addInt64($s12->mulInt(654183, 20)); $s3 = $s3->subInt64($s12->mulInt(997805, 20)); $s4 = $s4->addInt64($s12->mulInt(136657, 18)); $s5 = $s5->subInt64($s12->mulInt(683901, 20)); $s12 = new ParagonIE_Sodium_Core32_Int64(); $carry0 = $s0->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry1 = $s1->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry2 = $s2->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry3 = $s3->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry4 = $s4->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry5 = $s5->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry6 = $s6->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry7 = $s7->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry8 = $s8->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry9 = $s9->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry10 = $s10->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry11 = $s11->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $s0 = $s0->addInt64($s12->mulInt(666643, 20)); $s1 = $s1->addInt64($s12->mulInt(470296, 19)); $s2 = $s2->addInt64($s12->mulInt(654183, 20)); $s3 = $s3->subInt64($s12->mulInt(997805, 20)); $s4 = $s4->addInt64($s12->mulInt(136657, 18)); $s5 = $s5->subInt64($s12->mulInt(683901, 20)); $carry0 = $s0->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry1 = $s1->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry2 = $s2->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry3 = $s3->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry4 = $s4->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry5 = $s5->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry6 = $s6->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry7 = $s7->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry8 = $s10->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry9 = $s9->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry10 = $s10->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $S0 = $s0->toInt(); $S1 = $s1->toInt(); $S2 = $s2->toInt(); $S3 = $s3->toInt(); $S4 = $s4->toInt(); $S5 = $s5->toInt(); $S6 = $s6->toInt(); $S7 = $s7->toInt(); $S8 = $s8->toInt(); $S9 = $s9->toInt(); $S10 = $s10->toInt(); $S11 = $s11->toInt(); /** * @var array<int, int> */ $arr = array( (int) (0xff & ($S0 >> 0)), (int) (0xff & ($S0 >> 8)), (int) (0xff & (($S0 >> 16) | ($S1 << 5))), (int) (0xff & ($S1 >> 3)), (int) (0xff & ($S1 >> 11)), (int) (0xff & (($S1 >> 19) | ($S2 << 2))), (int) (0xff & ($S2 >> 6)), (int) (0xff & (($S2 >> 14) | ($S3 << 7))), (int) (0xff & ($S3 >> 1)), (int) (0xff & ($S3 >> 9)), (int) (0xff & (($S3 >> 17) | ($S4 << 4))), (int) (0xff & ($S4 >> 4)), (int) (0xff & ($S4 >> 12)), (int) (0xff & (($S4 >> 20) | ($S5 << 1))), (int) (0xff & ($S5 >> 7)), (int) (0xff & (($S5 >> 15) | ($S6 << 6))), (int) (0xff & ($S6 >> 2)), (int) (0xff & ($S6 >> 10)), (int) (0xff & (($S6 >> 18) | ($S7 << 3))), (int) (0xff & ($S7 >> 5)), (int) (0xff & ($S7 >> 13)), (int) (0xff & ($S8 >> 0)), (int) (0xff & ($S8 >> 8)), (int) (0xff & (($S8 >> 16) | ($S9 << 5))), (int) (0xff & ($S9 >> 3)), (int) (0xff & ($S9 >> 11)), (int) (0xff & (($S9 >> 19) | ($S10 << 2))), (int) (0xff & ($S10 >> 6)), (int) (0xff & (($S10 >> 14) | ($S11 << 7))), (int) (0xff & ($S11 >> 1)), (int) (0xff & ($S11 >> 9)), (int) (0xff & ($S11 >> 17)) ); return self::intArrayToString($arr); } /** * @internal You should not use this directly from another application * * @param string $s * @return string * @throws SodiumException * @throws TypeError */ public static function sc_reduce($s) { /** * @var ParagonIE_Sodium_Core32_Int64 $s0 * @var ParagonIE_Sodium_Core32_Int64 $s1 * @var ParagonIE_Sodium_Core32_Int64 $s2 * @var ParagonIE_Sodium_Core32_Int64 $s3 * @var ParagonIE_Sodium_Core32_Int64 $s4 * @var ParagonIE_Sodium_Core32_Int64 $s5 * @var ParagonIE_Sodium_Core32_Int64 $s6 * @var ParagonIE_Sodium_Core32_Int64 $s7 * @var ParagonIE_Sodium_Core32_Int64 $s8 * @var ParagonIE_Sodium_Core32_Int64 $s9 * @var ParagonIE_Sodium_Core32_Int64 $s10 * @var ParagonIE_Sodium_Core32_Int64 $s11 * @var ParagonIE_Sodium_Core32_Int64 $s12 * @var ParagonIE_Sodium_Core32_Int64 $s13 * @var ParagonIE_Sodium_Core32_Int64 $s14 * @var ParagonIE_Sodium_Core32_Int64 $s15 * @var ParagonIE_Sodium_Core32_Int64 $s16 * @var ParagonIE_Sodium_Core32_Int64 $s17 * @var ParagonIE_Sodium_Core32_Int64 $s18 * @var ParagonIE_Sodium_Core32_Int64 $s19 * @var ParagonIE_Sodium_Core32_Int64 $s20 * @var ParagonIE_Sodium_Core32_Int64 $s21 * @var ParagonIE_Sodium_Core32_Int64 $s22 * @var ParagonIE_Sodium_Core32_Int64 $s23 */ $s0 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 0, 3))); $s1 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5)); $s2 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2)); $s3 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7)); $s4 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4)); $s5 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1)); $s6 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6)); $s7 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3)); $s8 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 21, 3))); $s9 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5)); $s10 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2)); $s11 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7)); $s12 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4)); $s13 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1)); $s14 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6)); $s15 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3)); $s16 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & self::load_3(self::substr($s, 42, 3))); $s17 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5)); $s18 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2)); $s19 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7)); $s20 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4)); $s21 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1)); $s22 = ParagonIE_Sodium_Core32_Int64::fromInt(2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6)); $s23 = ParagonIE_Sodium_Core32_Int64::fromInt(0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3)); $s11 = $s11->addInt64($s23->mulInt(666643, 20)); $s12 = $s12->addInt64($s23->mulInt(470296, 19)); $s13 = $s13->addInt64($s23->mulInt(654183, 20)); $s14 = $s14->subInt64($s23->mulInt(997805, 20)); $s15 = $s15->addInt64($s23->mulInt(136657, 18)); $s16 = $s16->subInt64($s23->mulInt(683901, 20)); $s10 = $s10->addInt64($s22->mulInt(666643, 20)); $s11 = $s11->addInt64($s22->mulInt(470296, 19)); $s12 = $s12->addInt64($s22->mulInt(654183, 20)); $s13 = $s13->subInt64($s22->mulInt(997805, 20)); $s14 = $s14->addInt64($s22->mulInt(136657, 18)); $s15 = $s15->subInt64($s22->mulInt(683901, 20)); $s9 = $s9->addInt64($s21->mulInt(666643, 20)); $s10 = $s10->addInt64($s21->mulInt(470296, 19)); $s11 = $s11->addInt64($s21->mulInt(654183, 20)); $s12 = $s12->subInt64($s21->mulInt(997805, 20)); $s13 = $s13->addInt64($s21->mulInt(136657, 18)); $s14 = $s14->subInt64($s21->mulInt(683901, 20)); $s8 = $s8->addInt64($s20->mulInt(666643, 20)); $s9 = $s9->addInt64($s20->mulInt(470296, 19)); $s10 = $s10->addInt64($s20->mulInt(654183, 20)); $s11 = $s11->subInt64($s20->mulInt(997805, 20)); $s12 = $s12->addInt64($s20->mulInt(136657, 18)); $s13 = $s13->subInt64($s20->mulInt(683901, 20)); $s7 = $s7->addInt64($s19->mulInt(666643, 20)); $s8 = $s8->addInt64($s19->mulInt(470296, 19)); $s9 = $s9->addInt64($s19->mulInt(654183, 20)); $s10 = $s10->subInt64($s19->mulInt(997805, 20)); $s11 = $s11->addInt64($s19->mulInt(136657, 18)); $s12 = $s12->subInt64($s19->mulInt(683901, 20)); $s6 = $s6->addInt64($s18->mulInt(666643, 20)); $s7 = $s7->addInt64($s18->mulInt(470296, 19)); $s8 = $s8->addInt64($s18->mulInt(654183, 20)); $s9 = $s9->subInt64($s18->mulInt(997805, 20)); $s10 = $s10->addInt64($s18->mulInt(136657, 18)); $s11 = $s11->subInt64($s18->mulInt(683901, 20)); $carry6 = $s6->addInt(1 << 20)->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry8 = $s8->addInt(1 << 20)->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry10 = $s10->addInt(1 << 20)->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry12 = $s12->addInt(1 << 20)->shiftRight(21); $s13 = $s13->addInt64($carry12); $s12 = $s12->subInt64($carry12->shiftLeft(21)); $carry14 = $s14->addInt(1 << 20)->shiftRight(21); $s15 = $s15->addInt64($carry14); $s14 = $s14->subInt64($carry14->shiftLeft(21)); $carry16 = $s16->addInt(1 << 20)->shiftRight(21); $s17 = $s17->addInt64($carry16); $s16 = $s16->subInt64($carry16->shiftLeft(21)); $carry7 = $s7->addInt(1 << 20)->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry9 = $s9->addInt(1 << 20)->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry11 = $s11->addInt(1 << 20)->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $carry13 = $s13->addInt(1 << 20)->shiftRight(21); $s14 = $s14->addInt64($carry13); $s13 = $s13->subInt64($carry13->shiftLeft(21)); $carry15 = $s15->addInt(1 << 20)->shiftRight(21); $s16 = $s16->addInt64($carry15); $s15 = $s15->subInt64($carry15->shiftLeft(21)); $s5 = $s5->addInt64($s17->mulInt(666643, 20)); $s6 = $s6->addInt64($s17->mulInt(470296, 19)); $s7 = $s7->addInt64($s17->mulInt(654183, 20)); $s8 = $s8->subInt64($s17->mulInt(997805, 20)); $s9 = $s9->addInt64($s17->mulInt(136657, 18)); $s10 = $s10->subInt64($s17->mulInt(683901, 20)); $s4 = $s4->addInt64($s16->mulInt(666643, 20)); $s5 = $s5->addInt64($s16->mulInt(470296, 19)); $s6 = $s6->addInt64($s16->mulInt(654183, 20)); $s7 = $s7->subInt64($s16->mulInt(997805, 20)); $s8 = $s8->addInt64($s16->mulInt(136657, 18)); $s9 = $s9->subInt64($s16->mulInt(683901, 20)); $s3 = $s3->addInt64($s15->mulInt(666643, 20)); $s4 = $s4->addInt64($s15->mulInt(470296, 19)); $s5 = $s5->addInt64($s15->mulInt(654183, 20)); $s6 = $s6->subInt64($s15->mulInt(997805, 20)); $s7 = $s7->addInt64($s15->mulInt(136657, 18)); $s8 = $s8->subInt64($s15->mulInt(683901, 20)); $s2 = $s2->addInt64($s14->mulInt(666643, 20)); $s3 = $s3->addInt64($s14->mulInt(470296, 19)); $s4 = $s4->addInt64($s14->mulInt(654183, 20)); $s5 = $s5->subInt64($s14->mulInt(997805, 20)); $s6 = $s6->addInt64($s14->mulInt(136657, 18)); $s7 = $s7->subInt64($s14->mulInt(683901, 20)); $s1 = $s1->addInt64($s13->mulInt(666643, 20)); $s2 = $s2->addInt64($s13->mulInt(470296, 19)); $s3 = $s3->addInt64($s13->mulInt(654183, 20)); $s4 = $s4->subInt64($s13->mulInt(997805, 20)); $s5 = $s5->addInt64($s13->mulInt(136657, 18)); $s6 = $s6->subInt64($s13->mulInt(683901, 20)); $s0 = $s0->addInt64($s12->mulInt(666643, 20)); $s1 = $s1->addInt64($s12->mulInt(470296, 19)); $s2 = $s2->addInt64($s12->mulInt(654183, 20)); $s3 = $s3->subInt64($s12->mulInt(997805, 20)); $s4 = $s4->addInt64($s12->mulInt(136657, 18)); $s5 = $s5->subInt64($s12->mulInt(683901, 20)); $s12 = new ParagonIE_Sodium_Core32_Int64(); $carry0 = $s0->addInt(1 << 20)->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry2 = $s2->addInt(1 << 20)->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry4 = $s4->addInt(1 << 20)->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry6 = $s6->addInt(1 << 20)->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry8 = $s8->addInt(1 << 20)->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry10 = $s10->addInt(1 << 20)->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry1 = $s1->addInt(1 << 20)->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry3 = $s3->addInt(1 << 20)->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry5 = $s5->addInt(1 << 20)->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry7 = $s7->addInt(1 << 20)->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry9 = $s9->addInt(1 << 20)->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry11 = $s11->addInt(1 << 20)->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $s0 = $s0->addInt64($s12->mulInt(666643, 20)); $s1 = $s1->addInt64($s12->mulInt(470296, 19)); $s2 = $s2->addInt64($s12->mulInt(654183, 20)); $s3 = $s3->subInt64($s12->mulInt(997805, 20)); $s4 = $s4->addInt64($s12->mulInt(136657, 18)); $s5 = $s5->subInt64($s12->mulInt(683901, 20)); $s12 = new ParagonIE_Sodium_Core32_Int64(); $carry0 = $s0->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry1 = $s1->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry2 = $s2->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry3 = $s3->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry4 = $s4->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry5 = $s5->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry6 = $s6->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry7 = $s7->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry8 = $s8->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry9 = $s9->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry10 = $s10->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $carry11 = $s11->shiftRight(21); $s12 = $s12->addInt64($carry11); $s11 = $s11->subInt64($carry11->shiftLeft(21)); $s0 = $s0->addInt64($s12->mulInt(666643, 20)); $s1 = $s1->addInt64($s12->mulInt(470296, 19)); $s2 = $s2->addInt64($s12->mulInt(654183, 20)); $s3 = $s3->subInt64($s12->mulInt(997805, 20)); $s4 = $s4->addInt64($s12->mulInt(136657, 18)); $s5 = $s5->subInt64($s12->mulInt(683901, 20)); $carry0 = $s0->shiftRight(21); $s1 = $s1->addInt64($carry0); $s0 = $s0->subInt64($carry0->shiftLeft(21)); $carry1 = $s1->shiftRight(21); $s2 = $s2->addInt64($carry1); $s1 = $s1->subInt64($carry1->shiftLeft(21)); $carry2 = $s2->shiftRight(21); $s3 = $s3->addInt64($carry2); $s2 = $s2->subInt64($carry2->shiftLeft(21)); $carry3 = $s3->shiftRight(21); $s4 = $s4->addInt64($carry3); $s3 = $s3->subInt64($carry3->shiftLeft(21)); $carry4 = $s4->shiftRight(21); $s5 = $s5->addInt64($carry4); $s4 = $s4->subInt64($carry4->shiftLeft(21)); $carry5 = $s5->shiftRight(21); $s6 = $s6->addInt64($carry5); $s5 = $s5->subInt64($carry5->shiftLeft(21)); $carry6 = $s6->shiftRight(21); $s7 = $s7->addInt64($carry6); $s6 = $s6->subInt64($carry6->shiftLeft(21)); $carry7 = $s7->shiftRight(21); $s8 = $s8->addInt64($carry7); $s7 = $s7->subInt64($carry7->shiftLeft(21)); $carry8 = $s8->shiftRight(21); $s9 = $s9->addInt64($carry8); $s8 = $s8->subInt64($carry8->shiftLeft(21)); $carry9 = $s9->shiftRight(21); $s10 = $s10->addInt64($carry9); $s9 = $s9->subInt64($carry9->shiftLeft(21)); $carry10 = $s10->shiftRight(21); $s11 = $s11->addInt64($carry10); $s10 = $s10->subInt64($carry10->shiftLeft(21)); $S0 = $s0->toInt32()->toInt(); $S1 = $s1->toInt32()->toInt(); $S2 = $s2->toInt32()->toInt(); $S3 = $s3->toInt32()->toInt(); $S4 = $s4->toInt32()->toInt(); $S5 = $s5->toInt32()->toInt(); $S6 = $s6->toInt32()->toInt(); $S7 = $s7->toInt32()->toInt(); $S8 = $s8->toInt32()->toInt(); $S9 = $s9->toInt32()->toInt(); $S10 = $s10->toInt32()->toInt(); $S11 = $s11->toInt32()->toInt(); /** * @var array<int, int> */ $arr = array( (int) ($S0 >> 0), (int) ($S0 >> 8), (int) (($S0 >> 16) | ($S1 << 5)), (int) ($S1 >> 3), (int) ($S1 >> 11), (int) (($S1 >> 19) | ($S2 << 2)), (int) ($S2 >> 6), (int) (($S2 >> 14) | ($S3 << 7)), (int) ($S3 >> 1), (int) ($S3 >> 9), (int) (($S3 >> 17) | ($S4 << 4)), (int) ($S4 >> 4), (int) ($S4 >> 12), (int) (($S4 >> 20) | ($S5 << 1)), (int) ($S5 >> 7), (int) (($S5 >> 15) | ($S6 << 6)), (int) ($S6 >> 2), (int) ($S6 >> 10), (int) (($S6 >> 18) | ($S7 << 3)), (int) ($S7 >> 5), (int) ($S7 >> 13), (int) ($S8 >> 0), (int) ($S8 >> 8), (int) (($S8 >> 16) | ($S9 << 5)), (int) ($S9 >> 3), (int) ($S9 >> 11), (int) (($S9 >> 19) | ($S10 << 2)), (int) ($S10 >> 6), (int) (($S10 >> 14) | ($S11 << 7)), (int) ($S11 >> 1), (int) ($S11 >> 9), (int) $S11 >> 17 ); return self::intArrayToString($arr); } /** * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 * * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A * @return ParagonIE_Sodium_Core32_Curve25519_Ge_P3 * @throws SodiumException * @throws TypeError */ public static function ge_mul_l(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A) { $aslide = array( 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ); /** @var array<int, ParagonIE_Sodium_Core32_Curve25519_Ge_Cached> $Ai size 8 */ $Ai = array(); # ge_p3_to_cached(&Ai[0], A); $Ai[0] = self::ge_p3_to_cached($A); # ge_p3_dbl(&t, A); $t = self::ge_p3_dbl($A); # ge_p1p1_to_p3(&A2, &t); $A2 = self::ge_p1p1_to_p3($t); for ($i = 1; $i < 8; ++$i) { # ge_add(&t, &A2, &Ai[0]); $t = self::ge_add($A2, $Ai[$i - 1]); # ge_p1p1_to_p3(&u, &t); $u = self::ge_p1p1_to_p3($t); # ge_p3_to_cached(&Ai[i], &u); $Ai[$i] = self::ge_p3_to_cached($u); } $r = self::ge_p3_0(); for ($i = 252; $i >= 0; --$i) { $t = self::ge_p3_dbl($r); if ($aslide[$i] > 0) { # ge_p1p1_to_p3(&u, &t); $u = self::ge_p1p1_to_p3($t); # ge_add(&t, &u, &Ai[aslide[i] / 2]); $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]); } elseif ($aslide[$i] < 0) { # ge_p1p1_to_p3(&u, &t); $u = self::ge_p1p1_to_p3($t); # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]); } } # ge_p1p1_to_p3(r, &t); return self::ge_p1p1_to_p3($t); } } ��������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/Ge/P3.php�������������������������������������������������������������������������0000644�����������������00000003242�15021200076�0010613 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P3', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_Ge_P3 */ class ParagonIE_Sodium_Core32_Curve25519_Ge_P3 { /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $T; /** * ParagonIE_Sodium_Core32_Curve25519_Ge_P3 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t */ public function __construct( ParagonIE_Sodium_Core32_Curve25519_Fe $x = null, ParagonIE_Sodium_Core32_Curve25519_Fe $y = null, ParagonIE_Sodium_Core32_Curve25519_Fe $z = null, ParagonIE_Sodium_Core32_Curve25519_Fe $t = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->Z = $z; if ($t === null) { $t = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->T = $t; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/Ge/P2.php�������������������������������������������������������������������������0000644�����������������00000002541�15021200076�0010613 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P2', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_Ge_P2 */ class ParagonIE_Sodium_Core32_Curve25519_Ge_P2 { /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Z; /** * ParagonIE_Sodium_Core32_Curve25519_Ge_P2 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z */ public function __construct( ParagonIE_Sodium_Core32_Curve25519_Fe $x = null, ParagonIE_Sodium_Core32_Curve25519_Fe $y = null, ParagonIE_Sodium_Core32_Curve25519_Fe $z = null ) { if ($x === null) { $x = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->X = $x; if ($y === null) { $y = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->Y = $y; if ($z === null) { $z = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->Z = $z; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/Ge/P1p1.php�����������������������������������������������������������������������0000644�����������������00000003344�15021200076�0011055 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 */ class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 { /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $X; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Y; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $T; /** * ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t * * @throws SodiumException * @throws TypeError */ public function __construct( ParagonIE_Sodium_Core32_Curve25519_Fe $x = null, ParagonIE_Sodium_Core32_Curve25519_Fe $y = null, ParagonIE_Sodium_Core32_Curve25519_Fe $z = null, ParagonIE_Sodium_Core32_Curve25519_Fe $t = null ) { if ($x === null) { $x = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->X = $x; if ($y === null) { $y = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->Y = $y; if ($z === null) { $z = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->Z = $z; if ($t === null) { $t = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->T = $t; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/Ge/Precomp.php��������������������������������������������������������������������0000644�����������������00000002775�15021200076�0011750 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp */ class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp { /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $yplusx; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $yminusx; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $xy2d; /** * ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx * @param ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx * @param ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d * @throws SodiumException * @throws TypeError */ public function __construct( ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx = null, ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx = null, ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d = null ) { if ($yplusx === null) { $yplusx = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->yplusx = $yplusx; if ($yminusx === null) { $yminusx = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->yminusx = $yminusx; if ($xy2d === null) { $xy2d = ParagonIE_Sodium_Core32_Curve25519::fe_0(); } $this->xy2d = $xy2d; } } ���Core32/Curve25519/Ge/Cached.php���������������������������������������������������������������������0000644�����������������00000003415�15021200076�0011502 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Cached', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached */ class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached { /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $YplusX; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $YminusX; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $Z; /** * @var ParagonIE_Sodium_Core32_Curve25519_Fe */ public $T2d; /** * ParagonIE_Sodium_Core32_Curve25519_Ge_Cached constructor. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YplusX * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YminusX * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $Z * @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $T2d */ public function __construct( ParagonIE_Sodium_Core32_Curve25519_Fe $YplusX = null, ParagonIE_Sodium_Core32_Curve25519_Fe $YminusX = null, ParagonIE_Sodium_Core32_Curve25519_Fe $Z = null, ParagonIE_Sodium_Core32_Curve25519_Fe $T2d = null ) { if ($YplusX === null) { $YplusX = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->YplusX = $YplusX; if ($YminusX === null) { $YminusX = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->YminusX = $YminusX; if ($Z === null) { $Z = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->Z = $Z; if ($T2d === null) { $T2d = new ParagonIE_Sodium_Core32_Curve25519_Fe(); } $this->T2d = $T2d; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/Fe.php����������������������������������������������������������������������������0000644�����������������00000012572�15021200076�0010336 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_Fe', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_Fe * * This represents a Field Element */ class ParagonIE_Sodium_Core32_Curve25519_Fe implements ArrayAccess { /** * @var array<int, ParagonIE_Sodium_Core32_Int32> */ protected $container = array(); /** * @var int */ protected $size = 10; /** * @internal You should not use this directly from another application * * @param array<int, ParagonIE_Sodium_Core32_Int32> $array * @param bool $save_indexes * @return self * @throws SodiumException * @throws TypeError */ public static function fromArray($array, $save_indexes = null) { $count = count($array); if ($save_indexes) { $keys = array_keys($array); } else { $keys = range(0, $count - 1); } $array = array_values($array); $obj = new ParagonIE_Sodium_Core32_Curve25519_Fe(); if ($save_indexes) { for ($i = 0; $i < $count; ++$i) { $array[$i]->overflow = 0; $obj->offsetSet($keys[$i], $array[$i]); } } else { for ($i = 0; $i < $count; ++$i) { if (!($array[$i] instanceof ParagonIE_Sodium_Core32_Int32)) { throw new TypeError('Expected ParagonIE_Sodium_Core32_Int32'); } $array[$i]->overflow = 0; $obj->offsetSet($i, $array[$i]); } } return $obj; } /** * @internal You should not use this directly from another application * * @param array<int, int> $array * @param bool $save_indexes * @return self * @throws SodiumException * @throws TypeError */ public static function fromIntArray($array, $save_indexes = null) { $count = count($array); if ($save_indexes) { $keys = array_keys($array); } else { $keys = range(0, $count - 1); } $array = array_values($array); $set = array(); /** @var int $i */ /** @var int $v */ foreach ($array as $i => $v) { $set[$i] = ParagonIE_Sodium_Core32_Int32::fromInt($v); } $obj = new ParagonIE_Sodium_Core32_Curve25519_Fe(); if ($save_indexes) { for ($i = 0; $i < $count; ++$i) { $set[$i]->overflow = 0; $obj->offsetSet($keys[$i], $set[$i]); } } else { for ($i = 0; $i < $count; ++$i) { $set[$i]->overflow = 0; $obj->offsetSet($i, $set[$i]); } } return $obj; } /** * @internal You should not use this directly from another application * * @param mixed $offset * @param mixed $value * @return void * @throws SodiumException * @throws TypeError */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if (!($value instanceof ParagonIE_Sodium_Core32_Int32)) { throw new InvalidArgumentException('Expected an instance of ParagonIE_Sodium_Core32_Int32'); } if (is_null($offset)) { $this->container[] = $value; } else { ParagonIE_Sodium_Core32_Util::declareScalarType($offset, 'int', 1); $this->container[(int) $offset] = $value; } } /** * @internal You should not use this directly from another application * * @param mixed $offset * @return bool * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param mixed $offset * @return void * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param mixed $offset * @return ParagonIE_Sodium_Core32_Int32 * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetGet($offset) { if (!isset($this->container[$offset])) { $this->container[(int) $offset] = new ParagonIE_Sodium_Core32_Int32(); } /** @var ParagonIE_Sodium_Core32_Int32 $get */ $get = $this->container[$offset]; return $get; } /** * @internal You should not use this directly from another application * * @return array */ public function __debugInfo() { if (empty($this->container)) { return array(); } $c = array( (int) ($this->container[0]->toInt()), (int) ($this->container[1]->toInt()), (int) ($this->container[2]->toInt()), (int) ($this->container[3]->toInt()), (int) ($this->container[4]->toInt()), (int) ($this->container[5]->toInt()), (int) ($this->container[6]->toInt()), (int) ($this->container[7]->toInt()), (int) ($this->container[8]->toInt()), (int) ($this->container[9]->toInt()) ); return array(implode(', ', $c)); } } ��������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/README.md�������������������������������������������������������������������������0000644�����������������00000000332�15021200076�0010541 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Curve25519 Data Structures These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h). ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Curve25519/H.php�����������������������������������������������������������������������������0000644�����������������00000324375�15021200076�0010202 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Curve25519_H', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Curve25519_H * * This just contains the constants in the ref10/base.h file */ class ParagonIE_Sodium_Core32_Curve25519_H extends ParagonIE_Sodium_Core32_Util { /** * See: libsodium's crypto_core/curve25519/ref10/base.h * * @var array<int, array<int, array<int, array<int, int>>>> Basically, int[32][8][3][10] */ protected static $base = array( array( array( array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605), array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378), array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546), ), array( array(-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303), array(-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081), array(26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697), ), array( array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024), array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574), array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357), ), array( array(-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540), array(23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397), array(7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325), ), array( array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380), array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306), array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942), ), array( array(-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777), array(-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737), array(-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652), ), array( array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766), array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701), array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300), ), array( array(14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726), array(-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955), array(27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425), ), ), array( array( array(-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171), array(27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510), array(17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660), ), array( array(-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639), array(29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963), array(5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950), ), array( array(-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568), array(12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335), array(25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628), ), array( array(-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007), array(-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772), array(-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653), ), array( array(2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567), array(13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686), array(21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372), ), array( array(-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887), array(-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954), array(-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953), ), array( array(24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833), array(-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532), array(-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876), ), array( array(2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268), array(33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214), array(1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038), ), ), array( array( array(6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800), array(4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645), array(-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664), ), array( array(1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933), array(-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182), array(-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222), ), array( array(-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991), array(20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880), array(9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092), ), array( array(-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295), array(19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788), array(8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553), ), array( array(-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026), array(11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347), array(-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033), ), array( array(-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395), array(-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278), array(1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890), ), array( array(32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995), array(-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596), array(-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891), ), array( array(31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060), array(11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608), array(-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606), ), ), array( array( array(7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389), array(-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016), array(-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341), ), array( array(-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505), array(14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553), array(-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655), ), array( array(15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220), array(12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631), array(-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099), ), array( array(26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556), array(14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749), array(236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930), ), array( array(1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391), array(5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253), array(20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066), ), array( array(24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958), array(-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082), array(-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383), ), array( array(-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521), array(-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807), array(23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948), ), array( array(9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134), array(-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455), array(27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629), ), ), array( array( array(-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069), array(-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746), array(24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919), ), array( array(11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837), array(8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906), array(-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771), ), array( array(-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817), array(10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098), array(10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409), ), array( array(-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504), array(-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727), array(28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420), ), array( array(-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003), array(-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605), array(-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384), ), array( array(-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701), array(-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683), array(29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708), ), array( array(-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563), array(-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260), array(-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387), ), array( array(-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672), array(23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686), array(-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665), ), ), array( array( array(11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182), array(-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277), array(14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628), ), array( array(-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474), array(-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539), array(-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822), ), array( array(-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970), array(19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756), array(-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508), ), array( array(-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683), array(-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655), array(-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158), ), array( array(-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125), array(-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839), array(-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664), ), array( array(27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294), array(-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899), array(-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070), ), array( array(3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294), array(-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949), array(-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083), ), array( array(31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420), array(-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940), array(29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396), ), ), array( array( array(-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567), array(20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127), array(-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294), ), array( array(-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887), array(22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964), array(16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195), ), array( array(9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244), array(24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999), array(-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762), ), array( array(-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274), array(-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236), array(-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605), ), array( array(-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761), array(-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884), array(-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482), ), array( array(-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638), array(-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490), array(-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170), ), array( array(5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736), array(10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124), array(-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392), ), array( array(8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029), array(6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048), array(28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958), ), ), array( array( array(24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593), array(26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071), array(-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692), ), array( array(11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687), array(-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441), array(-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001), ), array( array(-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460), array(-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007), array(-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762), ), array( array(15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005), array(-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674), array(4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035), ), array( array(7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590), array(-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957), array(-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812), ), array( array(33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740), array(-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122), array(-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158), ), array( array(8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885), array(26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140), array(19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857), ), array( array(801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155), array(19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260), array(19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483), ), ), array( array( array(-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677), array(32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815), array(22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751), ), array( array(-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203), array(-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208), array(1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230), ), array( array(16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850), array(-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389), array(-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968), ), array( array(-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689), array(14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880), array(5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304), ), array( array(30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632), array(-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412), array(20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566), ), array( array(-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038), array(-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232), array(-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943), ), array( array(17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856), array(23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738), array(15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971), ), array( array(-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718), array(-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697), array(-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883), ), ), array( array( array(5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912), array(-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358), array(3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849), ), array( array(29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307), array(-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977), array(-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335), ), array( array(-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644), array(-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616), array(-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735), ), array( array(-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099), array(29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341), array(-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336), ), array( array(-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646), array(31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425), array(-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388), ), array( array(-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743), array(-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822), array(-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462), ), array( array(18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985), array(9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702), array(-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797), ), array( array(21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293), array(27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100), array(19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688), ), ), array( array( array(12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186), array(2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610), array(-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707), ), array( array(7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220), array(915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025), array(32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044), ), array( array(32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992), array(-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027), array(21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197), ), array( array(8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901), array(31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952), array(19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878), ), array( array(-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390), array(32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730), array(2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730), ), array( array(-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180), array(-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272), array(-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715), ), array( array(-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970), array(-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772), array(-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865), ), array( array(15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750), array(20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373), array(32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348), ), ), array( array( array(9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144), array(-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195), array(5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086), ), array( array(-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684), array(-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518), array(-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233), ), array( array(-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793), array(-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794), array(580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435), ), array( array(23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921), array(13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518), array(2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563), ), array( array(14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278), array(-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024), array(4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030), ), array( array(10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783), array(27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717), array(6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844), ), array( array(14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333), array(16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048), array(22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760), ), array( array(-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760), array(-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757), array(-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112), ), ), array( array( array(-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468), array(3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184), array(10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289), ), array( array(15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066), array(24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882), array(13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226), ), array( array(16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101), array(29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279), array(-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811), ), array( array(27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709), array(20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714), array(-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121), ), array( array(9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464), array(12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847), array(13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400), ), array( array(4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414), array(-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158), array(17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045), ), array( array(-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415), array(-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459), array(-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079), ), array( array(21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412), array(-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743), array(-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836), ), ), array( array( array(12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022), array(18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429), array(-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065), ), array( array(30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861), array(10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000), array(-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101), ), array( array(32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815), array(29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642), array(10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966), ), array( array(25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574), array(-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742), array(-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689), ), array( array(12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020), array(-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772), array(3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982), ), array( array(-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953), array(-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218), array(-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265), ), array( array(29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073), array(-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325), array(-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798), ), array( array(-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870), array(-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863), array(-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927), ), ), array( array( array(-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267), array(-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663), array(22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862), ), array( array(-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673), array(15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943), array(15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020), ), array( array(-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238), array(11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064), array(14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795), ), array( array(15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052), array(-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904), array(29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531), ), array( array(-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979), array(-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841), array(10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431), ), array( array(10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324), array(-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940), array(10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320), ), array( array(-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184), array(14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114), array(30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878), ), array( array(12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784), array(-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091), array(-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585), ), ), array( array( array(-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208), array(10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864), array(17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661), ), array( array(7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233), array(26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212), array(-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525), ), array( array(-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068), array(9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397), array(-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988), ), array( array(5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889), array(32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038), array(14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697), ), array( array(20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875), array(-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905), array(-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656), ), array( array(11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818), array(27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714), array(10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203), ), array( array(20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931), array(-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024), array(-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084), ), array( array(-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204), array(20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817), array(27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667), ), ), array( array( array(11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504), array(-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768), array(-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255), ), array( array(6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790), array(1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438), array(-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333), ), array( array(17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971), array(31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905), array(29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409), ), array( array(12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409), array(6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499), array(-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363), ), array( array(28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664), array(-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324), array(-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940), ), array( array(13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990), array(-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914), array(-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290), ), array( array(24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257), array(-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433), array(-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236), ), array( array(-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045), array(11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093), array(-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347), ), ), array( array( array(-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191), array(-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507), array(-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906), ), array( array(3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018), array(-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109), array(-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926), ), array( array(-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528), array(8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625), array(-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286), ), array( array(2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033), array(27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866), array(21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896), ), array( array(30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075), array(26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347), array(-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437), ), array( array(-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165), array(-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588), array(-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193), ), array( array(-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017), array(-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883), array(21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961), ), array( array(8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043), array(29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663), array(-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362), ), ), array( array( array(-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860), array(2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466), array(-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063), ), array( array(-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997), array(-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295), array(-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369), ), array( array(9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385), array(18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109), array(2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906), ), array( array(4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424), array(-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185), array(7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962), ), array( array(-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325), array(10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593), array(696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404), ), array( array(-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644), array(17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801), array(26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804), ), array( array(-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884), array(-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577), array(-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849), ), array( array(32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473), array(-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644), array(-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319), ), ), array( array( array(-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599), array(-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768), array(-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084), ), array( array(-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328), array(-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369), array(20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920), ), array( array(12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815), array(-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025), array(-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397), ), array( array(-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448), array(6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981), array(30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165), ), array( array(32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501), array(17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073), array(-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861), ), array( array(14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845), array(-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211), array(18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870), ), array( array(10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096), array(33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803), array(-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168), ), array( array(30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965), array(-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505), array(18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598), ), ), array( array( array(5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782), array(5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900), array(-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479), ), array( array(-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208), array(8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232), array(17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719), ), array( array(16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271), array(-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326), array(-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132), ), array( array(14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300), array(8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570), array(15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670), ), array( array(-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994), array(-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913), array(31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317), ), array( array(-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730), array(842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096), array(-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078), ), array( array(-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411), array(-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905), array(-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654), ), array( array(-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870), array(-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498), array(12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579), ), ), array( array( array(14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677), array(10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647), array(-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743), ), array( array(-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468), array(21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375), array(-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155), ), array( array(6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725), array(-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612), array(-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943), ), array( array(-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944), array(30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928), array(9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406), ), array( array(22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139), array(-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963), array(-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693), ), array( array(1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734), array(-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680), array(-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410), ), array( array(-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931), array(-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654), array(22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710), ), array( array(29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180), array(-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684), array(-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895), ), ), array( array( array(22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501), array(-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413), array(6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880), ), array( array(-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874), array(22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962), array(-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899), ), array( array(21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152), array(9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063), array(7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080), ), array( array(-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146), array(-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183), array(-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133), ), array( array(-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421), array(-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622), array(-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197), ), array( array(2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663), array(31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753), array(4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755), ), array( array(-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862), array(-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118), array(26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171), ), array( array(15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380), array(16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824), array(28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270), ), ), array( array( array(-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438), array(-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584), array(-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562), ), array( array(30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471), array(18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610), array(19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269), ), array( array(-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650), array(14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369), array(19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461), ), array( array(30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462), array(-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793), array(-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218), ), array( array(-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226), array(18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019), array(-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037), ), array( array(31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171), array(-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132), array(-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841), ), array( array(21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181), array(-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210), array(-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040), ), array( array(3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935), array(24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105), array(-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814), ), ), array( array( array(793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852), array(5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581), array(-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646), ), array( array(10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844), array(10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025), array(27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453), ), array( array(-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068), array(4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192), array(-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921), ), array( array(-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259), array(-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426), array(-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072), ), array( array(-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305), array(13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832), array(28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943), ), array( array(-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011), array(24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447), array(17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494), ), array( array(-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245), array(-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859), array(28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915), ), array( array(16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707), array(10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848), array(-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224), ), ), array( array( array(-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391), array(15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215), array(-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101), ), array( array(23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713), array(21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849), array(-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930), ), array( array(-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940), array(-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031), array(-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404), ), array( array(-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243), array(-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116), array(-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525), ), array( array(-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509), array(-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883), array(15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865), ), array( array(-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660), array(4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273), array(-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138), ), array( array(-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560), array(-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135), array(2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941), ), array( array(-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739), array(18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756), array(-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819), ), ), array( array( array(-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347), array(-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028), array(21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075), ), array( array(16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799), array(-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609), array(-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817), ), array( array(-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989), array(-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523), array(4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278), ), array( array(31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045), array(19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377), array(24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480), ), array( array(17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016), array(510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426), array(18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525), ), array( array(13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396), array(9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080), array(12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892), ), array( array(15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275), array(11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074), array(20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140), ), array( array(-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717), array(-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101), array(24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127), ), ), array( array( array(-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632), array(-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415), array(-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160), ), array( array(31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876), array(22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625), array(-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478), ), array( array(27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164), array(26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595), array(-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248), ), array( array(-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858), array(15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193), array(8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184), ), array( array(-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942), array(-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635), array(21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948), ), array( array(11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935), array(-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415), array(-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416), ), array( array(-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018), array(4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778), array(366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659), ), array( array(-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385), array(18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503), array(476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329), ), ), array( array( array(20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056), array(-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838), array(24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948), ), array( array(-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691), array(-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118), array(-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517), ), array( array(-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269), array(-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904), array(-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589), ), array( array(-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193), array(-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910), array(-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930), ), array( array(-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667), array(25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481), array(-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876), ), array( array(22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640), array(-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278), array(-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112), ), array( array(26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272), array(17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012), array(-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221), ), array( array(30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046), array(13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345), array(-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310), ), ), array( array( array(19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937), array(31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636), array(-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008), ), array( array(-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429), array(-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576), array(31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066), ), array( array(-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490), array(-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104), array(33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053), ), array( array(31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275), array(-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511), array(22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095), ), array( array(-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439), array(23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939), array(-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424), ), array( array(2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310), array(3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608), array(-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079), ), array( array(-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101), array(21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418), array(18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576), ), array( array(30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356), array(9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996), array(-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099), ), ), array( array( array(-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728), array(-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658), array(-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242), ), array( array(-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001), array(-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766), array(18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373), ), array( array(26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458), array(-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628), array(-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657), ), array( array(-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062), array(25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616), array(31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014), ), array( array(24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383), array(-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814), array(-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718), ), array( array(30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417), array(2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222), array(33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444), ), array( array(-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597), array(23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970), array(1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799), ), array( array(-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647), array(13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511), array(-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032), ), ), array( array( array(9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834), array(-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461), array(29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062), ), array( array(-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516), array(-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547), array(-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240), ), array( array(-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038), array(-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741), array(16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103), ), array( array(-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747), array(-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323), array(31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016), ), array( array(-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373), array(15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228), array(-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141), ), array( array(16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399), array(11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831), array(-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376), ), array( array(-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313), array(-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958), array(-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577), ), array( array(-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743), array(29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684), array(-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476), ), ) ); /** * See: libsodium's crypto_core/curve25519/ref10/base2.h * * @var array<int, array<int, array<int, int>>> basically int[8][3] */ protected static $base2 = array( array( array(25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605), array(-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378), array(-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546), ), array( array(15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024), array(16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574), array(30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357), ), array( array(10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380), array(4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306), array(19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942), ), array( array(5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766), array(-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701), array(28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300), ), array( array(-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877), array(-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951), array(4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784), ), array( array(-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436), array(25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918), array(23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877), ), array( array(-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800), array(-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305), array(-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300), ), array( array(-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876), array(-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619), array(-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683), ) ); /** * 37095705934669439343138083508754565189542113879843219016388785533085940283555 * * @var array<int, int> */ protected static $d = array( -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 ); /** * 2 * d = 16295367250680780974490674513165176452449235426866156013048779062215315747161 * * @var array<int, int> */ protected static $d2 = array( -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 ); /** * sqrt(-1) * * @var array<int, int> */ protected static $sqrtm1 = array( -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 ); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/HSalsa20.php���������������������������������������������������������������������������������0000644�����������������00000015435�15021200076�0007630 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_HSalsa20', false)) { return; } /** * Class ParagonIE_Sodium_Core32_HSalsa20 */ abstract class ParagonIE_Sodium_Core32_HSalsa20 extends ParagonIE_Sodium_Core32_Salsa20 { /** * Calculate an hsalsa20 hash of a single block * * HSalsa20 doesn't have a counter and will never be used for more than * one block (used to derive a subkey for xsalsa20). * * @internal You should not use this directly from another application * * @param string $in * @param string $k * @param string|null $c * @return string * @throws SodiumException * @throws TypeError */ public static function hsalsa20($in, $k, $c = null) { /** * @var ParagonIE_Sodium_Core32_Int32 $x0 * @var ParagonIE_Sodium_Core32_Int32 $x1 * @var ParagonIE_Sodium_Core32_Int32 $x2 * @var ParagonIE_Sodium_Core32_Int32 $x3 * @var ParagonIE_Sodium_Core32_Int32 $x4 * @var ParagonIE_Sodium_Core32_Int32 $x5 * @var ParagonIE_Sodium_Core32_Int32 $x6 * @var ParagonIE_Sodium_Core32_Int32 $x7 * @var ParagonIE_Sodium_Core32_Int32 $x8 * @var ParagonIE_Sodium_Core32_Int32 $x9 * @var ParagonIE_Sodium_Core32_Int32 $x10 * @var ParagonIE_Sodium_Core32_Int32 $x11 * @var ParagonIE_Sodium_Core32_Int32 $x12 * @var ParagonIE_Sodium_Core32_Int32 $x13 * @var ParagonIE_Sodium_Core32_Int32 $x14 * @var ParagonIE_Sodium_Core32_Int32 $x15 * @var ParagonIE_Sodium_Core32_Int32 $j0 * @var ParagonIE_Sodium_Core32_Int32 $j1 * @var ParagonIE_Sodium_Core32_Int32 $j2 * @var ParagonIE_Sodium_Core32_Int32 $j3 * @var ParagonIE_Sodium_Core32_Int32 $j4 * @var ParagonIE_Sodium_Core32_Int32 $j5 * @var ParagonIE_Sodium_Core32_Int32 $j6 * @var ParagonIE_Sodium_Core32_Int32 $j7 * @var ParagonIE_Sodium_Core32_Int32 $j8 * @var ParagonIE_Sodium_Core32_Int32 $j9 * @var ParagonIE_Sodium_Core32_Int32 $j10 * @var ParagonIE_Sodium_Core32_Int32 $j11 * @var ParagonIE_Sodium_Core32_Int32 $j12 * @var ParagonIE_Sodium_Core32_Int32 $j13 * @var ParagonIE_Sodium_Core32_Int32 $j14 * @var ParagonIE_Sodium_Core32_Int32 $j15 */ if (self::strlen($k) < 32) { throw new RangeException('Key must be 32 bytes long'); } if ($c === null) { $x0 = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865)); $x5 = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e)); $x10 = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32)); $x15 = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574)); } else { $x0 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4)); $x5 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4)); $x10 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4)); $x15 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4)); } $x1 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4)); $x2 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4)); $x3 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4)); $x4 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4)); $x6 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4)); $x7 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4)); $x8 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4)); $x9 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4)); $x11 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4)); $x12 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4)); $x13 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4)); $x14 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4)); for ($i = self::ROUNDS; $i > 0; $i -= 2) { $x4 = $x4->xorInt32($x0->addInt32($x12)->rotateLeft(7)); $x8 = $x8->xorInt32($x4->addInt32($x0)->rotateLeft(9)); $x12 = $x12->xorInt32($x8->addInt32($x4)->rotateLeft(13)); $x0 = $x0->xorInt32($x12->addInt32($x8)->rotateLeft(18)); $x9 = $x9->xorInt32($x5->addInt32($x1)->rotateLeft(7)); $x13 = $x13->xorInt32($x9->addInt32($x5)->rotateLeft(9)); $x1 = $x1->xorInt32($x13->addInt32($x9)->rotateLeft(13)); $x5 = $x5->xorInt32($x1->addInt32($x13)->rotateLeft(18)); $x14 = $x14->xorInt32($x10->addInt32($x6)->rotateLeft(7)); $x2 = $x2->xorInt32($x14->addInt32($x10)->rotateLeft(9)); $x6 = $x6->xorInt32($x2->addInt32($x14)->rotateLeft(13)); $x10 = $x10->xorInt32($x6->addInt32($x2)->rotateLeft(18)); $x3 = $x3->xorInt32($x15->addInt32($x11)->rotateLeft(7)); $x7 = $x7->xorInt32($x3->addInt32($x15)->rotateLeft(9)); $x11 = $x11->xorInt32($x7->addInt32($x3)->rotateLeft(13)); $x15 = $x15->xorInt32($x11->addInt32($x7)->rotateLeft(18)); $x1 = $x1->xorInt32($x0->addInt32($x3)->rotateLeft(7)); $x2 = $x2->xorInt32($x1->addInt32($x0)->rotateLeft(9)); $x3 = $x3->xorInt32($x2->addInt32($x1)->rotateLeft(13)); $x0 = $x0->xorInt32($x3->addInt32($x2)->rotateLeft(18)); $x6 = $x6->xorInt32($x5->addInt32($x4)->rotateLeft(7)); $x7 = $x7->xorInt32($x6->addInt32($x5)->rotateLeft(9)); $x4 = $x4->xorInt32($x7->addInt32($x6)->rotateLeft(13)); $x5 = $x5->xorInt32($x4->addInt32($x7)->rotateLeft(18)); $x11 = $x11->xorInt32($x10->addInt32($x9)->rotateLeft(7)); $x8 = $x8->xorInt32($x11->addInt32($x10)->rotateLeft(9)); $x9 = $x9->xorInt32($x8->addInt32($x11)->rotateLeft(13)); $x10 = $x10->xorInt32($x9->addInt32($x8)->rotateLeft(18)); $x12 = $x12->xorInt32($x15->addInt32($x14)->rotateLeft(7)); $x13 = $x13->xorInt32($x12->addInt32($x15)->rotateLeft(9)); $x14 = $x14->xorInt32($x13->addInt32($x12)->rotateLeft(13)); $x15 = $x15->xorInt32($x14->addInt32($x13)->rotateLeft(18)); } return $x0->toReverseString() . $x5->toReverseString() . $x10->toReverseString() . $x15->toReverseString() . $x6->toReverseString() . $x7->toReverseString() . $x8->toReverseString() . $x9->toReverseString(); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Poly1305.php���������������������������������������������������������������������������������0000644�����������������00000003062�15021200076�0007540 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Poly1305', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Poly1305 */ abstract class ParagonIE_Sodium_Core32_Poly1305 extends ParagonIE_Sodium_Core32_Util { const BLOCK_SIZE = 16; /** * @internal You should not use this directly from another application * * @param string $m * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function onetimeauth($m, $key) { if (self::strlen($key) < 32) { throw new InvalidArgumentException( 'Key must be 32 bytes long.' ); } $state = new ParagonIE_Sodium_Core32_Poly1305_State( self::substr($key, 0, 32) ); return $state ->update($m) ->finish(); } /** * @internal You should not use this directly from another application * * @param string $mac * @param string $m * @param string $key * @return bool * @throws SodiumException * @throws TypeError */ public static function onetimeauth_verify($mac, $m, $key) { if (self::strlen($key) < 32) { throw new InvalidArgumentException( 'Key must be 32 bytes long.' ); } $state = new ParagonIE_Sodium_Core32_Poly1305_State( self::substr($key, 0, 32) ); $calc = $state ->update($m) ->finish(); return self::verify_16($calc, $mac); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Ed25519.php����������������������������������������������������������������������������������0000644�����������������00000036567�15021200076�0007262 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Ed25519', false)) { return; } if (!class_exists('ParagonIE_Sodium_Core32_Curve25519')) { require_once dirname(__FILE__) . '/Curve25519.php'; } /** * Class ParagonIE_Sodium_Core32_Ed25519 */ abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_Curve25519 { const KEYPAIR_BYTES = 96; const SEED_BYTES = 32; /** * @internal You should not use this directly from another application * * @return string (96 bytes) * @throws Exception * @throws SodiumException * @throws TypeError */ public static function keypair() { $seed = random_bytes(self::SEED_BYTES); $pk = ''; $sk = ''; self::seed_keypair($pk, $sk, $seed); return $sk . $pk; } /** * @internal You should not use this directly from another application * * @param string $pk * @param string $sk * @param string $seed * @return string * @throws SodiumException * @throws TypeError */ public static function seed_keypair(&$pk, &$sk, $seed) { if (self::strlen($seed) !== self::SEED_BYTES) { throw new RangeException('crypto_sign keypair seed must be 32 bytes long'); } /** @var string $pk */ $pk = self::publickey_from_secretkey($seed); $sk = $seed . $pk; return $sk; } /** * @internal You should not use this directly from another application * * @param string $keypair * @return string * @throws TypeError */ public static function secretkey($keypair) { if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { throw new RangeException('crypto_sign keypair must be 96 bytes long'); } return self::substr($keypair, 0, 64); } /** * @internal You should not use this directly from another application * * @param string $keypair * @return string * @throws RangeException * @throws TypeError */ public static function publickey($keypair) { if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { throw new RangeException('crypto_sign keypair must be 96 bytes long'); } return self::substr($keypair, 64, 32); } /** * @internal You should not use this directly from another application * * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function publickey_from_secretkey($sk) { /** @var string $sk */ $sk = hash('sha512', self::substr($sk, 0, 32), true); $sk[0] = self::intToChr( self::chrToInt($sk[0]) & 248 ); $sk[31] = self::intToChr( (self::chrToInt($sk[31]) & 63) | 64 ); return self::sk_to_pk($sk); } /** * @param string $pk * @return string * @throws SodiumException * @throws TypeError */ public static function pk_to_curve25519($pk) { if (self::small_order($pk)) { throw new SodiumException('Public key is on a small order'); } $A = self::ge_frombytes_negate_vartime($pk); $p1 = self::ge_mul_l($A); if (!self::fe_isnonzero($p1->X)) { throw new SodiumException('Unexpected zero result'); } # fe_1(one_minus_y); # fe_sub(one_minus_y, one_minus_y, A.Y); # fe_invert(one_minus_y, one_minus_y); $one_minux_y = self::fe_invert( self::fe_sub( self::fe_1(), $A->Y ) ); # fe_1(x); # fe_add(x, x, A.Y); # fe_mul(x, x, one_minus_y); $x = self::fe_mul( self::fe_add(self::fe_1(), $A->Y), $one_minux_y ); # fe_tobytes(curve25519_pk, x); return self::fe_tobytes($x); } /** * @internal You should not use this directly from another application * * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sk_to_pk($sk) { return self::ge_p3_tobytes( self::ge_scalarmult_base( self::substr($sk, 0, 32) ) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError */ public static function sign($message, $sk) { /** @var string $signature */ $signature = self::sign_detached($message, $sk); return $signature . $message; } /** * @internal You should not use this directly from another application * * @param string $message A signed message * @param string $pk Public key * @return string Message (without signature) * @throws SodiumException * @throws TypeError */ public static function sign_open($message, $pk) { /** @var string $signature */ $signature = self::substr($message, 0, 64); /** @var string $message */ $message = self::substr($message, 64); if (self::verify_detached($signature, $message, $pk)) { return $message; } throw new SodiumException('Invalid signature'); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $sk * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress PossiblyInvalidArgument */ public static function sign_detached($message, $sk) { # crypto_hash_sha512(az, sk, 32); $az = hash('sha512', self::substr($sk, 0, 32), true); # az[0] &= 248; # az[31] &= 63; # az[31] |= 64; $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); # crypto_hash_sha512_init(&hs); # crypto_hash_sha512_update(&hs, az + 32, 32); # crypto_hash_sha512_update(&hs, m, mlen); # crypto_hash_sha512_final(&hs, nonce); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($az, 32, 32)); self::hash_update($hs, $message); $nonceHash = hash_final($hs, true); # memmove(sig + 32, sk + 32, 32); $pk = self::substr($sk, 32, 32); # sc_reduce(nonce); # ge_scalarmult_base(&R, nonce); # ge_p3_tobytes(sig, &R); $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); $sig = self::ge_p3_tobytes( self::ge_scalarmult_base($nonce) ); # crypto_hash_sha512_init(&hs); # crypto_hash_sha512_update(&hs, sig, 64); # crypto_hash_sha512_update(&hs, m, mlen); # crypto_hash_sha512_final(&hs, hram); $hs = hash_init('sha512'); self::hash_update($hs, self::substr($sig, 0, 32)); self::hash_update($hs, self::substr($pk, 0, 32)); self::hash_update($hs, $message); $hramHash = hash_final($hs, true); # sc_reduce(hram); # sc_muladd(sig + 32, hram, az, nonce); $hram = self::sc_reduce($hramHash); $sigAfter = self::sc_muladd($hram, $az, $nonce); $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); try { ParagonIE_Sodium_Compat::memzero($az); } catch (SodiumException $ex) { $az = null; } return $sig; } /** * @internal You should not use this directly from another application * * @param string $sig * @param string $message * @param string $pk * @return bool * @throws SodiumException * @throws TypeError */ public static function verify_detached($sig, $message, $pk) { if (self::strlen($sig) < 64) { throw new SodiumException('Signature is too short'); } if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { throw new SodiumException('S < L - Invalid signature'); } if (self::small_order($sig)) { throw new SodiumException('Signature is on too small of an order'); } if ((self::chrToInt($sig[63]) & 224) !== 0) { throw new SodiumException('Invalid signature'); } $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= self::chrToInt($pk[$i]); } if ($d === 0) { throw new SodiumException('All zero public key'); } /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ $orig = ParagonIE_Sodium_Compat::$fastMult; // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. ParagonIE_Sodium_Compat::$fastMult = true; /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */ $A = self::ge_frombytes_negate_vartime($pk); /** @var string $hDigest */ $hDigest = hash( 'sha512', self::substr($sig, 0, 32) . self::substr($pk, 0, 32) . $message, true ); /** @var string $h */ $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */ $R = self::ge_double_scalarmult_vartime( $h, $A, self::substr($sig, 32) ); /** @var string $rcheck */ $rcheck = self::ge_tobytes($R); // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. ParagonIE_Sodium_Compat::$fastMult = $orig; return self::verify_32($rcheck, self::substr($sig, 0, 32)); } /** * @internal You should not use this directly from another application * * @param string $S * @return bool * @throws SodiumException * @throws TypeError */ public static function check_S_lt_L($S) { if (self::strlen($S) < 32) { throw new SodiumException('Signature must be 32 bytes'); } static $L = array( 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ); /** @var array<int, int> $L */ $c = 0; $n = 1; $i = 32; do { --$i; $x = self::chrToInt($S[$i]); $c |= ( (($x - $L[$i]) >> 8) & $n ); $n &= ( (($x ^ $L[$i]) - 1) >> 8 ); } while ($i !== 0); return $c === 0; } /** * @param string $R * @return bool * @throws SodiumException * @throws TypeError */ public static function small_order($R) { static $blocklist = array( /* 0 (order 4) */ array( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), /* 1 (order 1) */ array( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ array( 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 ), /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ array( 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a ), /* p-1 (order 2) */ array( 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 ), /* p (order 4) */ array( 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa ), /* p+1 (order 1) */ array( 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f ), /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ array( 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f ), /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ array( 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f ), /* 2p-1 (order 2) */ array( 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), /* 2p (order 4) */ array( 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), /* 2p+1 (order 1) */ array( 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ) ); /** @var array<int, array<int, int>> $blocklist */ $countBlocklist = count($blocklist); for ($i = 0; $i < $countBlocklist; ++$i) { $c = 0; for ($j = 0; $j < 32; ++$j) { $c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j]; } if ($c === 0) { return true; } } return false; } } �����������������������������������������������������������������������������������������������������������������������������������������Core32/Salsa20.php����������������������������������������������������������������������������������0000644�����������������00000026362�15021200076�0007521 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Salsa20', false)) { return; } /** * Class ParagonIE_Sodium_Core32_Salsa20 */ abstract class ParagonIE_Sodium_Core32_Salsa20 extends ParagonIE_Sodium_Core32_Util { const ROUNDS = 20; /** * Calculate an salsa20 hash of a single block * * @internal You should not use this directly from another application * * @param string $in * @param string $k * @param string|null $c * @return string * @throws SodiumException * @throws TypeError */ public static function core_salsa20($in, $k, $c = null) { /** * @var ParagonIE_Sodium_Core32_Int32 $x0 * @var ParagonIE_Sodium_Core32_Int32 $x1 * @var ParagonIE_Sodium_Core32_Int32 $x2 * @var ParagonIE_Sodium_Core32_Int32 $x3 * @var ParagonIE_Sodium_Core32_Int32 $x4 * @var ParagonIE_Sodium_Core32_Int32 $x5 * @var ParagonIE_Sodium_Core32_Int32 $x6 * @var ParagonIE_Sodium_Core32_Int32 $x7 * @var ParagonIE_Sodium_Core32_Int32 $x8 * @var ParagonIE_Sodium_Core32_Int32 $x9 * @var ParagonIE_Sodium_Core32_Int32 $x10 * @var ParagonIE_Sodium_Core32_Int32 $x11 * @var ParagonIE_Sodium_Core32_Int32 $x12 * @var ParagonIE_Sodium_Core32_Int32 $x13 * @var ParagonIE_Sodium_Core32_Int32 $x14 * @var ParagonIE_Sodium_Core32_Int32 $x15 * @var ParagonIE_Sodium_Core32_Int32 $j0 * @var ParagonIE_Sodium_Core32_Int32 $j1 * @var ParagonIE_Sodium_Core32_Int32 $j2 * @var ParagonIE_Sodium_Core32_Int32 $j3 * @var ParagonIE_Sodium_Core32_Int32 $j4 * @var ParagonIE_Sodium_Core32_Int32 $j5 * @var ParagonIE_Sodium_Core32_Int32 $j6 * @var ParagonIE_Sodium_Core32_Int32 $j7 * @var ParagonIE_Sodium_Core32_Int32 $j8 * @var ParagonIE_Sodium_Core32_Int32 $j9 * @var ParagonIE_Sodium_Core32_Int32 $j10 * @var ParagonIE_Sodium_Core32_Int32 $j11 * @var ParagonIE_Sodium_Core32_Int32 $j12 * @var ParagonIE_Sodium_Core32_Int32 $j13 * @var ParagonIE_Sodium_Core32_Int32 $j14 * @var ParagonIE_Sodium_Core32_Int32 $j15 */ if (self::strlen($k) < 32) { throw new RangeException('Key must be 32 bytes long'); } if ($c === null) { $x0 = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865)); $x5 = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e)); $x10 = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32)); $x15 = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574)); } else { $x0 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4)); $x5 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4)); $x10 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4)); $x15 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4)); } $x1 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4)); $x2 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4)); $x3 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4)); $x4 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4)); $x6 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4)); $x7 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4)); $x8 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4)); $x9 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4)); $x11 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4)); $x12 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4)); $x13 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4)); $x14 = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4)); $j0 = clone $x0; $j1 = clone $x1; $j2 = clone $x2; $j3 = clone $x3; $j4 = clone $x4; $j5 = clone $x5; $j6 = clone $x6; $j7 = clone $x7; $j8 = clone $x8; $j9 = clone $x9; $j10 = clone $x10; $j11 = clone $x11; $j12 = clone $x12; $j13 = clone $x13; $j14 = clone $x14; $j15 = clone $x15; for ($i = self::ROUNDS; $i > 0; $i -= 2) { $x4 = $x4->xorInt32($x0->addInt32($x12)->rotateLeft(7)); $x8 = $x8->xorInt32($x4->addInt32($x0)->rotateLeft(9)); $x12 = $x12->xorInt32($x8->addInt32($x4)->rotateLeft(13)); $x0 = $x0->xorInt32($x12->addInt32($x8)->rotateLeft(18)); $x9 = $x9->xorInt32($x5->addInt32($x1)->rotateLeft(7)); $x13 = $x13->xorInt32($x9->addInt32($x5)->rotateLeft(9)); $x1 = $x1->xorInt32($x13->addInt32($x9)->rotateLeft(13)); $x5 = $x5->xorInt32($x1->addInt32($x13)->rotateLeft(18)); $x14 = $x14->xorInt32($x10->addInt32($x6)->rotateLeft(7)); $x2 = $x2->xorInt32($x14->addInt32($x10)->rotateLeft(9)); $x6 = $x6->xorInt32($x2->addInt32($x14)->rotateLeft(13)); $x10 = $x10->xorInt32($x6->addInt32($x2)->rotateLeft(18)); $x3 = $x3->xorInt32($x15->addInt32($x11)->rotateLeft(7)); $x7 = $x7->xorInt32($x3->addInt32($x15)->rotateLeft(9)); $x11 = $x11->xorInt32($x7->addInt32($x3)->rotateLeft(13)); $x15 = $x15->xorInt32($x11->addInt32($x7)->rotateLeft(18)); $x1 = $x1->xorInt32($x0->addInt32($x3)->rotateLeft(7)); $x2 = $x2->xorInt32($x1->addInt32($x0)->rotateLeft(9)); $x3 = $x3->xorInt32($x2->addInt32($x1)->rotateLeft(13)); $x0 = $x0->xorInt32($x3->addInt32($x2)->rotateLeft(18)); $x6 = $x6->xorInt32($x5->addInt32($x4)->rotateLeft(7)); $x7 = $x7->xorInt32($x6->addInt32($x5)->rotateLeft(9)); $x4 = $x4->xorInt32($x7->addInt32($x6)->rotateLeft(13)); $x5 = $x5->xorInt32($x4->addInt32($x7)->rotateLeft(18)); $x11 = $x11->xorInt32($x10->addInt32($x9)->rotateLeft(7)); $x8 = $x8->xorInt32($x11->addInt32($x10)->rotateLeft(9)); $x9 = $x9->xorInt32($x8->addInt32($x11)->rotateLeft(13)); $x10 = $x10->xorInt32($x9->addInt32($x8)->rotateLeft(18)); $x12 = $x12->xorInt32($x15->addInt32($x14)->rotateLeft(7)); $x13 = $x13->xorInt32($x12->addInt32($x15)->rotateLeft(9)); $x14 = $x14->xorInt32($x13->addInt32($x12)->rotateLeft(13)); $x15 = $x15->xorInt32($x14->addInt32($x13)->rotateLeft(18)); } $x0 = $x0->addInt32($j0); $x1 = $x1->addInt32($j1); $x2 = $x2->addInt32($j2); $x3 = $x3->addInt32($j3); $x4 = $x4->addInt32($j4); $x5 = $x5->addInt32($j5); $x6 = $x6->addInt32($j6); $x7 = $x7->addInt32($j7); $x8 = $x8->addInt32($j8); $x9 = $x9->addInt32($j9); $x10 = $x10->addInt32($j10); $x11 = $x11->addInt32($j11); $x12 = $x12->addInt32($j12); $x13 = $x13->addInt32($j13); $x14 = $x14->addInt32($j14); $x15 = $x15->addInt32($j15); return $x0->toReverseString() . $x1->toReverseString() . $x2->toReverseString() . $x3->toReverseString() . $x4->toReverseString() . $x5->toReverseString() . $x6->toReverseString() . $x7->toReverseString() . $x8->toReverseString() . $x9->toReverseString() . $x10->toReverseString() . $x11->toReverseString() . $x12->toReverseString() . $x13->toReverseString() . $x14->toReverseString() . $x15->toReverseString(); } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function salsa20($len, $nonce, $key) { if (self::strlen($key) !== 32) { throw new RangeException('Key must be 32 bytes long'); } $kcopy = '' . $key; $in = self::substr($nonce, 0, 8) . str_repeat("\0", 8); $c = ''; while ($len >= 64) { $c .= self::core_salsa20($in, $kcopy, null); $u = 1; // Internal counter. for ($i = 8; $i < 16; ++$i) { $u += self::chrToInt($in[$i]); $in[$i] = self::intToChr($u & 0xff); $u >>= 8; } $len -= 64; } if ($len > 0) { $c .= self::substr( self::core_salsa20($in, $kcopy, null), 0, $len ); } try { ParagonIE_Sodium_Compat::memzero($kcopy); } catch (SodiumException $ex) { $kcopy = null; } return $c; } /** * @internal You should not use this directly from another application * * @param string $m * @param string $n * @param int $ic * @param string $k * @return string * @throws SodiumException * @throws TypeError */ public static function salsa20_xor_ic($m, $n, $ic, $k) { $mlen = self::strlen($m); if ($mlen < 1) { return ''; } $kcopy = self::substr($k, 0, 32); $in = self::substr($n, 0, 8); // Initialize the counter $in .= ParagonIE_Sodium_Core32_Util::store64_le($ic); $c = ''; while ($mlen >= 64) { $block = self::core_salsa20($in, $kcopy, null); $c .= self::xorStrings( self::substr($m, 0, 64), self::substr($block, 0, 64) ); $u = 1; for ($i = 8; $i < 16; ++$i) { $u += self::chrToInt($in[$i]); $in[$i] = self::intToChr($u & 0xff); $u >>= 8; } $mlen -= 64; $m = self::substr($m, 64); } if ($mlen) { $block = self::core_salsa20($in, $kcopy, null); $c .= self::xorStrings( self::substr($m, 0, $mlen), self::substr($block, 0, $mlen) ); } try { ParagonIE_Sodium_Compat::memzero($block); ParagonIE_Sodium_Compat::memzero($kcopy); } catch (SodiumException $ex) { $block = null; $kcopy = null; } return $c; } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function salsa20_xor($message, $nonce, $key) { return self::xorStrings( $message, self::salsa20( self::strlen($message), $nonce, $key ) ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/XSalsa20.php���������������������������������������������������������������������������������0000644�����������������00000002543�15021200076�0007644 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_XSalsa20', false)) { return; } /** * Class ParagonIE_Sodium_Core32_XSalsa20 */ abstract class ParagonIE_Sodium_Core32_XSalsa20 extends ParagonIE_Sodium_Core32_HSalsa20 { /** * Expand a key and nonce into an xsalsa20 keystream. * * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function xsalsa20($len, $nonce, $key) { $ret = self::salsa20( $len, self::substr($nonce, 16, 8), self::hsalsa20($nonce, $key) ); return $ret; } /** * Encrypt a string with XSalsa20. Doesn't provide integrity. * * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function xsalsa20_xor($message, $nonce, $key) { return self::xorStrings( $message, self::xsalsa20( self::strlen($message), $nonce, $key ) ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/BLAKE2b.php����������������������������������������������������������������������������������0000644�����������������00000053464�15021200076�0007361 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) { return; } /** * Class ParagonIE_Sodium_Core_BLAKE2b * * Based on the work of Devi Mandiri in devi/salt. */ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Util { /** * @var SplFixedArray */ public static $iv; /** * @var array<int, array<int, int>> */ public static $sigma = array( array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), array( 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), array( 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), array( 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), array( 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), array( 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), array( 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), array( 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), array( 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0), array( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array( 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3) ); const BLOCKBYTES = 128; const OUTBYTES = 64; const KEYBYTES = 64; /** * Turn two 32-bit integers into a fixed array representing a 64-bit integer. * * @internal You should not use this directly from another application * * @param int $high * @param int $low * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public static function new64($high, $low) { return ParagonIE_Sodium_Core32_Int64::fromInts($low, $high); } /** * Convert an arbitrary number into an SplFixedArray of two 32-bit integers * that represents a 64-bit integer. * * @internal You should not use this directly from another application * * @param int $num * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ protected static function to64($num) { list($hi, $lo) = self::numericTo64BitInteger($num); return self::new64($hi, $lo); } /** * Adds two 64-bit integers together, returning their sum as a SplFixedArray * containing two 32-bit integers (representing a 64-bit integer). * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Int64 $x * @param ParagonIE_Sodium_Core32_Int64 $y * @return ParagonIE_Sodium_Core32_Int64 */ protected static function add64($x, $y) { return $x->addInt64($y); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Int64 $x * @param ParagonIE_Sodium_Core32_Int64 $y * @param ParagonIE_Sodium_Core32_Int64 $z * @return ParagonIE_Sodium_Core32_Int64 */ public static function add364($x, $y, $z) { return $x->addInt64($y)->addInt64($z); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Int64 $x * @param ParagonIE_Sodium_Core32_Int64 $y * @return ParagonIE_Sodium_Core32_Int64 * @throws TypeError */ public static function xor64(ParagonIE_Sodium_Core32_Int64 $x, ParagonIE_Sodium_Core32_Int64 $y) { return $x->xorInt64($y); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Int64 $x * @param int $c * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public static function rotr64(ParagonIE_Sodium_Core32_Int64 $x, $c) { return $x->rotateRight($c); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $i * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public static function load64($x, $i) { /** @var int $l */ $l = (int) ($x[$i]) | ((int) ($x[$i+1]) << 8) | ((int) ($x[$i+2]) << 16) | ((int) ($x[$i+3]) << 24); /** @var int $h */ $h = (int) ($x[$i+4]) | ((int) ($x[$i+5]) << 8) | ((int) ($x[$i+6]) << 16) | ((int) ($x[$i+7]) << 24); return self::new64($h, $l); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $x * @param int $i * @param ParagonIE_Sodium_Core32_Int64 $u * @return void * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset */ public static function store64(SplFixedArray $x, $i, ParagonIE_Sodium_Core32_Int64 $u) { $v = clone $u; $maxLength = $x->getSize() - 1; for ($j = 0; $j < 8; ++$j) { $k = 3 - ($j >> 1); $x[$i] = $v->limbs[$k] & 0xff; if (++$i > $maxLength) { return; } $v->limbs[$k] >>= 8; } } /** * This just sets the $iv static variable. * * @internal You should not use this directly from another application * * @return void * @throws SodiumException * @throws TypeError */ public static function pseudoConstructor() { static $called = false; if ($called) { return; } self::$iv = new SplFixedArray(8); self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908); self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b); self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b); self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1); self::$iv[4] = self::new64(0x510e527f, 0xade682d1); self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f); self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b); self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179); $called = true; } /** * Returns a fresh BLAKE2 context. * * @internal You should not use this directly from another application * * @return SplFixedArray * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @throws SodiumException * @throws TypeError */ protected static function context() { $ctx = new SplFixedArray(6); $ctx[0] = new SplFixedArray(8); // h $ctx[1] = new SplFixedArray(2); // t $ctx[2] = new SplFixedArray(2); // f $ctx[3] = new SplFixedArray(256); // buf $ctx[4] = 0; // buflen $ctx[5] = 0; // last_node (uint8_t) for ($i = 8; $i--;) { $ctx[0][$i] = self::$iv[$i]; } for ($i = 256; $i--;) { $ctx[3][$i] = 0; } $zero = self::new64(0, 0); $ctx[1][0] = $zero; $ctx[1][1] = $zero; $ctx[2][0] = $zero; $ctx[2][1] = $zero; return $ctx; } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $buf * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedAssignment */ protected static function compress(SplFixedArray $ctx, SplFixedArray $buf) { $m = new SplFixedArray(16); $v = new SplFixedArray(16); for ($i = 16; $i--;) { $m[$i] = self::load64($buf, $i << 3); } for ($i = 8; $i--;) { $v[$i] = $ctx[0][$i]; } $v[ 8] = self::$iv[0]; $v[ 9] = self::$iv[1]; $v[10] = self::$iv[2]; $v[11] = self::$iv[3]; $v[12] = self::xor64($ctx[1][0], self::$iv[4]); $v[13] = self::xor64($ctx[1][1], self::$iv[5]); $v[14] = self::xor64($ctx[2][0], self::$iv[6]); $v[15] = self::xor64($ctx[2][1], self::$iv[7]); for ($r = 0; $r < 12; ++$r) { $v = self::G($r, 0, 0, 4, 8, 12, $v, $m); $v = self::G($r, 1, 1, 5, 9, 13, $v, $m); $v = self::G($r, 2, 2, 6, 10, 14, $v, $m); $v = self::G($r, 3, 3, 7, 11, 15, $v, $m); $v = self::G($r, 4, 0, 5, 10, 15, $v, $m); $v = self::G($r, 5, 1, 6, 11, 12, $v, $m); $v = self::G($r, 6, 2, 7, 8, 13, $v, $m); $v = self::G($r, 7, 3, 4, 9, 14, $v, $m); } for ($i = 8; $i--;) { $ctx[0][$i] = self::xor64( $ctx[0][$i], self::xor64($v[$i], $v[$i+8]) ); } } /** * @internal You should not use this directly from another application * * @param int $r * @param int $i * @param int $a * @param int $b * @param int $c * @param int $d * @param SplFixedArray $v * @param SplFixedArray $m * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayOffset */ public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v, SplFixedArray $m) { $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]); $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32); $v[$c] = self::add64($v[$c], $v[$d]); $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24); $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]); $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16); $v[$c] = self::add64($v[$c], $v[$d]); $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63); return $v; } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param int $inc * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment */ public static function increment_counter($ctx, $inc) { if ($inc < 0) { throw new SodiumException('Increasing by a negative number makes no sense.'); } $t = self::to64($inc); # S->t is $ctx[1] in our implementation # S->t[0] = ( uint64_t )( t >> 0 ); $ctx[1][0] = self::add64($ctx[1][0], $t); # S->t[1] += ( S->t[0] < inc ); if (!($ctx[1][0] instanceof ParagonIE_Sodium_Core32_Int64)) { throw new TypeError('Not an int64'); } /** @var ParagonIE_Sodium_Core32_Int64 $c*/ $c = $ctx[1][0]; if ($c->isLessThanInt($inc)) { $ctx[1][1] = self::add64($ctx[1][1], self::to64(1)); } } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $p * @param int $plen * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedMethodCall * @psalm-suppress MixedOperand */ public static function update(SplFixedArray $ctx, SplFixedArray $p, $plen) { self::pseudoConstructor(); $offset = 0; while ($plen > 0) { $left = $ctx[4]; $fill = 256 - $left; if ($plen > $fill) { # memcpy( S->buf + left, in, fill ); /* Fill buffer */ for ($i = $fill; $i--;) { $ctx[3][$i + $left] = $p[$i + $offset]; } # S->buflen += fill; $ctx[4] += $fill; # blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); self::increment_counter($ctx, 128); # blake2b_compress( S, S->buf ); /* Compress */ self::compress($ctx, $ctx[3]); # memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */ for ($i = 128; $i--;) { $ctx[3][$i] = $ctx[3][$i + 128]; } # S->buflen -= BLAKE2B_BLOCKBYTES; $ctx[4] -= 128; # in += fill; $offset += $fill; # inlen -= fill; $plen -= $fill; } else { for ($i = $plen; $i--;) { $ctx[3][$i + $left] = $p[$i + $offset]; } $ctx[4] += $plen; $offset += $plen; $plen -= $plen; } } } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @param SplFixedArray $out * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedArrayOffset * @psalm-suppress MixedMethodCall * @psalm-suppress MixedOperand */ public static function finish(SplFixedArray $ctx, SplFixedArray $out) { self::pseudoConstructor(); if ($ctx[4] > 128) { self::increment_counter($ctx, 128); self::compress($ctx, $ctx[3]); $ctx[4] -= 128; if ($ctx[4] > 128) { throw new SodiumException('Failed to assert that buflen <= 128 bytes'); } for ($i = $ctx[4]; $i--;) { $ctx[3][$i] = $ctx[3][$i + 128]; } } self::increment_counter($ctx, $ctx[4]); $ctx[2][0] = self::new64(0xffffffff, 0xffffffff); for ($i = 256 - $ctx[4]; $i--;) { /** @var int $i */ $ctx[3][$i + $ctx[4]] = 0; } self::compress($ctx, $ctx[3]); $i = (int) (($out->getSize() - 1) / 8); for (; $i >= 0; --$i) { self::store64($out, $i << 3, $ctx[0][$i]); } return $out; } /** * @internal You should not use this directly from another application * * @param SplFixedArray|null $key * @param int $outlen * @param SplFixedArray|null $salt * @param SplFixedArray|null $personal * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedAssignment * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedMethodCall */ public static function init( $key = null, $outlen = 64, $salt = null, $personal = null ) { self::pseudoConstructor(); $klen = 0; if ($key !== null) { if (count($key) > 64) { throw new SodiumException('Invalid key size'); } $klen = count($key); } if ($outlen > 64) { throw new SodiumException('Invalid output size'); } $ctx = self::context(); $p = new SplFixedArray(64); // Zero our param buffer... for ($i = 64; --$i;) { $p[$i] = 0; } $p[0] = $outlen; // digest_length $p[1] = $klen; // key_length $p[2] = 1; // fanout $p[3] = 1; // depth if ($salt instanceof SplFixedArray) { // salt: [32] through [47] for ($i = 0; $i < 16; ++$i) { $p[32 + $i] = (int) $salt[$i]; } } if ($personal instanceof SplFixedArray) { // personal: [48] through [63] for ($i = 0; $i < 16; ++$i) { $p[48 + $i] = (int) $personal[$i]; } } $ctx[0][0] = self::xor64( $ctx[0][0], self::load64($p, 0) ); if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) { // We need to do what blake2b_init_param() does: for ($i = 1; $i < 8; ++$i) { $ctx[0][$i] = self::xor64( $ctx[0][$i], self::load64($p, $i << 3) ); } } if ($klen > 0 && $key instanceof SplFixedArray) { $block = new SplFixedArray(128); for ($i = 128; $i--;) { $block[$i] = 0; } for ($i = $klen; $i--;) { $block[$i] = $key[$i]; } self::update($ctx, $block, 128); $ctx[4] = 128; } return $ctx; } /** * Convert a string into an SplFixedArray of integers * * @internal You should not use this directly from another application * * @param string $str * @return SplFixedArray * @psalm-suppress MixedArgumentTypeCoercion */ public static function stringToSplFixedArray($str = '') { $values = unpack('C*', $str); return SplFixedArray::fromArray(array_values($values)); } /** * Convert an SplFixedArray of integers into a string * * @internal You should not use this directly from another application * * @param SplFixedArray $a * @return string */ public static function SplFixedArrayToString(SplFixedArray $a) { /** * @var array<int, string|int> */ $arr = $a->toArray(); $c = $a->count(); array_unshift($arr, str_repeat('C', $c)); return (string) (call_user_func_array('pack', $arr)); } /** * @internal You should not use this directly from another application * * @param SplFixedArray $ctx * @return string * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment * @psalm-suppress MixedMethodCall */ public static function contextToString(SplFixedArray $ctx) { $str = ''; /** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */ $ctxA = $ctx[0]->toArray(); # uint64_t h[8]; for ($i = 0; $i < 8; ++$i) { if (!($ctxA[$i] instanceof ParagonIE_Sodium_Core32_Int64)) { throw new TypeError('Not an instance of Int64'); } /** @var ParagonIE_Sodium_Core32_Int64 $ctxAi */ $ctxAi = $ctxA[$i]; $str .= $ctxAi->toReverseString(); } # uint64_t t[2]; # uint64_t f[2]; for ($i = 1; $i < 3; ++$i) { /** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */ $ctxA = $ctx[$i]->toArray(); /** @var ParagonIE_Sodium_Core32_Int64 $ctxA1 */ $ctxA1 = $ctxA[0]; /** @var ParagonIE_Sodium_Core32_Int64 $ctxA2 */ $ctxA2 = $ctxA[1]; $str .= $ctxA1->toReverseString(); $str .= $ctxA2->toReverseString(); } # uint8_t buf[2 * 128]; $str .= self::SplFixedArrayToString($ctx[3]); /** @var int $ctx4 */ $ctx4 = $ctx[4]; # size_t buflen; $str .= implode('', array( self::intToChr($ctx4 & 0xff), self::intToChr(($ctx4 >> 8) & 0xff), self::intToChr(($ctx4 >> 16) & 0xff), self::intToChr(($ctx4 >> 24) & 0xff), "\x00\x00\x00\x00" /* self::intToChr(($ctx4 >> 32) & 0xff), self::intToChr(($ctx4 >> 40) & 0xff), self::intToChr(($ctx4 >> 48) & 0xff), self::intToChr(($ctx4 >> 56) & 0xff) */ )); # uint8_t last_node; return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23); } /** * Creates an SplFixedArray containing other SplFixedArray elements, from * a string (compatible with \Sodium\crypto_generichash_{init, update, final}) * * @internal You should not use this directly from another application * * @param string $string * @return SplFixedArray * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedArrayAssignment */ public static function stringToContext($string) { $ctx = self::context(); # uint64_t h[8]; for ($i = 0; $i < 8; ++$i) { $ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromReverseString( self::substr($string, (($i << 3) + 0), 8) ); } # uint64_t t[2]; # uint64_t f[2]; for ($i = 1; $i < 3; ++$i) { $ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromReverseString( self::substr($string, 72 + (($i - 1) << 4), 8) ); $ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromReverseString( self::substr($string, 64 + (($i - 1) << 4), 8) ); } # uint8_t buf[2 * 128]; $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256)); # uint8_t buf[2 * 128]; $int = 0; for ($i = 0; $i < 8; ++$i) { $int |= self::chrToInt($string[352 + $i]) << ($i << 3); } $ctx[4] = $int; return $ctx; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/ChaCha20/Ctx.php�����������������������������������������������������������������������������0000644�����������������00000011450�15021200076�0010313 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) { return; } /** * Class ParagonIE_Sodium_Core32_ChaCha20_Ctx */ class ParagonIE_Sodium_Core32_ChaCha20_Ctx extends ParagonIE_Sodium_Core32_Util implements ArrayAccess { /** * @var SplFixedArray internally, <int, ParagonIE_Sodium_Core32_Int32> */ protected $container; /** * ParagonIE_Sodium_Core_ChaCha20_Ctx constructor. * * @internal You should not use this directly from another application * * @param string $key ChaCha20 key. * @param string $iv Initialization Vector (a.k.a. nonce). * @param string $counter The initial counter value. * Defaults to 8 0x00 bytes. * @throws InvalidArgumentException * @throws SodiumException * @throws TypeError */ public function __construct($key = '', $iv = '', $counter = '') { if (self::strlen($key) !== 32) { throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.'); } if (self::strlen($iv) !== 8) { throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.'); } $this->container = new SplFixedArray(16); /* "expand 32-byte k" as per ChaCha20 spec */ $this->container[0] = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865)); $this->container[1] = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e)); $this->container[2] = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32)); $this->container[3] = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574)); $this->container[4] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4)); $this->container[5] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4)); $this->container[6] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4)); $this->container[7] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4)); $this->container[8] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4)); $this->container[9] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4)); $this->container[10] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4)); $this->container[11] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4)); if (empty($counter)) { $this->container[12] = new ParagonIE_Sodium_Core32_Int32(); $this->container[13] = new ParagonIE_Sodium_Core32_Int32(); } else { $this->container[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4)); $this->container[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 4, 4)); } $this->container[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4)); $this->container[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4)); } /** * @internal You should not use this directly from another application * * @param int $offset * @param int|ParagonIE_Sodium_Core32_Int32 $value * @return void */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { if (!is_int($offset)) { throw new InvalidArgumentException('Expected an integer'); } if ($value instanceof ParagonIE_Sodium_Core32_Int32) { /* } elseif (is_int($value)) { $value = ParagonIE_Sodium_Core32_Int32::fromInt($value); */ } else { throw new InvalidArgumentException('Expected an integer'); } $this->container[$offset] = $value; } /** * @internal You should not use this directly from another application * * @param int $offset * @return bool * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return void * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->container[$offset]); } /** * @internal You should not use this directly from another application * * @param int $offset * @return mixed|null * @psalm-suppress MixedArrayOffset */ #[ReturnTypeWillChange] public function offsetGet($offset) { return isset($this->container[$offset]) ? $this->container[$offset] : null; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/ChaCha20/IetfCtx.php�������������������������������������������������������������������������0000644�����������������00000002737�15021200076�0011133 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', false)) { return; } /** * Class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx */ class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx extends ParagonIE_Sodium_Core32_ChaCha20_Ctx { /** * ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor. * * @internal You should not use this directly from another application * * @param string $key ChaCha20 key. * @param string $iv Initialization Vector (a.k.a. nonce). * @param string $counter The initial counter value. * Defaults to 4 0x00 bytes. * @throws InvalidArgumentException * @throws SodiumException * @throws TypeError */ public function __construct($key = '', $iv = '', $counter = '') { if (self::strlen($iv) !== 12) { throw new InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.'); } parent::__construct($key, self::substr($iv, 0, 8), $counter); if (!empty($counter)) { $this->container[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4)); } $this->container[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4)); $this->container[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4)); $this->container[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 8, 4)); } } ���������������������������������Core32/XChaCha20.php��������������������������������������������������������������������������������0000644�����������������00000004626�15021200076�0007714 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_XChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core32_XChaCha20 */ class ParagonIE_Sodium_Core32_XChaCha20 extends ParagonIE_Sodium_Core32_HChaCha20 { /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function stream($len = 64, $nonce = '', $key = '') { if (self::strlen($nonce) !== 24) { throw new SodiumException('Nonce must be 24 bytes long'); } return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_Ctx( self::hChaCha20( self::substr($nonce, 0, 16), $key ), self::substr($nonce, 16, 8) ), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function streamXorIc($message, $nonce = '', $key = '', $ic = '') { if (self::strlen($nonce) !== 24) { throw new SodiumException('Nonce must be 24 bytes long'); } return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_Ctx( self::hChaCha20(self::substr($nonce, 0, 16), $key), self::substr($nonce, 16, 8), $ic ), $message ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx( self::hChaCha20(self::substr($nonce, 0, 16), $key), "\x00\x00\x00\x00" . self::substr($nonce, 16, 8), $ic ), $message ); } } ����������������������������������������������������������������������������������������������������������Core32/error_log������������������������������������������������������������������������������������0000644�����������������00000046102�15021200076�0007512 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[24-Mar-2022 05:02:52 America/Boise] PHP Fatal error: Uncaught Error: Class 'ParagonIE_Sodium_Core32_Curve25519' not found in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php:10 Stack trace: #0 {main} thrown in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php on line 10 [24-Mar-2022 05:02:52 America/Boise] PHP Fatal error: Uncaught Error: Class 'ParagonIE_Sodium_Core32_Curve25519' not found in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php:10 Stack trace: #0 {main} thrown in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php on line 10 [26-Mar-2022 03:47:56 America/Boise] PHP Fatal error: Uncaught Error: Class 'ParagonIE_Sodium_Core32_Curve25519' not found in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php:10 Stack trace: #0 {main} thrown in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php on line 10 [26-Mar-2022 03:47:57 America/Boise] PHP Fatal error: Uncaught Error: Class 'ParagonIE_Sodium_Core32_Curve25519' not found in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php:10 Stack trace: #0 {main} thrown in /home2/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php on line 10 [18-May-2025 15:57:13 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php on line 10 [18-May-2025 15:57:14 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php on line 10 [18-May-2025 15:57:16 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HSalsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php on line 10 [18-May-2025 15:57:17 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 15:57:18 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Salsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HSalsa20.php on line 10 [18-May-2025 15:57:22 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php on line 12 [18-May-2025 15:57:23 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php(7): require_once() #1 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 15:57:24 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php on line 10 [18-May-2025 15:57:27 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Salsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Salsa20.php on line 10 [18-May-2025 15:57:40 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php on line 10 [18-May-2025 15:57:42 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 12 [18-May-2025 15:57:45 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XChaCha20.php on line 10 [18-May-2025 15:57:46 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php on line 10 [18-May-2025 18:43:51 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php on line 10 [18-May-2025 18:43:52 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php on line 10 [18-May-2025 18:43:54 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php on line 10 [18-May-2025 18:43:57 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Poly1305.php on line 10 [18-May-2025 18:43:57 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php on line 12 [18-May-2025 18:43:58 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php on line 12 [18-May-2025 18:44:00 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php on line 12 [18-May-2025 18:44:03 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/SipHash.php on line 12 [18-May-2025 18:44:04 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php on line 10 [18-May-2025 18:44:04 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php on line 10 [18-May-2025 18:44:11 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/X25519.php on line 10 [18-May-2025 18:44:24 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/BLAKE2b.php:12 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/BLAKE2b.php on line 12 [18-May-2025 18:44:25 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Salsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Salsa20.php on line 10 [18-May-2025 18:44:35 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Salsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Salsa20.php on line 10 [18-May-2025 18:44:35 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XChaCha20.php on line 10 [18-May-2025 18:44:40 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XChaCha20.php on line 10 [18-May-2025 18:44:50 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HSalsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php on line 10 [18-May-2025 18:44:51 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HSalsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php on line 10 [18-May-2025 18:44:54 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_HSalsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/XSalsa20.php on line 10 [18-May-2025 18:44:56 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php on line 10 [18-May-2025 18:44:56 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php on line 10 [18-May-2025 18:44:58 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php on line 10 [18-May-2025 18:45:01 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_ChaCha20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HChaCha20.php on line 10 [18-May-2025 18:45:02 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php on line 10 [18-May-2025 18:45:02 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php on line 10 [18-May-2025 18:45:04 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/ChaCha20.php on line 10 [18-May-2025 18:45:10 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php(7): require_once() #1 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 18:45:11 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php(7): require_once() #1 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 18:45:13 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Ed25519.php(7): require_once() #1 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 18:45:22 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Salsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HSalsa20.php on line 10 [18-May-2025 18:45:24 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Salsa20" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HSalsa20.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/HSalsa20.php on line 10 [18-May-2025 18:45:30 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php on line 10 [18-May-2025 18:45:31 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php on line 10 [18-May-2025 18:45:32 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core_Util" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php:10 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Util.php on line 10 [18-May-2025 18:45:41 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 18:45:43 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 [18-May-2025 18:45:46 America/New_York] PHP Fatal error: Uncaught Error: Class "ParagonIE_Sodium_Core32_Curve25519_H" not found in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php:16 Stack trace: #0 {main} thrown in /home/abhiramc/public_html/biharafoods/wp-includes/sodium_compat/src/Core32/Curve25519.php on line 16 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Int64.php������������������������������������������������������������������������������������0000644�����������������00000074704�15021200076�0007223 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Class ParagonIE_Sodium_Core32_Int64 * * Encapsulates a 64-bit integer. * * These are immutable. It always returns a new instance. */ class ParagonIE_Sodium_Core32_Int64 { /** * @var array<int, int> - four 16-bit integers */ public $limbs = array(0, 0, 0, 0); /** * @var int */ public $overflow = 0; /** * @var bool */ public $unsignedInt = false; /** * ParagonIE_Sodium_Core32_Int64 constructor. * @param array $array * @param bool $unsignedInt */ public function __construct($array = array(0, 0, 0, 0), $unsignedInt = false) { $this->limbs = array( (int) $array[0], (int) $array[1], (int) $array[2], (int) $array[3] ); $this->overflow = 0; $this->unsignedInt = $unsignedInt; } /** * Adds two int64 objects * * @param ParagonIE_Sodium_Core32_Int64 $addend * @return ParagonIE_Sodium_Core32_Int64 */ public function addInt64(ParagonIE_Sodium_Core32_Int64 $addend) { $i0 = $this->limbs[0]; $i1 = $this->limbs[1]; $i2 = $this->limbs[2]; $i3 = $this->limbs[3]; $j0 = $addend->limbs[0]; $j1 = $addend->limbs[1]; $j2 = $addend->limbs[2]; $j3 = $addend->limbs[3]; $r3 = $i3 + ($j3 & 0xffff); $carry = $r3 >> 16; $r2 = $i2 + ($j2 & 0xffff) + $carry; $carry = $r2 >> 16; $r1 = $i1 + ($j1 & 0xffff) + $carry; $carry = $r1 >> 16; $r0 = $i0 + ($j0 & 0xffff) + $carry; $carry = $r0 >> 16; $r0 &= 0xffff; $r1 &= 0xffff; $r2 &= 0xffff; $r3 &= 0xffff; $return = new ParagonIE_Sodium_Core32_Int64( array($r0, $r1, $r2, $r3) ); $return->overflow = $carry; $return->unsignedInt = $this->unsignedInt; return $return; } /** * Adds a normal integer to an int64 object * * @param int $int * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public function addInt($int) { ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); /** @var int $int */ $int = (int) $int; $i0 = $this->limbs[0]; $i1 = $this->limbs[1]; $i2 = $this->limbs[2]; $i3 = $this->limbs[3]; $r3 = $i3 + ($int & 0xffff); $carry = $r3 >> 16; $r2 = $i2 + (($int >> 16) & 0xffff) + $carry; $carry = $r2 >> 16; $r1 = $i1 + $carry; $carry = $r1 >> 16; $r0 = $i0 + $carry; $carry = $r0 >> 16; $r0 &= 0xffff; $r1 &= 0xffff; $r2 &= 0xffff; $r3 &= 0xffff; $return = new ParagonIE_Sodium_Core32_Int64( array($r0, $r1, $r2, $r3) ); $return->overflow = $carry; $return->unsignedInt = $this->unsignedInt; return $return; } /** * @param int $b * @return int */ public function compareInt($b = 0) { $gt = 0; $eq = 1; $i = 4; $j = 0; while ($i > 0) { --$i; /** @var int $x1 */ $x1 = $this->limbs[$i]; /** @var int $x2 */ $x2 = ($b >> ($j << 4)) & 0xffff; /** int */ $gt |= (($x2 - $x1) >> 8) & $eq; /** int */ $eq &= (($x2 ^ $x1) - 1) >> 8; } return ($gt + $gt - $eq) + 1; } /** * @param int $b * @return bool */ public function isGreaterThan($b = 0) { return $this->compareInt($b) > 0; } /** * @param int $b * @return bool */ public function isLessThanInt($b = 0) { return $this->compareInt($b) < 0; } /** * @param int $hi * @param int $lo * @return ParagonIE_Sodium_Core32_Int64 */ public function mask64($hi = 0, $lo = 0) { /** @var int $a */ $a = ($hi >> 16) & 0xffff; /** @var int $b */ $b = ($hi) & 0xffff; /** @var int $c */ $c = ($lo >> 16) & 0xffff; /** @var int $d */ $d = ($lo & 0xffff); return new ParagonIE_Sodium_Core32_Int64( array( $this->limbs[0] & $a, $this->limbs[1] & $b, $this->limbs[2] & $c, $this->limbs[3] & $d ), $this->unsignedInt ); } /** * @param int $int * @param int $size * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment */ public function mulInt($int = 0, $size = 0) { if (ParagonIE_Sodium_Compat::$fastMult) { return $this->mulIntFast($int); } ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2); /** @var int $int */ $int = (int) $int; /** @var int $size */ $size = (int) $size; if (!$size) { $size = 63; } $a = clone $this; $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; // Initialize: $ret0 = 0; $ret1 = 0; $ret2 = 0; $ret3 = 0; $a0 = $a->limbs[0]; $a1 = $a->limbs[1]; $a2 = $a->limbs[2]; $a3 = $a->limbs[3]; /** @var int $size */ /** @var int $i */ for ($i = $size; $i >= 0; --$i) { $mask = -($int & 1); $x0 = $a0 & $mask; $x1 = $a1 & $mask; $x2 = $a2 & $mask; $x3 = $a3 & $mask; $ret3 += $x3; $c = $ret3 >> 16; $ret2 += $x2 + $c; $c = $ret2 >> 16; $ret1 += $x1 + $c; $c = $ret1 >> 16; $ret0 += $x0 + $c; $ret0 &= 0xffff; $ret1 &= 0xffff; $ret2 &= 0xffff; $ret3 &= 0xffff; $a3 = $a3 << 1; $x3 = $a3 >> 16; $a2 = ($a2 << 1) | $x3; $x2 = $a2 >> 16; $a1 = ($a1 << 1) | $x2; $x1 = $a1 >> 16; $a0 = ($a0 << 1) | $x1; $a0 &= 0xffff; $a1 &= 0xffff; $a2 &= 0xffff; $a3 &= 0xffff; $int >>= 1; } $return->limbs[0] = $ret0; $return->limbs[1] = $ret1; $return->limbs[2] = $ret2; $return->limbs[3] = $ret3; return $return; } /** * @param ParagonIE_Sodium_Core32_Int64 $A * @param ParagonIE_Sodium_Core32_Int64 $B * @return array<int, ParagonIE_Sodium_Core32_Int64> * @throws SodiumException * @throws TypeError * @psalm-suppress MixedInferredReturnType */ public static function ctSelect( ParagonIE_Sodium_Core32_Int64 $A, ParagonIE_Sodium_Core32_Int64 $B ) { $a = clone $A; $b = clone $B; /** @var int $aNeg */ $aNeg = ($a->limbs[0] >> 15) & 1; /** @var int $bNeg */ $bNeg = ($b->limbs[0] >> 15) & 1; /** @var int $m */ $m = (-($aNeg & $bNeg)) | 1; /** @var int $swap */ $swap = $bNeg & ~$aNeg; /** @var int $d */ $d = -$swap; /* if ($bNeg && !$aNeg) { $a = clone $int; $b = clone $this; } elseif($bNeg && $aNeg) { $a = $this->mulInt(-1); $b = $int->mulInt(-1); } */ $x = $a->xorInt64($b)->mask64($d, $d); return array( $a->xorInt64($x)->mulInt($m), $b->xorInt64($x)->mulInt($m) ); } /** * @param array<int, int> $a * @param array<int, int> $b * @param int $baseLog2 * @return array<int, int> */ public function multiplyLong(array $a, array $b, $baseLog2 = 16) { $a_l = count($a); $b_l = count($b); /** @var array<int, int> $r */ $r = array_fill(0, $a_l + $b_l + 1, 0); $base = 1 << $baseLog2; for ($i = 0; $i < $a_l; ++$i) { $a_i = $a[$i]; for ($j = 0; $j < $a_l; ++$j) { $b_j = $b[$j]; $product = (($a_i * $b_j) + $r[$i + $j]); $carry = (((int) $product >> $baseLog2) & 0xffff); $r[$i + $j] = ((int) $product - (int) ($carry * $base)) & 0xffff; $r[$i + $j + 1] += $carry; } } return array_slice($r, 0, 5); } /** * @param int $int * @return ParagonIE_Sodium_Core32_Int64 */ public function mulIntFast($int) { // Handle negative numbers $aNeg = ($this->limbs[0] >> 15) & 1; $bNeg = ($int >> 31) & 1; $a = array_reverse($this->limbs); $b = array( $int & 0xffff, ($int >> 16) & 0xffff, -$bNeg & 0xffff, -$bNeg & 0xffff ); if ($aNeg) { for ($i = 0; $i < 4; ++$i) { $a[$i] = ($a[$i] ^ 0xffff) & 0xffff; } ++$a[0]; } if ($bNeg) { for ($i = 0; $i < 4; ++$i) { $b[$i] = ($b[$i] ^ 0xffff) & 0xffff; } ++$b[0]; } // Multiply $res = $this->multiplyLong($a, $b); // Re-apply negation to results if ($aNeg !== $bNeg) { for ($i = 0; $i < 4; ++$i) { $res[$i] = (0xffff ^ $res[$i]) & 0xffff; } // Handle integer overflow $c = 1; for ($i = 0; $i < 4; ++$i) { $res[$i] += $c; $c = $res[$i] >> 16; $res[$i] &= 0xffff; } } // Return our values $return = new ParagonIE_Sodium_Core32_Int64(); $return->limbs = array( $res[3] & 0xffff, $res[2] & 0xffff, $res[1] & 0xffff, $res[0] & 0xffff ); if (count($res) > 4) { $return->overflow = $res[4] & 0xffff; } $return->unsignedInt = $this->unsignedInt; return $return; } /** * @param ParagonIE_Sodium_Core32_Int64 $right * @return ParagonIE_Sodium_Core32_Int64 */ public function mulInt64Fast(ParagonIE_Sodium_Core32_Int64 $right) { $aNeg = ($this->limbs[0] >> 15) & 1; $bNeg = ($right->limbs[0] >> 15) & 1; $a = array_reverse($this->limbs); $b = array_reverse($right->limbs); if ($aNeg) { for ($i = 0; $i < 4; ++$i) { $a[$i] = ($a[$i] ^ 0xffff) & 0xffff; } ++$a[0]; } if ($bNeg) { for ($i = 0; $i < 4; ++$i) { $b[$i] = ($b[$i] ^ 0xffff) & 0xffff; } ++$b[0]; } $res = $this->multiplyLong($a, $b); if ($aNeg !== $bNeg) { if ($aNeg !== $bNeg) { for ($i = 0; $i < 4; ++$i) { $res[$i] = ($res[$i] ^ 0xffff) & 0xffff; } $c = 1; for ($i = 0; $i < 4; ++$i) { $res[$i] += $c; $c = $res[$i] >> 16; $res[$i] &= 0xffff; } } } $return = new ParagonIE_Sodium_Core32_Int64(); $return->limbs = array( $res[3] & 0xffff, $res[2] & 0xffff, $res[1] & 0xffff, $res[0] & 0xffff ); if (count($res) > 4) { $return->overflow = $res[4]; } return $return; } /** * @param ParagonIE_Sodium_Core32_Int64 $int * @param int $size * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment */ public function mulInt64(ParagonIE_Sodium_Core32_Int64 $int, $size = 0) { if (ParagonIE_Sodium_Compat::$fastMult) { return $this->mulInt64Fast($int); } ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2); if (!$size) { $size = 63; } list($a, $b) = self::ctSelect($this, $int); $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; // Initialize: $ret0 = 0; $ret1 = 0; $ret2 = 0; $ret3 = 0; $a0 = $a->limbs[0]; $a1 = $a->limbs[1]; $a2 = $a->limbs[2]; $a3 = $a->limbs[3]; $b0 = $b->limbs[0]; $b1 = $b->limbs[1]; $b2 = $b->limbs[2]; $b3 = $b->limbs[3]; /** @var int $size */ /** @var int $i */ for ($i = (int) $size; $i >= 0; --$i) { $mask = -($b3 & 1); $x0 = $a0 & $mask; $x1 = $a1 & $mask; $x2 = $a2 & $mask; $x3 = $a3 & $mask; $ret3 += $x3; $c = $ret3 >> 16; $ret2 += $x2 + $c; $c = $ret2 >> 16; $ret1 += $x1 + $c; $c = $ret1 >> 16; $ret0 += $x0 + $c; $ret0 &= 0xffff; $ret1 &= 0xffff; $ret2 &= 0xffff; $ret3 &= 0xffff; $a3 = $a3 << 1; $x3 = $a3 >> 16; $a2 = ($a2 << 1) | $x3; $x2 = $a2 >> 16; $a1 = ($a1 << 1) | $x2; $x1 = $a1 >> 16; $a0 = ($a0 << 1) | $x1; $a0 &= 0xffff; $a1 &= 0xffff; $a2 &= 0xffff; $a3 &= 0xffff; $x0 = ($b0 & 1) << 16; $x1 = ($b1 & 1) << 16; $x2 = ($b2 & 1) << 16; $b0 = ($b0 >> 1); $b1 = (($b1 | $x0) >> 1); $b2 = (($b2 | $x1) >> 1); $b3 = (($b3 | $x2) >> 1); $b0 &= 0xffff; $b1 &= 0xffff; $b2 &= 0xffff; $b3 &= 0xffff; } $return->limbs[0] = $ret0; $return->limbs[1] = $ret1; $return->limbs[2] = $ret2; $return->limbs[3] = $ret3; return $return; } /** * OR this 64-bit integer with another. * * @param ParagonIE_Sodium_Core32_Int64 $b * @return ParagonIE_Sodium_Core32_Int64 */ public function orInt64(ParagonIE_Sodium_Core32_Int64 $b) { $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; $return->limbs = array( (int) ($this->limbs[0] | $b->limbs[0]), (int) ($this->limbs[1] | $b->limbs[1]), (int) ($this->limbs[2] | $b->limbs[2]), (int) ($this->limbs[3] | $b->limbs[3]) ); return $return; } /** * @param int $c * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess */ public function rotateLeft($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; $c &= 63; if ($c === 0) { // NOP, but we want a copy. $return->limbs = $this->limbs; } else { /** @var array<int, int> $limbs */ $limbs =& $return->limbs; /** @var array<int, int> $myLimbs */ $myLimbs =& $this->limbs; /** @var int $idx_shift */ $idx_shift = ($c >> 4) & 3; /** @var int $sub_shift */ $sub_shift = $c & 15; for ($i = 3; $i >= 0; --$i) { /** @var int $j */ $j = ($i + $idx_shift) & 3; /** @var int $k */ $k = ($i + $idx_shift + 1) & 3; $limbs[$i] = (int) ( ( ((int) ($myLimbs[$j]) << $sub_shift) | ((int) ($myLimbs[$k]) >> (16 - $sub_shift)) ) & 0xffff ); } } return $return; } /** * Rotate to the right * * @param int $c * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArrayAccess */ public function rotateRight($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; /** @var ParagonIE_Sodium_Core32_Int64 $return */ $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; $c &= 63; /** @var int $c */ if ($c === 0) { // NOP, but we want a copy. $return->limbs = $this->limbs; } else { /** @var array<int, int> $limbs */ $limbs =& $return->limbs; /** @var array<int, int> $myLimbs */ $myLimbs =& $this->limbs; /** @var int $idx_shift */ $idx_shift = ($c >> 4) & 3; /** @var int $sub_shift */ $sub_shift = $c & 15; for ($i = 3; $i >= 0; --$i) { /** @var int $j */ $j = ($i - $idx_shift) & 3; /** @var int $k */ $k = ($i - $idx_shift - 1) & 3; $limbs[$i] = (int) ( ( ((int) ($myLimbs[$j]) >> (int) ($sub_shift)) | ((int) ($myLimbs[$k]) << (16 - (int) ($sub_shift))) ) & 0xffff ); } } return $return; } /** * @param int $c * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public function shiftLeft($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); /** @var int $c */ $c = (int) $c; $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; $c &= 63; if ($c >= 16) { if ($c >= 48) { $return->limbs = array( $this->limbs[3], 0, 0, 0 ); } elseif ($c >= 32) { $return->limbs = array( $this->limbs[2], $this->limbs[3], 0, 0 ); } else { $return->limbs = array( $this->limbs[1], $this->limbs[2], $this->limbs[3], 0 ); } return $return->shiftLeft($c & 15); } if ($c === 0) { $return->limbs = $this->limbs; } elseif ($c < 0) { /** @var int $c */ return $this->shiftRight(-$c); } else { if (!is_int($c)) { throw new TypeError(); } /** @var int $carry */ $carry = 0; for ($i = 3; $i >= 0; --$i) { /** @var int $tmp */ $tmp = ($this->limbs[$i] << $c) | ($carry & 0xffff); $return->limbs[$i] = (int) ($tmp & 0xffff); /** @var int $carry */ $carry = $tmp >> 16; } } return $return; } /** * @param int $c * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public function shiftRight($c = 0) { ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1); $c = (int) $c; /** @var int $c */ $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; $c &= 63; $negative = -(($this->limbs[0] >> 15) & 1); if ($c >= 16) { if ($c >= 48) { $return->limbs = array( (int) ($negative & 0xffff), (int) ($negative & 0xffff), (int) ($negative & 0xffff), (int) $this->limbs[0] ); } elseif ($c >= 32) { $return->limbs = array( (int) ($negative & 0xffff), (int) ($negative & 0xffff), (int) $this->limbs[0], (int) $this->limbs[1] ); } else { $return->limbs = array( (int) ($negative & 0xffff), (int) $this->limbs[0], (int) $this->limbs[1], (int) $this->limbs[2] ); } return $return->shiftRight($c & 15); } if ($c === 0) { $return->limbs = $this->limbs; } elseif ($c < 0) { return $this->shiftLeft(-$c); } else { if (!is_int($c)) { throw new TypeError(); } /** @var int $carryRight */ $carryRight = ($negative & 0xffff); $mask = (int) (((1 << ($c + 1)) - 1) & 0xffff); for ($i = 0; $i < 4; ++$i) { $return->limbs[$i] = (int) ( (($this->limbs[$i] >> $c) | ($carryRight << (16 - $c))) & 0xffff ); $carryRight = (int) ($this->limbs[$i] & $mask); } } return $return; } /** * Subtract a normal integer from an int64 object. * * @param int $int * @return ParagonIE_Sodium_Core32_Int64 * @throws SodiumException * @throws TypeError */ public function subInt($int) { ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1); $int = (int) $int; $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; /** @var int $carry */ $carry = 0; for ($i = 3; $i >= 0; --$i) { /** @var int $tmp */ $tmp = $this->limbs[$i] - (($int >> 16) & 0xffff) + $carry; /** @var int $carry */ $carry = $tmp >> 16; $return->limbs[$i] = (int) ($tmp & 0xffff); } return $return; } /** * The difference between two Int64 objects. * * @param ParagonIE_Sodium_Core32_Int64 $b * @return ParagonIE_Sodium_Core32_Int64 */ public function subInt64(ParagonIE_Sodium_Core32_Int64 $b) { $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; /** @var int $carry */ $carry = 0; for ($i = 3; $i >= 0; --$i) { /** @var int $tmp */ $tmp = $this->limbs[$i] - $b->limbs[$i] + $carry; /** @var int $carry */ $carry = ($tmp >> 16); $return->limbs[$i] = (int) ($tmp & 0xffff); } return $return; } /** * XOR this 64-bit integer with another. * * @param ParagonIE_Sodium_Core32_Int64 $b * @return ParagonIE_Sodium_Core32_Int64 */ public function xorInt64(ParagonIE_Sodium_Core32_Int64 $b) { $return = new ParagonIE_Sodium_Core32_Int64(); $return->unsignedInt = $this->unsignedInt; $return->limbs = array( (int) ($this->limbs[0] ^ $b->limbs[0]), (int) ($this->limbs[1] ^ $b->limbs[1]), (int) ($this->limbs[2] ^ $b->limbs[2]), (int) ($this->limbs[3] ^ $b->limbs[3]) ); return $return; } /** * @param int $low * @param int $high * @return self * @throws SodiumException * @throws TypeError */ public static function fromInts($low, $high) { ParagonIE_Sodium_Core32_Util::declareScalarType($low, 'int', 1); ParagonIE_Sodium_Core32_Util::declareScalarType($high, 'int', 2); $high = (int) $high; $low = (int) $low; return new ParagonIE_Sodium_Core32_Int64( array( (int) (($high >> 16) & 0xffff), (int) ($high & 0xffff), (int) (($low >> 16) & 0xffff), (int) ($low & 0xffff) ) ); } /** * @param int $low * @return self * @throws SodiumException * @throws TypeError */ public static function fromInt($low) { ParagonIE_Sodium_Core32_Util::declareScalarType($low, 'int', 1); $low = (int) $low; return new ParagonIE_Sodium_Core32_Int64( array( 0, 0, (int) (($low >> 16) & 0xffff), (int) ($low & 0xffff) ) ); } /** * @return int */ public function toInt() { return (int) ( (($this->limbs[2] & 0xffff) << 16) | ($this->limbs[3] & 0xffff) ); } /** * @param string $string * @return self * @throws SodiumException * @throws TypeError */ public static function fromString($string) { ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1); $string = (string) $string; if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) { throw new RangeException( 'String must be 8 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.' ); } $return = new ParagonIE_Sodium_Core32_Int64(); $return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8); $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff); $return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8); $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff); $return->limbs[2] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff) << 8); $return->limbs[2] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff); $return->limbs[3] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff) << 8); $return->limbs[3] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff); return $return; } /** * @param string $string * @return self * @throws SodiumException * @throws TypeError */ public static function fromReverseString($string) { ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1); $string = (string) $string; if (ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) { throw new RangeException( 'String must be 8 bytes; ' . ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.' ); } $return = new ParagonIE_Sodium_Core32_Int64(); $return->limbs[0] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff) << 8); $return->limbs[0] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff); $return->limbs[1] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff) << 8); $return->limbs[1] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff); $return->limbs[2] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8); $return->limbs[2] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff); $return->limbs[3] = (int) ((ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8); $return->limbs[3] |= (ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff); return $return; } /** * @return array<int, int> */ public function toArray() { return array( (int) ((($this->limbs[0] & 0xffff) << 16) | ($this->limbs[1] & 0xffff)), (int) ((($this->limbs[2] & 0xffff) << 16) | ($this->limbs[3] & 0xffff)) ); } /** * @return ParagonIE_Sodium_Core32_Int32 */ public function toInt32() { $return = new ParagonIE_Sodium_Core32_Int32(); $return->limbs[0] = (int) ($this->limbs[2]); $return->limbs[1] = (int) ($this->limbs[3]); $return->unsignedInt = $this->unsignedInt; $return->overflow = (int) (ParagonIE_Sodium_Core32_Util::abs($this->limbs[1], 16) & 0xffff); return $return; } /** * @return ParagonIE_Sodium_Core32_Int64 */ public function toInt64() { $return = new ParagonIE_Sodium_Core32_Int64(); $return->limbs[0] = (int) ($this->limbs[0]); $return->limbs[1] = (int) ($this->limbs[1]); $return->limbs[2] = (int) ($this->limbs[2]); $return->limbs[3] = (int) ($this->limbs[3]); $return->unsignedInt = $this->unsignedInt; $return->overflow = ParagonIE_Sodium_Core32_Util::abs($this->overflow); return $return; } /** * @param bool $bool * @return self */ public function setUnsignedInt($bool = false) { $this->unsignedInt = !empty($bool); return $this; } /** * @return string * @throws TypeError */ public function toString() { return ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[2] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[3] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] & 0xff); } /** * @return string * @throws TypeError */ public function toReverseString() { return ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[3] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[2] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[1] >> 8) & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . ParagonIE_Sodium_Core32_Util::intToChr(($this->limbs[0] >> 8) & 0xff); } /** * @return string */ public function __toString() { try { return $this->toString(); } catch (TypeError $ex) { // PHP engine can't handle exceptions from __toString() return ''; } } } ������������������������������������������������������������Core32/HChaCha20.php��������������������������������������������������������������������������������0000644�����������������00000012261�15021200076�0007666 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_HChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core_HChaCha20 */ class ParagonIE_Sodium_Core32_HChaCha20 extends ParagonIE_Sodium_Core32_ChaCha20 { /** * @param string $in * @param string $key * @param string|null $c * @return string * @throws SodiumException * @throws TypeError */ public static function hChaCha20($in = '', $key = '', $c = null) { $ctx = array(); if ($c === null) { $ctx[0] = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865)); $ctx[1] = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e)); $ctx[2] = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32)); $ctx[3] = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574)); } else { $ctx[0] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4)); $ctx[1] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4)); $ctx[2] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4)); $ctx[3] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4)); } $ctx[4] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4)); $ctx[5] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4)); $ctx[6] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4)); $ctx[7] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4)); $ctx[8] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4)); $ctx[9] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4)); $ctx[10] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4)); $ctx[11] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4)); $ctx[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4)); $ctx[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4)); $ctx[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4)); $ctx[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4)); return self::hChaCha20Bytes($ctx); } /** * @param array $ctx * @return string * @throws SodiumException * @throws TypeError */ protected static function hChaCha20Bytes(array $ctx) { /** @var ParagonIE_Sodium_Core32_Int32 $x0 */ $x0 = $ctx[0]; /** @var ParagonIE_Sodium_Core32_Int32 $x1 */ $x1 = $ctx[1]; /** @var ParagonIE_Sodium_Core32_Int32 $x2 */ $x2 = $ctx[2]; /** @var ParagonIE_Sodium_Core32_Int32 $x3 */ $x3 = $ctx[3]; /** @var ParagonIE_Sodium_Core32_Int32 $x4 */ $x4 = $ctx[4]; /** @var ParagonIE_Sodium_Core32_Int32 $x5 */ $x5 = $ctx[5]; /** @var ParagonIE_Sodium_Core32_Int32 $x6 */ $x6 = $ctx[6]; /** @var ParagonIE_Sodium_Core32_Int32 $x7 */ $x7 = $ctx[7]; /** @var ParagonIE_Sodium_Core32_Int32 $x8 */ $x8 = $ctx[8]; /** @var ParagonIE_Sodium_Core32_Int32 $x9 */ $x9 = $ctx[9]; /** @var ParagonIE_Sodium_Core32_Int32 $x10 */ $x10 = $ctx[10]; /** @var ParagonIE_Sodium_Core32_Int32 $x11 */ $x11 = $ctx[11]; /** @var ParagonIE_Sodium_Core32_Int32 $x12 */ $x12 = $ctx[12]; /** @var ParagonIE_Sodium_Core32_Int32 $x13 */ $x13 = $ctx[13]; /** @var ParagonIE_Sodium_Core32_Int32 $x14 */ $x14 = $ctx[14]; /** @var ParagonIE_Sodium_Core32_Int32 $x15 */ $x15 = $ctx[15]; for ($i = 0; $i < 10; ++$i) { # QUARTERROUND( x0, x4, x8, x12) list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12); # QUARTERROUND( x1, x5, x9, x13) list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13); # QUARTERROUND( x2, x6, x10, x14) list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14); # QUARTERROUND( x3, x7, x11, x15) list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15); # QUARTERROUND( x0, x5, x10, x15) list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15); # QUARTERROUND( x1, x6, x11, x12) list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12); # QUARTERROUND( x2, x7, x8, x13) list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13); # QUARTERROUND( x3, x4, x9, x14) list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14); } return $x0->toReverseString() . $x1->toReverseString() . $x2->toReverseString() . $x3->toReverseString() . $x12->toReverseString() . $x13->toReverseString() . $x14->toReverseString() . $x15->toReverseString(); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/X25519.php�����������������������������������������������������������������������������������0000644�����������������00000025442�15021200076�0007127 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_X25519', false)) { return; } /** * Class ParagonIE_Sodium_Core32_X25519 */ abstract class ParagonIE_Sodium_Core32_X25519 extends ParagonIE_Sodium_Core32_Curve25519 { /** * Alters the objects passed to this method in place. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @param ParagonIE_Sodium_Core32_Curve25519_Fe $g * @param int $b * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedMethodCall */ public static function fe_cswap( ParagonIE_Sodium_Core32_Curve25519_Fe $f, ParagonIE_Sodium_Core32_Curve25519_Fe $g, $b = 0 ) { $f0 = (int) $f[0]->toInt(); $f1 = (int) $f[1]->toInt(); $f2 = (int) $f[2]->toInt(); $f3 = (int) $f[3]->toInt(); $f4 = (int) $f[4]->toInt(); $f5 = (int) $f[5]->toInt(); $f6 = (int) $f[6]->toInt(); $f7 = (int) $f[7]->toInt(); $f8 = (int) $f[8]->toInt(); $f9 = (int) $f[9]->toInt(); $g0 = (int) $g[0]->toInt(); $g1 = (int) $g[1]->toInt(); $g2 = (int) $g[2]->toInt(); $g3 = (int) $g[3]->toInt(); $g4 = (int) $g[4]->toInt(); $g5 = (int) $g[5]->toInt(); $g6 = (int) $g[6]->toInt(); $g7 = (int) $g[7]->toInt(); $g8 = (int) $g[8]->toInt(); $g9 = (int) $g[9]->toInt(); $b = -$b; /** @var int $x0 */ $x0 = ($f0 ^ $g0) & $b; /** @var int $x1 */ $x1 = ($f1 ^ $g1) & $b; /** @var int $x2 */ $x2 = ($f2 ^ $g2) & $b; /** @var int $x3 */ $x3 = ($f3 ^ $g3) & $b; /** @var int $x4 */ $x4 = ($f4 ^ $g4) & $b; /** @var int $x5 */ $x5 = ($f5 ^ $g5) & $b; /** @var int $x6 */ $x6 = ($f6 ^ $g6) & $b; /** @var int $x7 */ $x7 = ($f7 ^ $g7) & $b; /** @var int $x8 */ $x8 = ($f8 ^ $g8) & $b; /** @var int $x9 */ $x9 = ($f9 ^ $g9) & $b; $f[0] = ParagonIE_Sodium_Core32_Int32::fromInt($f0 ^ $x0); $f[1] = ParagonIE_Sodium_Core32_Int32::fromInt($f1 ^ $x1); $f[2] = ParagonIE_Sodium_Core32_Int32::fromInt($f2 ^ $x2); $f[3] = ParagonIE_Sodium_Core32_Int32::fromInt($f3 ^ $x3); $f[4] = ParagonIE_Sodium_Core32_Int32::fromInt($f4 ^ $x4); $f[5] = ParagonIE_Sodium_Core32_Int32::fromInt($f5 ^ $x5); $f[6] = ParagonIE_Sodium_Core32_Int32::fromInt($f6 ^ $x6); $f[7] = ParagonIE_Sodium_Core32_Int32::fromInt($f7 ^ $x7); $f[8] = ParagonIE_Sodium_Core32_Int32::fromInt($f8 ^ $x8); $f[9] = ParagonIE_Sodium_Core32_Int32::fromInt($f9 ^ $x9); $g[0] = ParagonIE_Sodium_Core32_Int32::fromInt($g0 ^ $x0); $g[1] = ParagonIE_Sodium_Core32_Int32::fromInt($g1 ^ $x1); $g[2] = ParagonIE_Sodium_Core32_Int32::fromInt($g2 ^ $x2); $g[3] = ParagonIE_Sodium_Core32_Int32::fromInt($g3 ^ $x3); $g[4] = ParagonIE_Sodium_Core32_Int32::fromInt($g4 ^ $x4); $g[5] = ParagonIE_Sodium_Core32_Int32::fromInt($g5 ^ $x5); $g[6] = ParagonIE_Sodium_Core32_Int32::fromInt($g6 ^ $x6); $g[7] = ParagonIE_Sodium_Core32_Int32::fromInt($g7 ^ $x7); $g[8] = ParagonIE_Sodium_Core32_Int32::fromInt($g8 ^ $x8); $g[9] = ParagonIE_Sodium_Core32_Int32::fromInt($g9 ^ $x9); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $f * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError * @psalm-suppress MixedAssignment * @psalm-suppress MixedMethodCall */ public static function fe_mul121666(ParagonIE_Sodium_Core32_Curve25519_Fe $f) { /** @var array<int, ParagonIE_Sodium_Core32_Int64> $h */ $h = array(); for ($i = 0; $i < 10; ++$i) { $h[$i] = $f[$i]->toInt64()->mulInt(121666, 17); } $carry9 = $h[9]->addInt(1 << 24)->shiftRight(25); $h[0] = $h[0]->addInt64($carry9->mulInt(19, 5)); $h[9] = $h[9]->subInt64($carry9->shiftLeft(25)); $carry1 = $h[1]->addInt(1 << 24)->shiftRight(25); $h[2] = $h[2]->addInt64($carry1); $h[1] = $h[1]->subInt64($carry1->shiftLeft(25)); $carry3 = $h[3]->addInt(1 << 24)->shiftRight(25); $h[4] = $h[4]->addInt64($carry3); $h[3] = $h[3]->subInt64($carry3->shiftLeft(25)); $carry5 = $h[5]->addInt(1 << 24)->shiftRight(25); $h[6] = $h[6]->addInt64($carry5); $h[5] = $h[5]->subInt64($carry5->shiftLeft(25)); $carry7 = $h[7]->addInt(1 << 24)->shiftRight(25); $h[8] = $h[8]->addInt64($carry7); $h[7] = $h[7]->subInt64($carry7->shiftLeft(25)); $carry0 = $h[0]->addInt(1 << 25)->shiftRight(26); $h[1] = $h[1]->addInt64($carry0); $h[0] = $h[0]->subInt64($carry0->shiftLeft(26)); $carry2 = $h[2]->addInt(1 << 25)->shiftRight(26); $h[3] = $h[3]->addInt64($carry2); $h[2] = $h[2]->subInt64($carry2->shiftLeft(26)); $carry4 = $h[4]->addInt(1 << 25)->shiftRight(26); $h[5] = $h[5]->addInt64($carry4); $h[4] = $h[4]->subInt64($carry4->shiftLeft(26)); $carry6 = $h[6]->addInt(1 << 25)->shiftRight(26); $h[7] = $h[7]->addInt64($carry6); $h[6] = $h[6]->subInt64($carry6->shiftLeft(26)); $carry8 = $h[8]->addInt(1 << 25)->shiftRight(26); $h[9] = $h[9]->addInt64($carry8); $h[8] = $h[8]->subInt64($carry8->shiftLeft(26)); for ($i = 0; $i < 10; ++$i) { $h[$i] = $h[$i]->toInt32(); } /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h2 */ $h2 = $h; return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h2); } /** * @internal You should not use this directly from another application * * Inline comments preceded by # are from libsodium's ref10 code. * * @param string $n * @param string $p * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_scalarmult_curve25519_ref10($n, $p) { # for (i = 0;i < 32;++i) e[i] = n[i]; $e = '' . $n; # e[0] &= 248; $e[0] = self::intToChr( self::chrToInt($e[0]) & 248 ); # e[31] &= 127; # e[31] |= 64; $e[31] = self::intToChr( (self::chrToInt($e[31]) & 127) | 64 ); # fe_frombytes(x1,p); $x1 = self::fe_frombytes($p); # fe_1(x2); $x2 = self::fe_1(); # fe_0(z2); $z2 = self::fe_0(); # fe_copy(x3,x1); $x3 = self::fe_copy($x1); # fe_1(z3); $z3 = self::fe_1(); # swap = 0; /** @var int $swap */ $swap = 0; # for (pos = 254;pos >= 0;--pos) { for ($pos = 254; $pos >= 0; --$pos) { # b = e[pos / 8] >> (pos & 7); /** @var int $b */ $b = self::chrToInt( $e[(int) floor($pos / 8)] ) >> ($pos & 7); # b &= 1; $b &= 1; # swap ^= b; $swap ^= $b; # fe_cswap(x2,x3,swap); self::fe_cswap($x2, $x3, $swap); # fe_cswap(z2,z3,swap); self::fe_cswap($z2, $z3, $swap); # swap = b; /** @var int $swap */ $swap = $b; # fe_sub(tmp0,x3,z3); $tmp0 = self::fe_sub($x3, $z3); # fe_sub(tmp1,x2,z2); $tmp1 = self::fe_sub($x2, $z2); # fe_add(x2,x2,z2); $x2 = self::fe_add($x2, $z2); # fe_add(z2,x3,z3); $z2 = self::fe_add($x3, $z3); # fe_mul(z3,tmp0,x2); $z3 = self::fe_mul($tmp0, $x2); # fe_mul(z2,z2,tmp1); $z2 = self::fe_mul($z2, $tmp1); # fe_sq(tmp0,tmp1); $tmp0 = self::fe_sq($tmp1); # fe_sq(tmp1,x2); $tmp1 = self::fe_sq($x2); # fe_add(x3,z3,z2); $x3 = self::fe_add($z3, $z2); # fe_sub(z2,z3,z2); $z2 = self::fe_sub($z3, $z2); # fe_mul(x2,tmp1,tmp0); $x2 = self::fe_mul($tmp1, $tmp0); # fe_sub(tmp1,tmp1,tmp0); $tmp1 = self::fe_sub($tmp1, $tmp0); # fe_sq(z2,z2); $z2 = self::fe_sq($z2); # fe_mul121666(z3,tmp1); $z3 = self::fe_mul121666($tmp1); # fe_sq(x3,x3); $x3 = self::fe_sq($x3); # fe_add(tmp0,tmp0,z3); $tmp0 = self::fe_add($tmp0, $z3); # fe_mul(z3,x1,z2); $z3 = self::fe_mul($x1, $z2); # fe_mul(z2,tmp1,tmp0); $z2 = self::fe_mul($tmp1, $tmp0); } # fe_cswap(x2,x3,swap); self::fe_cswap($x2, $x3, $swap); # fe_cswap(z2,z3,swap); self::fe_cswap($z2, $z3, $swap); # fe_invert(z2,z2); $z2 = self::fe_invert($z2); # fe_mul(x2,x2,z2); $x2 = self::fe_mul($x2, $z2); # fe_tobytes(q,x2); return (string) self::fe_tobytes($x2); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY * @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ * @return ParagonIE_Sodium_Core32_Curve25519_Fe * @throws SodiumException * @throws TypeError */ public static function edwards_to_montgomery( ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY, ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ ) { $tempX = self::fe_add($edwardsZ, $edwardsY); $tempZ = self::fe_sub($edwardsZ, $edwardsY); $tempZ = self::fe_invert($tempZ); return self::fe_mul($tempX, $tempZ); } /** * @internal You should not use this directly from another application * * @param string $n * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_scalarmult_curve25519_ref10_base($n) { # for (i = 0;i < 32;++i) e[i] = n[i]; $e = '' . $n; # e[0] &= 248; $e[0] = self::intToChr( self::chrToInt($e[0]) & 248 ); # e[31] &= 127; # e[31] |= 64; $e[31] = self::intToChr( (self::chrToInt($e[31]) & 127) | 64 ); $A = self::ge_scalarmult_base($e); if ( !($A->Y instanceof ParagonIE_Sodium_Core32_Curve25519_Fe) || !($A->Z instanceof ParagonIE_Sodium_Core32_Curve25519_Fe) ) { throw new TypeError('Null points encountered'); } $pk = self::edwards_to_montgomery($A->Y, $A->Z); return self::fe_tobytes($pk); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/Util.php�������������������������������������������������������������������������������������0000644�����������������00000000321�15021200076�0007214 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_Util', false)) { return; } /** * Class ParagonIE_Sodium_Core_Util */ abstract class ParagonIE_Sodium_Core32_Util extends ParagonIE_Sodium_Core_Util { } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core32/ChaCha20.php���������������������������������������������������������������������������������0000644�����������������00000034257�15021200076�0007567 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php if (class_exists('ParagonIE_Sodium_Core32_ChaCha20', false)) { return; } /** * Class ParagonIE_Sodium_Core32_ChaCha20 */ class ParagonIE_Sodium_Core32_ChaCha20 extends ParagonIE_Sodium_Core32_Util { /** * The ChaCha20 quarter round function. Works on four 32-bit integers. * * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_Int32 $a * @param ParagonIE_Sodium_Core32_Int32 $b * @param ParagonIE_Sodium_Core32_Int32 $c * @param ParagonIE_Sodium_Core32_Int32 $d * @return array<int, ParagonIE_Sodium_Core32_Int32> * @throws SodiumException * @throws TypeError */ protected static function quarterRound( ParagonIE_Sodium_Core32_Int32 $a, ParagonIE_Sodium_Core32_Int32 $b, ParagonIE_Sodium_Core32_Int32 $c, ParagonIE_Sodium_Core32_Int32 $d ) { /** @var ParagonIE_Sodium_Core32_Int32 $a */ /** @var ParagonIE_Sodium_Core32_Int32 $b */ /** @var ParagonIE_Sodium_Core32_Int32 $c */ /** @var ParagonIE_Sodium_Core32_Int32 $d */ # a = PLUS(a,b); d = ROTATE(XOR(d,a),16); $a = $a->addInt32($b); $d = $d->xorInt32($a)->rotateLeft(16); # c = PLUS(c,d); b = ROTATE(XOR(b,c),12); $c = $c->addInt32($d); $b = $b->xorInt32($c)->rotateLeft(12); # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); $a = $a->addInt32($b); $d = $d->xorInt32($a)->rotateLeft(8); # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); $c = $c->addInt32($d); $b = $b->xorInt32($c)->rotateLeft(7); return array($a, $b, $c, $d); } /** * @internal You should not use this directly from another application * * @param ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx * @param string $message * * @return string * @throws SodiumException * @throws TypeError */ public static function encryptBytes( ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx, $message = '' ) { $bytes = self::strlen($message); /** @var ParagonIE_Sodium_Core32_Int32 $x0 */ /** @var ParagonIE_Sodium_Core32_Int32 $x1 */ /** @var ParagonIE_Sodium_Core32_Int32 $x2 */ /** @var ParagonIE_Sodium_Core32_Int32 $x3 */ /** @var ParagonIE_Sodium_Core32_Int32 $x4 */ /** @var ParagonIE_Sodium_Core32_Int32 $x5 */ /** @var ParagonIE_Sodium_Core32_Int32 $x6 */ /** @var ParagonIE_Sodium_Core32_Int32 $x7 */ /** @var ParagonIE_Sodium_Core32_Int32 $x8 */ /** @var ParagonIE_Sodium_Core32_Int32 $x9 */ /** @var ParagonIE_Sodium_Core32_Int32 $x10 */ /** @var ParagonIE_Sodium_Core32_Int32 $x11 */ /** @var ParagonIE_Sodium_Core32_Int32 $x12 */ /** @var ParagonIE_Sodium_Core32_Int32 $x13 */ /** @var ParagonIE_Sodium_Core32_Int32 $x14 */ /** @var ParagonIE_Sodium_Core32_Int32 $x15 */ /* j0 = ctx->input[0]; j1 = ctx->input[1]; j2 = ctx->input[2]; j3 = ctx->input[3]; j4 = ctx->input[4]; j5 = ctx->input[5]; j6 = ctx->input[6]; j7 = ctx->input[7]; j8 = ctx->input[8]; j9 = ctx->input[9]; j10 = ctx->input[10]; j11 = ctx->input[11]; j12 = ctx->input[12]; j13 = ctx->input[13]; j14 = ctx->input[14]; j15 = ctx->input[15]; */ /** @var ParagonIE_Sodium_Core32_Int32 $j0 */ $j0 = $ctx[0]; /** @var ParagonIE_Sodium_Core32_Int32 $j1 */ $j1 = $ctx[1]; /** @var ParagonIE_Sodium_Core32_Int32 $j2 */ $j2 = $ctx[2]; /** @var ParagonIE_Sodium_Core32_Int32 $j3 */ $j3 = $ctx[3]; /** @var ParagonIE_Sodium_Core32_Int32 $j4 */ $j4 = $ctx[4]; /** @var ParagonIE_Sodium_Core32_Int32 $j5 */ $j5 = $ctx[5]; /** @var ParagonIE_Sodium_Core32_Int32 $j6 */ $j6 = $ctx[6]; /** @var ParagonIE_Sodium_Core32_Int32 $j7 */ $j7 = $ctx[7]; /** @var ParagonIE_Sodium_Core32_Int32 $j8 */ $j8 = $ctx[8]; /** @var ParagonIE_Sodium_Core32_Int32 $j9 */ $j9 = $ctx[9]; /** @var ParagonIE_Sodium_Core32_Int32 $j10 */ $j10 = $ctx[10]; /** @var ParagonIE_Sodium_Core32_Int32 $j11 */ $j11 = $ctx[11]; /** @var ParagonIE_Sodium_Core32_Int32 $j12 */ $j12 = $ctx[12]; /** @var ParagonIE_Sodium_Core32_Int32 $j13 */ $j13 = $ctx[13]; /** @var ParagonIE_Sodium_Core32_Int32 $j14 */ $j14 = $ctx[14]; /** @var ParagonIE_Sodium_Core32_Int32 $j15 */ $j15 = $ctx[15]; $c = ''; for (;;) { if ($bytes < 64) { $message .= str_repeat("\x00", 64 - $bytes); } $x0 = clone $j0; $x1 = clone $j1; $x2 = clone $j2; $x3 = clone $j3; $x4 = clone $j4; $x5 = clone $j5; $x6 = clone $j6; $x7 = clone $j7; $x8 = clone $j8; $x9 = clone $j9; $x10 = clone $j10; $x11 = clone $j11; $x12 = clone $j12; $x13 = clone $j13; $x14 = clone $j14; $x15 = clone $j15; # for (i = 20; i > 0; i -= 2) { for ($i = 20; $i > 0; $i -= 2) { # QUARTERROUND( x0, x4, x8, x12) list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12); # QUARTERROUND( x1, x5, x9, x13) list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13); # QUARTERROUND( x2, x6, x10, x14) list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14); # QUARTERROUND( x3, x7, x11, x15) list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15); # QUARTERROUND( x0, x5, x10, x15) list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15); # QUARTERROUND( x1, x6, x11, x12) list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12); # QUARTERROUND( x2, x7, x8, x13) list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13); # QUARTERROUND( x3, x4, x9, x14) list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14); } /* x0 = PLUS(x0, j0); x1 = PLUS(x1, j1); x2 = PLUS(x2, j2); x3 = PLUS(x3, j3); x4 = PLUS(x4, j4); x5 = PLUS(x5, j5); x6 = PLUS(x6, j6); x7 = PLUS(x7, j7); x8 = PLUS(x8, j8); x9 = PLUS(x9, j9); x10 = PLUS(x10, j10); x11 = PLUS(x11, j11); x12 = PLUS(x12, j12); x13 = PLUS(x13, j13); x14 = PLUS(x14, j14); x15 = PLUS(x15, j15); */ $x0 = $x0->addInt32($j0); $x1 = $x1->addInt32($j1); $x2 = $x2->addInt32($j2); $x3 = $x3->addInt32($j3); $x4 = $x4->addInt32($j4); $x5 = $x5->addInt32($j5); $x6 = $x6->addInt32($j6); $x7 = $x7->addInt32($j7); $x8 = $x8->addInt32($j8); $x9 = $x9->addInt32($j9); $x10 = $x10->addInt32($j10); $x11 = $x11->addInt32($j11); $x12 = $x12->addInt32($j12); $x13 = $x13->addInt32($j13); $x14 = $x14->addInt32($j14); $x15 = $x15->addInt32($j15); /* x0 = XOR(x0, LOAD32_LE(m + 0)); x1 = XOR(x1, LOAD32_LE(m + 4)); x2 = XOR(x2, LOAD32_LE(m + 8)); x3 = XOR(x3, LOAD32_LE(m + 12)); x4 = XOR(x4, LOAD32_LE(m + 16)); x5 = XOR(x5, LOAD32_LE(m + 20)); x6 = XOR(x6, LOAD32_LE(m + 24)); x7 = XOR(x7, LOAD32_LE(m + 28)); x8 = XOR(x8, LOAD32_LE(m + 32)); x9 = XOR(x9, LOAD32_LE(m + 36)); x10 = XOR(x10, LOAD32_LE(m + 40)); x11 = XOR(x11, LOAD32_LE(m + 44)); x12 = XOR(x12, LOAD32_LE(m + 48)); x13 = XOR(x13, LOAD32_LE(m + 52)); x14 = XOR(x14, LOAD32_LE(m + 56)); x15 = XOR(x15, LOAD32_LE(m + 60)); */ $x0 = $x0->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4))); $x1 = $x1->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 4, 4))); $x2 = $x2->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 8, 4))); $x3 = $x3->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4))); $x4 = $x4->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 16, 4))); $x5 = $x5->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 20, 4))); $x6 = $x6->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 24, 4))); $x7 = $x7->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 28, 4))); $x8 = $x8->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 32, 4))); $x9 = $x9->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 36, 4))); $x10 = $x10->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 40, 4))); $x11 = $x11->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 44, 4))); $x12 = $x12->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 48, 4))); $x13 = $x13->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 52, 4))); $x14 = $x14->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 56, 4))); $x15 = $x15->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 60, 4))); /* j12 = PLUSONE(j12); if (!j12) { j13 = PLUSONE(j13); } */ /** @var ParagonIE_Sodium_Core32_Int32 $j12 */ $j12 = $j12->addInt(1); if ($j12->limbs[0] === 0 && $j12->limbs[1] === 0) { $j13 = $j13->addInt(1); } /* STORE32_LE(c + 0, x0); STORE32_LE(c + 4, x1); STORE32_LE(c + 8, x2); STORE32_LE(c + 12, x3); STORE32_LE(c + 16, x4); STORE32_LE(c + 20, x5); STORE32_LE(c + 24, x6); STORE32_LE(c + 28, x7); STORE32_LE(c + 32, x8); STORE32_LE(c + 36, x9); STORE32_LE(c + 40, x10); STORE32_LE(c + 44, x11); STORE32_LE(c + 48, x12); STORE32_LE(c + 52, x13); STORE32_LE(c + 56, x14); STORE32_LE(c + 60, x15); */ $block = $x0->toReverseString() . $x1->toReverseString() . $x2->toReverseString() . $x3->toReverseString() . $x4->toReverseString() . $x5->toReverseString() . $x6->toReverseString() . $x7->toReverseString() . $x8->toReverseString() . $x9->toReverseString() . $x10->toReverseString() . $x11->toReverseString() . $x12->toReverseString() . $x13->toReverseString() . $x14->toReverseString() . $x15->toReverseString(); /* Partial block */ if ($bytes < 64) { $c .= self::substr($block, 0, $bytes); break; } /* Full block */ $c .= $block; $bytes -= 64; if ($bytes <= 0) { break; } $message = self::substr($message, 64); } /* end for(;;) loop */ $ctx[12] = $j12; $ctx[13] = $j13; return $c; } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function stream($len = 64, $nonce = '', $key = '') { return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param int $len * @param string $nonce * @param string $key * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStream($len, $nonce = '', $key = '') { return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce), str_repeat("\x00", $len) ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce, $ic), $message ); } /** * @internal You should not use this directly from another application * * @param string $message * @param string $nonce * @param string $key * @param string $ic * @return string * @throws SodiumException * @throws TypeError */ public static function streamXorIc($message, $nonce = '', $key = '', $ic = '') { return self::encryptBytes( new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce, $ic), $message ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Compat.php������������������������������������������������������������������������������������������0000644�����������������00000500364�15021200076�0006501 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Libsodium compatibility layer * * This is the only class you should be interfacing with, as a user of * sodium_compat. * * If the PHP extension for libsodium is installed, it will always use that * instead of our implementations. You get better performance and stronger * guarantees against side-channels that way. * * However, if your users don't have the PHP extension installed, we offer a * compatible interface here. It will give you the correct results as if the * PHP extension was installed. It won't be as fast, of course. * * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * * * * Until audited, this is probably not safe to use! DANGER WILL ROBINSON * * * * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * */ if (class_exists('ParagonIE_Sodium_Compat', false)) { return; } class ParagonIE_Sodium_Compat { /** * This parameter prevents the use of the PECL extension. * It should only be used for unit testing. * * @var bool */ public static $disableFallbackForUnitTests = false; /** * Use fast multiplication rather than our constant-time multiplication * implementation. Can be enabled at runtime. Only enable this if you * are absolutely certain that there is no timing leak on your platform. * * @var bool */ public static $fastMult = false; const LIBRARY_MAJOR_VERSION = 9; const LIBRARY_MINOR_VERSION = 1; const LIBRARY_VERSION_MAJOR = 9; const LIBRARY_VERSION_MINOR = 1; const VERSION_STRING = 'polyfill-1.0.8'; // From libsodium const BASE64_VARIANT_ORIGINAL = 1; const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3; const BASE64_VARIANT_URLSAFE = 5; const BASE64_VARIANT_URLSAFE_NO_PADDING = 7; const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32; const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0; const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12; const CRYPTO_AEAD_AES256GCM_ABYTES = 16; const CRYPTO_AEAD_AEGIS128L_KEYBYTES = 16; const CRYPTO_AEAD_AEGIS128L_NSECBYTES = 0; const CRYPTO_AEAD_AEGIS128L_NPUBBYTES = 16; const CRYPTO_AEAD_AEGIS128L_ABYTES = 32; const CRYPTO_AEAD_AEGIS256_KEYBYTES = 32; const CRYPTO_AEAD_AEGIS256_NSECBYTES = 0; const CRYPTO_AEAD_AEGIS256_NPUBBYTES = 32; const CRYPTO_AEAD_AEGIS256_ABYTES = 32; const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32; const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0; const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8; const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12; const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24; const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16; const CRYPTO_AUTH_BYTES = 32; const CRYPTO_AUTH_KEYBYTES = 32; const CRYPTO_BOX_SEALBYTES = 16; const CRYPTO_BOX_SECRETKEYBYTES = 32; const CRYPTO_BOX_PUBLICKEYBYTES = 32; const CRYPTO_BOX_KEYPAIRBYTES = 64; const CRYPTO_BOX_MACBYTES = 16; const CRYPTO_BOX_NONCEBYTES = 24; const CRYPTO_BOX_SEEDBYTES = 32; const CRYPTO_CORE_RISTRETTO255_BYTES = 32; const CRYPTO_CORE_RISTRETTO255_SCALARBYTES = 32; const CRYPTO_CORE_RISTRETTO255_HASHBYTES = 64; const CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES = 64; const CRYPTO_KDF_BYTES_MIN = 16; const CRYPTO_KDF_BYTES_MAX = 64; const CRYPTO_KDF_CONTEXTBYTES = 8; const CRYPTO_KDF_KEYBYTES = 32; const CRYPTO_KX_BYTES = 32; const CRYPTO_KX_PRIMITIVE = 'x25519blake2b'; const CRYPTO_KX_SEEDBYTES = 32; const CRYPTO_KX_KEYPAIRBYTES = 64; const CRYPTO_KX_PUBLICKEYBYTES = 32; const CRYPTO_KX_SECRETKEYBYTES = 32; const CRYPTO_KX_SESSIONKEYBYTES = 32; const CRYPTO_GENERICHASH_BYTES = 32; const CRYPTO_GENERICHASH_BYTES_MIN = 16; const CRYPTO_GENERICHASH_BYTES_MAX = 64; const CRYPTO_GENERICHASH_KEYBYTES = 32; const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16; const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64; const CRYPTO_PWHASH_SALTBYTES = 16; const CRYPTO_PWHASH_STRPREFIX = '$argon2id$'; const CRYPTO_PWHASH_ALG_ARGON2I13 = 1; const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2; const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432; const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4; const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728; const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6; const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912; const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$'; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432; const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824; const CRYPTO_SCALARMULT_BYTES = 32; const CRYPTO_SCALARMULT_SCALARBYTES = 32; const CRYPTO_SCALARMULT_RISTRETTO255_BYTES = 32; const CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES = 32; const CRYPTO_SHORTHASH_BYTES = 8; const CRYPTO_SHORTHASH_KEYBYTES = 16; const CRYPTO_SECRETBOX_KEYBYTES = 32; const CRYPTO_SECRETBOX_MACBYTES = 16; const CRYPTO_SECRETBOX_NONCEBYTES = 24; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3; const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80; const CRYPTO_SIGN_BYTES = 64; const CRYPTO_SIGN_SEEDBYTES = 32; const CRYPTO_SIGN_PUBLICKEYBYTES = 32; const CRYPTO_SIGN_SECRETKEYBYTES = 64; const CRYPTO_SIGN_KEYPAIRBYTES = 96; const CRYPTO_STREAM_KEYBYTES = 32; const CRYPTO_STREAM_NONCEBYTES = 24; const CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32; const CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24; /** * Add two numbers (little-endian unsigned), storing the value in the first * parameter. * * This mutates $val. * * @param string $val * @param string $addv * @return void * @throws SodiumException */ public static function add( #[\SensitiveParameter] &$val, #[\SensitiveParameter] $addv ) { $val_len = ParagonIE_Sodium_Core_Util::strlen($val); $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv); if ($val_len !== $addv_len) { throw new SodiumException('values must have the same length'); } $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val); $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv); $c = 0; for ($i = 0; $i < $val_len; $i++) { $c += ($A[$i] + $B[$i]); $A[$i] = ($c & 0xff); $c >>= 8; } $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); } /** * @param string $encoded * @param int $variant * @param string $ignore * @return string * @throws SodiumException */ public static function base642bin( #[\SensitiveParameter] $encoded, $variant, $ignore = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($encoded, 'string', 1); /** @var string $encoded */ $encoded = (string) $encoded; if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) { return ''; } // Just strip before decoding if (!empty($ignore)) { $encoded = str_replace($ignore, '', $encoded); } try { switch ($variant) { case self::BASE64_VARIANT_ORIGINAL: return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true); case self::BASE64_VARIANT_ORIGINAL_NO_PADDING: return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false); case self::BASE64_VARIANT_URLSAFE: return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true); case self::BASE64_VARIANT_URLSAFE_NO_PADDING: return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false); default: throw new SodiumException('invalid base64 variant identifier'); } } catch (Exception $ex) { if ($ex instanceof SodiumException) { throw $ex; } throw new SodiumException('invalid base64 string'); } } /** * @param string $decoded * @param int $variant * @return string * @throws SodiumException */ public static function bin2base64( #[\SensitiveParameter] $decoded, $variant ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($decoded, 'string', 1); /** @var string $decoded */ $decoded = (string) $decoded; if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) { return ''; } switch ($variant) { case self::BASE64_VARIANT_ORIGINAL: return ParagonIE_Sodium_Core_Base64_Original::encode($decoded); case self::BASE64_VARIANT_ORIGINAL_NO_PADDING: return ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded); case self::BASE64_VARIANT_URLSAFE: return ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded); case self::BASE64_VARIANT_URLSAFE_NO_PADDING: return ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded); default: throw new SodiumException('invalid base64 variant identifier'); } } /** * Cache-timing-safe implementation of bin2hex(). * * @param string $string A string (probably raw binary) * @return string A hexadecimal-encoded string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function bin2hex( #[\SensitiveParameter] $string ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1); if (self::useNewSodiumAPI()) { return (string) sodium_bin2hex($string); } if (self::use_fallback('bin2hex')) { return (string) call_user_func('\\Sodium\\bin2hex', $string); } return ParagonIE_Sodium_Core_Util::bin2hex($string); } /** * Compare two strings, in constant-time. * Compared to memcmp(), compare() is more useful for sorting. * * @param string $left The left operand; must be a string * @param string $right The right operand; must be a string * @return int If < 0 if the left operand is less than the right * If = 0 if both strings are equal * If > 0 if the right operand is less than the left * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function compare( #[\SensitiveParameter] $left, #[\SensitiveParameter] $right ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); if (self::useNewSodiumAPI()) { return (int) sodium_compare($left, $right); } if (self::use_fallback('compare')) { return (int) call_user_func('\\Sodium\\compare', $left, $right); } return ParagonIE_Sodium_Core_Util::compare($left, $right); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * AEGIS-128L * * @param string $ciphertext Encrypted message (with MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 32 bytes * @param string $key Encryption key * * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_aegis128l_decrypt( $ciphertext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS_128L_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); } $ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext); if ($ct_length < self::CRYPTO_AEAD_AEGIS128L_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS128L_ABYTES long'); } $ct = ParagonIE_Sodium_Core_Util::substr( $ciphertext, 0, $ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES ); $tag = ParagonIE_Sodium_Core_Util::substr( $ciphertext, $ct_length - self::CRYPTO_AEAD_AEGIS128L_ABYTES, self::CRYPTO_AEAD_AEGIS128L_ABYTES ); return ParagonIE_Sodium_Core_AEGIS128L::decrypt($ct, $tag, $assocData, $key, $nonce); } /** * Authenticated Encryption with Associated Data: Encryption * * Algorithm: * AEGIS-128L * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 32 bytes * @param string $key Encryption key * * @return string Ciphertext with 32-byte authentication tag appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_aegis128l_encrypt( #[\SensitiveParameter] $plaintext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS128L_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS128L_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); } list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS128L::encrypt($plaintext, $assocData, $key, $nonce); return $ct . $tag; } /** * Return a secure random key for use with the AEGIS-128L * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_aegis128l_keygen() { return random_bytes(self::CRYPTO_AEAD_AEGIS128L_KEYBYTES); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * AEGIS-256 * * @param string $ciphertext Encrypted message (with MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 32 bytes * @param string $key Encryption key * * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_aegis256_decrypt( $ciphertext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS256_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS256_KEYBYTES long'); } $ct_length = ParagonIE_Sodium_Core_Util::strlen($ciphertext); if ($ct_length < self::CRYPTO_AEAD_AEGIS256_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_AEGIS256_ABYTES long'); } $ct = ParagonIE_Sodium_Core_Util::substr( $ciphertext, 0, $ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES ); $tag = ParagonIE_Sodium_Core_Util::substr( $ciphertext, $ct_length - self::CRYPTO_AEAD_AEGIS256_ABYTES, self::CRYPTO_AEAD_AEGIS256_ABYTES ); return ParagonIE_Sodium_Core_AEGIS256::decrypt($ct, $tag, $assocData, $key, $nonce); } /** * Authenticated Encryption with Associated Data: Encryption * * Algorithm: * AEGIS-256 * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 32 bytes * @param string $key Encryption key * * @return string Ciphertext with 32-byte authentication tag appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_aegis256_encrypt( #[\SensitiveParameter] $plaintext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AEGIS256_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AEGIS256_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AEGIS128L_KEYBYTES long'); } list($ct, $tag) = ParagonIE_Sodium_Core_AEGIS256::encrypt($plaintext, $assocData, $key, $nonce); return $ct . $tag; } /** * Return a secure random key for use with the AEGIS-256 * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_aegis256_keygen() { return random_bytes(self::CRYPTO_AEAD_AEGIS256_KEYBYTES); } /** * Is AES-256-GCM even available to use? * * @return bool * @psalm-suppress UndefinedFunction * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_aes256gcm_is_available() { if (self::useNewSodiumAPI()) { return sodium_crypto_aead_aes256gcm_is_available(); } if (self::use_fallback('crypto_aead_aes256gcm_is_available')) { return call_user_func('\\Sodium\\crypto_aead_aes256gcm_is_available'); } if (PHP_VERSION_ID < 70100) { // OpenSSL doesn't support AEAD before 7.1.0 return false; } if (!is_callable('openssl_encrypt') || !is_callable('openssl_decrypt')) { // OpenSSL isn't installed return false; } return (bool) in_array('aes-256-gcm', openssl_get_cipher_methods()); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * AES-256-GCM * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string|bool The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_aes256gcm_decrypt( $ciphertext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { if (!self::crypto_aead_aes256gcm_is_available()) { throw new SodiumException('AES-256-GCM is not available'); } ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_AES256GCM_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_AES256GCM_ABYTES long'); } if (!is_callable('openssl_decrypt')) { throw new SodiumException('The OpenSSL extension is not installed, or openssl_decrypt() is not available'); } /** @var string $ctext */ $ctext = ParagonIE_Sodium_Core_Util::substr($ciphertext, 0, -self::CRYPTO_AEAD_AES256GCM_ABYTES); /** @var string $authTag */ $authTag = ParagonIE_Sodium_Core_Util::substr($ciphertext, -self::CRYPTO_AEAD_AES256GCM_ABYTES, 16); return openssl_decrypt( $ctext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $authTag, $assocData ); } /** * Authenticated Encryption with Associated Data: Encryption * * Algorithm: * AES-256-GCM * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string Ciphertext with a 16-byte GCM message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_aes256gcm_encrypt( #[\SensitiveParameter] $plaintext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { if (!self::crypto_aead_aes256gcm_is_available()) { throw new SodiumException('AES-256-GCM is not available'); } ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long'); } if (!is_callable('openssl_encrypt')) { throw new SodiumException('The OpenSSL extension is not installed, or openssl_encrypt() is not available'); } $authTag = ''; $ciphertext = openssl_encrypt( $plaintext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $nonce, $authTag, $assocData ); return $ciphertext . $authTag; } /** * Return a secure random key for use with the AES-256-GCM * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_aes256gcm_keygen() { return random_bytes(self::CRYPTO_AEAD_AES256GCM_KEYBYTES); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * ChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_chacha20poly1305_decrypt( $ciphertext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_aead_chacha20poly1305_decrypt( $ciphertext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) { return call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_decrypt', $ciphertext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt( $ciphertext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt( $ciphertext, $assocData, $nonce, $key ); } /** * Authenticated Encryption with Associated Data * * Algorithm: * ChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string Ciphertext with a 16-byte Poly1305 message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_chacha20poly1305_encrypt( #[\SensitiveParameter] $plaintext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_aead_chacha20poly1305_encrypt( $plaintext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) { return (string) call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_encrypt', $plaintext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt( $plaintext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt( $plaintext, $assocData, $nonce, $key ); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * ChaCha20-Poly1305 * * IETF mode uses a 96-bit random nonce with a 32-bit counter. * Regular mode uses a 64-bit random nonce with a 64-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 12 bytes * @param string $key Encryption key * * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_aead_chacha20poly1305_ietf_decrypt( $ciphertext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_aead_chacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) { return call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt', $ciphertext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } /** * Return a secure random key for use with the ChaCha20-Poly1305 * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_chacha20poly1305_keygen() { return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES); } /** * Authenticated Encryption with Associated Data * * Algorithm: * ChaCha20-Poly1305 * * IETF mode uses a 96-bit random nonce with a 32-bit counter. * Regular mode uses a 64-bit random nonce with a 64-bit counter. * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * * @return string Ciphertext with a 16-byte Poly1305 message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_chacha20poly1305_ietf_encrypt( #[\SensitiveParameter] $plaintext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); if (!is_null($assocData)) { ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); } ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_aead_chacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) { return (string) call_user_func( '\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt', $plaintext, $assocData, $nonce, $key ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } /** * Return a secure random key for use with the ChaCha20-Poly1305 * symmetric AEAD interface. (IETF version) * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_chacha20poly1305_ietf_keygen() { return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES); } /** * Authenticated Encryption with Associated Data: Decryption * * Algorithm: * XChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * @param bool $dontFallback Don't fallback to ext/sodium * * @return string|bool The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_xchacha20poly1305_ietf_decrypt( $ciphertext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '', $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); if (!is_null($assocData)) { ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); } else { $assocData = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) { throw new SodiumException('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long'); } if (self::useNewSodiumAPI() && !$dontFallback) { if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) { return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt( $ciphertext, $assocData, $nonce, $key ); } /** * Authenticated Encryption with Associated Data * * Algorithm: * XChaCha20-Poly1305 * * This mode uses a 64-bit random nonce with a 64-bit counter. * IETF mode uses a 96-bit random nonce with a 32-bit counter. * * @param string $plaintext Message to be encrypted * @param string $assocData Authenticated Associated Data (unencrypted) * @param string $nonce Number to be used only Once; must be 8 bytes * @param string $key Encryption key * @param bool $dontFallback Don't fallback to ext/sodium * * @return string Ciphertext with a 16-byte Poly1305 message * authentication code appended * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_aead_xchacha20poly1305_ietf_encrypt( #[\SensitiveParameter] $plaintext = '', $assocData = '', $nonce = '', #[\SensitiveParameter] $key = '', $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); if (!is_null($assocData)) { ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2); } else { $assocData = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long'); } if (self::useNewSodiumAPI() && !$dontFallback) { if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) { return sodium_crypto_aead_xchacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt( $plaintext, $assocData, $nonce, $key ); } /** * Return a secure random key for use with the XChaCha20-Poly1305 * symmetric AEAD interface. * * @return string * @throws Exception * @throws Error */ public static function crypto_aead_xchacha20poly1305_ietf_keygen() { return random_bytes(self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES); } /** * Authenticate a message. Uses symmetric-key cryptography. * * Algorithm: * HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits. * Not to be confused with HMAC-SHA-512/256 which would use the * SHA-512/256 hash function (uses different initial parameters * but still truncates to 256 bits to sidestep length-extension * attacks). * * @param string $message Message to be authenticated * @param string $key Symmetric authentication key * @return string Message authentication code * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_auth( $message, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_auth($message, $key); } if (self::use_fallback('crypto_auth')) { return (string) call_user_func('\\Sodium\\crypto_auth', $message, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::auth($message, $key); } return ParagonIE_Sodium_Crypto::auth($message, $key); } /** * @return string * @throws Exception * @throws Error */ public static function crypto_auth_keygen() { return random_bytes(self::CRYPTO_AUTH_KEYBYTES); } /** * Verify the MAC of a message previously authenticated with crypto_auth. * * @param string $mac Message authentication code * @param string $message Message whose authenticity you are attempting to * verify (with a given MAC and key) * @param string $key Symmetric authentication key * @return bool TRUE if authenticated, FALSE otherwise * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_auth_verify( $mac, $message, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($mac, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) { throw new SodiumException('Argument 1 must be CRYPTO_AUTH_BYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (bool) sodium_crypto_auth_verify($mac, $message, $key); } if (self::use_fallback('crypto_auth_verify')) { return (bool) call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message, $key); } return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key); } /** * Authenticated asymmetric-key encryption. Both the sender and recipient * may decrypt messages. * * Algorithm: X25519-XSalsa20-Poly1305. * X25519: Elliptic-Curve Diffie Hellman over Curve25519. * XSalsa20: Extended-nonce variant of salsa20. * Poyl1305: Polynomial MAC for one-time message authentication. * * @param string $plaintext The message to be encrypted * @param string $nonce A Number to only be used Once; must be 24 bytes * @param string $keypair Your secret key and your recipient's public key * @return string Ciphertext with 16-byte Poly1305 MAC * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box( $plaintext, $nonce, #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box($plaintext, $nonce, $keypair); } if (self::use_fallback('crypto_box')) { return (string) call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce, $keypair); } return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair); } /** * Anonymous public-key encryption. Only the recipient may decrypt messages. * * Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box. * The sender's X25519 keypair is ephemeral. * Nonce is generated from the BLAKE2b hash of both public keys. * * This provides ciphertext integrity. * * @param string $plaintext Message to be sealed * @param string $publicKey Your recipient's public key * @return string Sealed message that only your recipient can * decrypt * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_seal( #[\SensitiveParameter] $plaintext, $publicKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_seal($plaintext, $publicKey); } if (self::use_fallback('crypto_box_seal')) { return (string) call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_seal($plaintext, $publicKey); } return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey); } /** * Opens a message encrypted with crypto_box_seal(). Requires * the recipient's keypair (sk || pk) to decrypt successfully. * * This validates ciphertext integrity. * * @param string $ciphertext Sealed message to be opened * @param string $keypair Your crypto_box keypair * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_box_seal_open( $ciphertext, #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_box_seal_open($ciphertext, $keypair); } if (self::use_fallback('crypto_box_seal_open')) { return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext, $keypair); } return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair); } /** * Generate a new random X25519 keypair. * * @return string A 64-byte string; the first 32 are your secret key, while * the last 32 are your public key. crypto_box_secretkey() * and crypto_box_publickey() exist to separate them so you * don't accidentally get them mixed up! * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_keypair() { if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_keypair(); } if (self::use_fallback('crypto_box_keypair')) { return (string) call_user_func('\\Sodium\\crypto_box_keypair'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_keypair(); } return ParagonIE_Sodium_Crypto::box_keypair(); } /** * Combine two keys into a keypair for use in library methods that expect * a keypair. This doesn't necessarily have to be the same person's keys. * * @param string $secretKey Secret key * @param string $publicKey Public key * @return string Keypair * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_keypair_from_secretkey_and_publickey( #[\SensitiveParameter] $secretKey, $publicKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); } if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) { return (string) call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); } return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); } /** * Decrypt a message previously encrypted with crypto_box(). * * @param string $ciphertext Encrypted message * @param string $nonce Number to only be used Once; must be 24 bytes * @param string $keypair Your secret key and the sender's public key * @return string The original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_box_open( $ciphertext, $nonce, #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_box_open($ciphertext, $nonce, $keypair); } if (self::use_fallback('crypto_box_open')) { return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce, $keypair); } return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair); } /** * Extract the public key from a crypto_box keypair. * * @param string $keypair Keypair containing secret and public key * @return string Your crypto_box public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_publickey( #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_publickey($keypair); } if (self::use_fallback('crypto_box_publickey')) { return (string) call_user_func('\\Sodium\\crypto_box_publickey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_publickey($keypair); } return ParagonIE_Sodium_Crypto::box_publickey($keypair); } /** * Calculate the X25519 public key from a given X25519 secret key. * * @param string $secretKey Any X25519 secret key * @return string The corresponding X25519 public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_publickey_from_secretkey( #[\SensitiveParameter] $secretKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_publickey_from_secretkey($secretKey); } if (self::use_fallback('crypto_box_publickey_from_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey); } return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey); } /** * Extract the secret key from a crypto_box keypair. * * @param string $keypair * @return string Your crypto_box secret key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_box_secretkey( #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_secretkey($keypair); } if (self::use_fallback('crypto_box_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_box_secretkey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_secretkey($keypair); } return ParagonIE_Sodium_Crypto::box_secretkey($keypair); } /** * Generate an X25519 keypair from a seed. * * @param string $seed * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress UndefinedFunction */ public static function crypto_box_seed_keypair( #[\SensitiveParameter] $seed ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); if (self::useNewSodiumAPI()) { return (string) sodium_crypto_box_seed_keypair($seed); } if (self::use_fallback('crypto_box_seed_keypair')) { return (string) call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::box_seed_keypair($seed); } return ParagonIE_Sodium_Crypto::box_seed_keypair($seed); } /** * Calculates a BLAKE2b hash, with an optional key. * * @param string $message The message to be hashed * @param string|null $key If specified, must be a string between 16 * and 64 bytes long * @param int $length Output length in bytes; must be between 16 * and 64 (default = 32) * @return string Raw binary * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_generichash( $message, #[\SensitiveParameter] $key = '', $length = self::CRYPTO_GENERICHASH_BYTES ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); if (is_null($key)) { $key = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 3); /* Input validation: */ if (!empty($key)) { if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); } } if (self::useNewSodiumAPI()) { return (string) sodium_crypto_generichash($message, $key, $length); } if (self::use_fallback('crypto_generichash')) { return (string) call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::generichash($message, $key, $length); } return ParagonIE_Sodium_Crypto::generichash($message, $key, $length); } /** * Get the final BLAKE2b hash output for a given context. * * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). * @param int $length Hash output size. * @return string Final BLAKE2b hash. * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress ReferenceConstraintViolation * @psalm-suppress ConflictingReferenceConstraint */ public static function crypto_generichash_final( #[\SensitiveParameter] &$ctx, $length = self::CRYPTO_GENERICHASH_BYTES ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); if (self::useNewSodiumAPI()) { return sodium_crypto_generichash_final($ctx, $length); } if (self::use_fallback('crypto_generichash_final')) { $func = '\\Sodium\\crypto_generichash_final'; return (string) $func($ctx, $length); } if ($length < 1) { try { self::memzero($ctx); } catch (SodiumException $ex) { unset($ctx); } return ''; } if (PHP_INT_SIZE === 4) { $result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length); } else { $result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length); } try { self::memzero($ctx); } catch (SodiumException $ex) { unset($ctx); } return $result; } /** * Initialize a BLAKE2b hashing context, for use in a streaming interface. * * @param string|null $key If specified must be a string between 16 and 64 bytes * @param int $length The size of the desired hash output * @return string A BLAKE2 hashing context, encoded as a string * (To be 100% compatible with ext/libsodium) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_generichash_init( #[\SensitiveParameter] $key = '', $length = self::CRYPTO_GENERICHASH_BYTES ) { /* Type checks: */ if (is_null($key)) { $key = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); /* Input validation: */ if (!empty($key)) { if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); } } if (self::useNewSodiumAPI()) { return sodium_crypto_generichash_init($key, $length); } if (self::use_fallback('crypto_generichash_init')) { return (string) call_user_func('\\Sodium\\crypto_generichash_init', $key, $length); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::generichash_init($key, $length); } return ParagonIE_Sodium_Crypto::generichash_init($key, $length); } /** * Initialize a BLAKE2b hashing context, for use in a streaming interface. * * @param string|null $key If specified must be a string between 16 and 64 bytes * @param int $length The size of the desired hash output * @param string $salt Salt (up to 16 bytes) * @param string $personal Personalization string (up to 16 bytes) * @return string A BLAKE2 hashing context, encoded as a string * (To be 100% compatible with ext/libsodium) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_generichash_init_salt_personal( #[\SensitiveParameter] $key = '', $length = self::CRYPTO_GENERICHASH_BYTES, $salt = '', $personal = '' ) { /* Type checks: */ if (is_null($key)) { $key = ''; } ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($personal, 'string', 4); $salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT); $personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT); /* Input validation: */ if (!empty($key)) { /* if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); } */ if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); } } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length, $salt, $personal); } return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal); } /** * Update a BLAKE2b hashing context with additional data. * * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). * $ctx is passed by reference and gets updated in-place. * @param-out string $ctx * @param string $message The message to append to the existing hash state. * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress ReferenceConstraintViolation */ public static function crypto_generichash_update( #[\SensitiveParameter] &$ctx, $message ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); if (self::useNewSodiumAPI()) { sodium_crypto_generichash_update($ctx, $message); return; } if (self::use_fallback('crypto_generichash_update')) { $func = '\\Sodium\\crypto_generichash_update'; $func($ctx, $message); return; } if (PHP_INT_SIZE === 4) { $ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx, $message); } else { $ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message); } } /** * @return string * @throws Exception * @throws Error */ public static function crypto_generichash_keygen() { return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES); } /** * @param int $subkey_len * @param int $subkey_id * @param string $context * @param string $key * @return string * @throws SodiumException */ public static function crypto_kdf_derive_from_key( $subkey_len, $subkey_id, $context, #[\SensitiveParameter] $key ) { ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($context, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); $subkey_id = (int) $subkey_id; $subkey_len = (int) $subkey_len; $context = (string) $context; $key = (string) $key; if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) { throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN'); } if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) { throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX'); } if ($subkey_id < 0) { throw new SodiumException('subkey_id cannot be negative'); } if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) { throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) { throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes'); } $salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id); $state = self::crypto_generichash_init_salt_personal( $key, $subkey_len, $salt, $context ); return self::crypto_generichash_final($state, $subkey_len); } /** * @return string * @throws Exception * @throws Error */ public static function crypto_kdf_keygen() { return random_bytes(self::CRYPTO_KDF_KEYBYTES); } /** * Perform a key exchange, between a designated client and a server. * * Typically, you would designate one machine to be the client and the * other to be the server. The first two keys are what you'd expect for * scalarmult() below, but the latter two public keys don't swap places. * * | ALICE | BOB | * | Client | Server | * |--------------------------------|-------------------------------------| * | shared = crypto_kx( | shared = crypto_kx( | * | alice_sk, | bob_sk, | <- contextual * | bob_pk, | alice_pk, | <- contextual * | alice_pk, | alice_pk, | <----- static * | bob_pk | bob_pk | <----- static * | ) | ) | * * They are used along with the scalarmult product to generate a 256-bit * BLAKE2b hash unique to the client and server keys. * * @param string $my_secret * @param string $their_public * @param string $client_public * @param string $server_public * @param bool $dontFallback * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_kx( #[\SensitiveParameter] $my_secret, $their_public, $client_public, $server_public, $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($my_secret, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($their_public, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($client_public, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($server_public, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI() && !$dontFallback) { if (is_callable('sodium_crypto_kx')) { return (string) sodium_crypto_kx( $my_secret, $their_public, $client_public, $server_public ); } } if (self::use_fallback('crypto_kx')) { return (string) call_user_func( '\\Sodium\\crypto_kx', $my_secret, $their_public, $client_public, $server_public ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::keyExchange( $my_secret, $their_public, $client_public, $server_public ); } return ParagonIE_Sodium_Crypto::keyExchange( $my_secret, $their_public, $client_public, $server_public ); } /** * @param string $seed * @return string * @throws SodiumException */ public static function crypto_kx_seed_keypair( #[\SensitiveParameter] $seed ) { ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); $seed = (string) $seed; if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) { throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes'); } $sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES); $pk = self::crypto_scalarmult_base($sk); return $sk . $pk; } /** * @return string * @throws Exception */ public static function crypto_kx_keypair() { $sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES); $pk = self::crypto_scalarmult_base($sk); return $sk . $pk; } /** * @param string $keypair * @param string $serverPublicKey * @return array{0: string, 1: string} * @throws SodiumException */ public static function crypto_kx_client_session_keys( #[\SensitiveParameter] $keypair, $serverPublicKey ) { ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey, 'string', 2); $keypair = (string) $keypair; $serverPublicKey = (string) $serverPublicKey; if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) { throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) { throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes'); } $sk = self::crypto_kx_secretkey($keypair); $pk = self::crypto_kx_publickey($keypair); $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2); self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey)); self::crypto_generichash_update($h, $pk); self::crypto_generichash_update($h, $serverPublicKey); $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2); return array( ParagonIE_Sodium_Core_Util::substr( $sessionKeys, 0, self::CRYPTO_KX_SESSIONKEYBYTES ), ParagonIE_Sodium_Core_Util::substr( $sessionKeys, self::CRYPTO_KX_SESSIONKEYBYTES, self::CRYPTO_KX_SESSIONKEYBYTES ) ); } /** * @param string $keypair * @param string $clientPublicKey * @return array{0: string, 1: string} * @throws SodiumException */ public static function crypto_kx_server_session_keys( #[\SensitiveParameter] $keypair, $clientPublicKey ) { ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey, 'string', 2); $keypair = (string) $keypair; $clientPublicKey = (string) $clientPublicKey; if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) { throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) { throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes'); } $sk = self::crypto_kx_secretkey($keypair); $pk = self::crypto_kx_publickey($keypair); $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2); self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey)); self::crypto_generichash_update($h, $clientPublicKey); self::crypto_generichash_update($h, $pk); $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2); return array( ParagonIE_Sodium_Core_Util::substr( $sessionKeys, self::CRYPTO_KX_SESSIONKEYBYTES, self::CRYPTO_KX_SESSIONKEYBYTES ), ParagonIE_Sodium_Core_Util::substr( $sessionKeys, 0, self::CRYPTO_KX_SESSIONKEYBYTES ) ); } /** * @param string $kp * @return string * @throws SodiumException */ public static function crypto_kx_secretkey( #[\SensitiveParameter] $kp ) { return ParagonIE_Sodium_Core_Util::substr( $kp, 0, self::CRYPTO_KX_SECRETKEYBYTES ); } /** * @param string $kp * @return string * @throws SodiumException */ public static function crypto_kx_publickey($kp) { return ParagonIE_Sodium_Core_Util::substr( $kp, self::CRYPTO_KX_SECRETKEYBYTES, self::CRYPTO_KX_PUBLICKEYBYTES ); } /** * @param int $outlen * @param string $passwd * @param string $salt * @param int $opslimit * @param int $memlimit * @param int|null $alg * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_pwhash( $outlen, #[\SensitiveParameter] $passwd, $salt, $opslimit, $memlimit, $alg = null ) { ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5); if (self::useNewSodiumAPI()) { if (!is_null($alg)) { ParagonIE_Sodium_Core_Util::declareScalarType($alg, 'int', 6); return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg); } return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit); } if (self::use_fallback('crypto_pwhash')) { return (string) call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' ); } /** * !Exclusive to sodium_compat! * * This returns TRUE if the native crypto_pwhash API is available by libsodium. * This returns FALSE if only sodium_compat is available. * * @return bool */ public static function crypto_pwhash_is_available() { if (self::useNewSodiumAPI()) { return true; } if (self::use_fallback('crypto_pwhash')) { return true; } return false; } /** * @param string $passwd * @param int $opslimit * @param int $memlimit * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_pwhash_str( #[\SensitiveParameter] $passwd, $opslimit, $memlimit ) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); if (self::useNewSodiumAPI()) { return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit); } if (self::use_fallback('crypto_pwhash_str')) { return (string) call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' ); } /** * Do we need to rehash this password? * * @param string $hash * @param int $opslimit * @param int $memlimit * @return bool * @throws SodiumException */ public static function crypto_pwhash_str_needs_rehash( #[\SensitiveParameter] $hash, $opslimit, $memlimit ) { ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); // Just grab the first 4 pieces. $pieces = explode('$', (string) $hash); $prefix = implode('$', array_slice($pieces, 0, 4)); // Rebuild the expected header. /** @var int $ops */ $ops = (int) $opslimit; /** @var int $mem */ $mem = (int) $memlimit >> 10; $encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1'; // Do they match? If so, we don't need to rehash, so return false. return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix); } /** * @param string $passwd * @param string $hash * @return bool * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_pwhash_str_verify( #[\SensitiveParameter] $passwd, #[\SensitiveParameter] $hash ) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2); if (self::useNewSodiumAPI()) { return (bool) sodium_crypto_pwhash_str_verify($passwd, $hash); } if (self::use_fallback('crypto_pwhash_str_verify')) { return (bool) call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' ); } /** * @param int $outlen * @param string $passwd * @param string $salt * @param int $opslimit * @param int $memlimit * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_pwhash_scryptsalsa208sha256( $outlen, #[\SensitiveParameter] $passwd, $salt, $opslimit, $memlimit ) { ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5); if (self::useNewSodiumAPI()) { return (string) sodium_crypto_pwhash_scryptsalsa208sha256( (int) $outlen, (string) $passwd, (string) $salt, (int) $opslimit, (int) $memlimit ); } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { return (string) call_user_func( '\\Sodium\\crypto_pwhash_scryptsalsa208sha256', (int) $outlen, (string) $passwd, (string) $salt, (int) $opslimit, (int) $memlimit ); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' ); } /** * !Exclusive to sodium_compat! * * This returns TRUE if the native crypto_pwhash API is available by libsodium. * This returns FALSE if only sodium_compat is available. * * @return bool */ public static function crypto_pwhash_scryptsalsa208sha256_is_available() { if (self::useNewSodiumAPI()) { return true; } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) { return true; } return false; } /** * @param string $passwd * @param int $opslimit * @param int $memlimit * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_pwhash_scryptsalsa208sha256_str( #[\SensitiveParameter] $passwd, $opslimit, $memlimit ) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2); ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3); if (self::useNewSodiumAPI()) { return (string) sodium_crypto_pwhash_scryptsalsa208sha256_str( (string) $passwd, (int) $opslimit, (int) $memlimit ); } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) { return (string) call_user_func( '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str', (string) $passwd, (int) $opslimit, (int) $memlimit ); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' ); } /** * @param string $passwd * @param string $hash * @return bool * @throws SodiumException * @throws TypeError */ public static function crypto_pwhash_scryptsalsa208sha256_str_verify( #[\SensitiveParameter] $passwd, #[\SensitiveParameter] $hash ) { ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2); if (self::useNewSodiumAPI()) { return (bool) sodium_crypto_pwhash_scryptsalsa208sha256_str_verify( (string) $passwd, (string) $hash ); } if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) { return (bool) call_user_func( '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify', (string) $passwd, (string) $hash ); } // This is the best we can do. throw new SodiumException( 'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP' ); } /** * Calculate the shared secret between your secret key and your * recipient's public key. * * Algorithm: X25519 (ECDH over Curve25519) * * @param string $secretKey * @param string $publicKey * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_scalarmult( #[\SensitiveParameter] $secretKey, $publicKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_scalarmult($secretKey, $publicKey); } if (self::use_fallback('crypto_scalarmult')) { return (string) call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey); } /* Output validation: Forbid all-zero keys */ if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { throw new SodiumException('Zero secret key is not allowed'); } if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) { throw new SodiumException('Zero public key is not allowed'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey); } return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey); } /** * Calculate an X25519 public key from an X25519 secret key. * * @param string $secretKey * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress TooFewArguments * @psalm-suppress MixedArgument */ public static function crypto_scalarmult_base( #[\SensitiveParameter] $secretKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_scalarmult_base($secretKey); } if (self::use_fallback('crypto_scalarmult_base')) { return (string) call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey); } if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { throw new SodiumException('Zero secret key is not allowed'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey); } return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey); } /** * Authenticated symmetric-key encryption. * * Algorithm: XSalsa20-Poly1305 * * @param string $plaintext The message you're encrypting * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Ciphertext with Poly1305 MAC * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_secretbox( #[\SensitiveParameter] $plaintext, $nonce, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_secretbox($plaintext, $nonce, $key); } if (self::use_fallback('crypto_secretbox')) { return (string) call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key); } /** * Decrypts a message previously encrypted with crypto_secretbox(). * * @param string $ciphertext Ciphertext with Poly1305 MAC * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_secretbox_open( $ciphertext, $nonce, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_secretbox_open($ciphertext, $nonce, $key); } if (self::use_fallback('crypto_secretbox_open')) { return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key); } /** * Return a secure random key for use with crypto_secretbox * * @return string * @throws Exception * @throws Error */ public static function crypto_secretbox_keygen() { return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES); } /** * Authenticated symmetric-key encryption. * * Algorithm: XChaCha20-Poly1305 * * @param string $plaintext The message you're encrypting * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Ciphertext with Poly1305 MAC * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key); } /** * Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305(). * * @param string $ciphertext Ciphertext with Poly1305 MAC * @param string $nonce A Number to be used Once; must be 24 bytes * @param string $key Symmetric encryption key * @return string Original plaintext message * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_secretbox_xchacha20poly1305_open( $ciphertext, $nonce, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); } return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); } /** * @param string $key * @return array<int, string> Returns a state and a header. * @throws Exception * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_init_push( #[\SensitiveParameter] $key ) { if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key); } /** * @param string $header * @param string $key * @return string Returns a state. * @throws Exception */ public static function crypto_secretstream_xchacha20poly1305_init_pull( $header, #[\SensitiveParameter] $key ) { if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) { throw new SodiumException( 'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes' ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header); } /** * @param string $state * @param string $msg * @param string $aad * @param int $tag * @return string * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_push( #[\SensitiveParameter] &$state, #[\SensitiveParameter] $msg, $aad = '', $tag = 0 ) { if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push( $state, $msg, $aad, $tag ); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push( $state, $msg, $aad, $tag ); } /** * @param string $state * @param string $msg * @param string $aad * @return bool|array{0: string, 1: int} * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_pull( #[\SensitiveParameter] &$state, $msg, $aad = '' ) { if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull( $state, $msg, $aad ); } return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull( $state, $msg, $aad ); } /** * @return string * @throws Exception */ public static function crypto_secretstream_xchacha20poly1305_keygen() { return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES); } /** * @param string $state * @return void * @throws SodiumException */ public static function crypto_secretstream_xchacha20poly1305_rekey( #[\SensitiveParameter] &$state ) { if (PHP_INT_SIZE === 4) { ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state); } else { ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state); } } /** * Calculates a SipHash-2-4 hash of a message for a given key. * * @param string $message Input message * @param string $key SipHash-2-4 key * @return string Hash * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_shorthash( $message, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_shorthash($message, $key); } if (self::use_fallback('crypto_shorthash')) { return (string) call_user_func('\\Sodium\\crypto_shorthash', $message, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_SipHash::sipHash24($message, $key); } return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key); } /** * Return a secure random key for use with crypto_shorthash * * @return string * @throws Exception * @throws Error */ public static function crypto_shorthash_keygen() { return random_bytes(self::CRYPTO_SHORTHASH_KEYBYTES); } /** * Returns a signed message. You probably want crypto_sign_detached() * instead, which only returns the signature. * * Algorithm: Ed25519 (EdDSA over Curve25519) * * @param string $message Message to be signed. * @param string $secretKey Secret signing key. * @return string Signed message (signature is prefixed). * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_sign( $message, #[\SensitiveParameter] $secretKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign($message, $secretKey); } if (self::use_fallback('crypto_sign')) { return (string) call_user_func('\\Sodium\\crypto_sign', $message, $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign($message, $secretKey); } return ParagonIE_Sodium_Crypto::sign($message, $secretKey); } /** * Validates a signed message then returns the message. * * @param string $signedMessage A signed message * @param string $publicKey A public key * @return string The original message (if the signature is * valid for this public key) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument * @psalm-suppress MixedInferredReturnType * @psalm-suppress MixedReturnStatement */ public static function crypto_sign_open( $signedMessage, $publicKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_BYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { /** * @psalm-suppress InvalidReturnStatement * @psalm-suppress FalsableReturnStatement */ return sodium_crypto_sign_open($signedMessage, $publicKey); } if (self::use_fallback('crypto_sign_open')) { return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign_open($signedMessage, $publicKey); } return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey); } /** * Generate a new random Ed25519 keypair. * * @return string * @throws SodiumException * @throws TypeError */ public static function crypto_sign_keypair() { if (self::useNewSodiumAPI()) { return sodium_crypto_sign_keypair(); } if (self::use_fallback('crypto_sign_keypair')) { return (string) call_user_func('\\Sodium\\crypto_sign_keypair'); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::keypair(); } return ParagonIE_Sodium_Core_Ed25519::keypair(); } /** * @param string $sk * @param string $pk * @return string * @throws SodiumException */ public static function crypto_sign_keypair_from_secretkey_and_publickey( #[\SensitiveParameter] $sk, $pk ) { ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1); $sk = (string) $sk; $pk = (string) $pk; if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes'); } if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk); } return $sk . $pk; } /** * Generate an Ed25519 keypair from a seed. * * @param string $seed Input seed * @return string Keypair * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_seed_keypair( #[\SensitiveParameter] $seed ) { ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1); if (self::useNewSodiumAPI()) { return sodium_crypto_sign_seed_keypair($seed); } if (self::use_fallback('crypto_sign_keypair')) { return (string) call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed); } $publicKey = ''; $secretKey = ''; if (PHP_INT_SIZE === 4) { ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey, $secretKey, $seed); } else { ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed); } return $secretKey . $publicKey; } /** * Extract an Ed25519 public key from an Ed25519 keypair. * * @param string $keypair Keypair * @return string Public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_publickey( #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_publickey($keypair); } if (self::use_fallback('crypto_sign_publickey')) { return (string) call_user_func('\\Sodium\\crypto_sign_publickey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair); } return ParagonIE_Sodium_Core_Ed25519::publickey($keypair); } /** * Calculate an Ed25519 public key from an Ed25519 secret key. * * @param string $secretKey Your Ed25519 secret key * @return string The corresponding Ed25519 public key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_publickey_from_secretkey( #[\SensitiveParameter] $secretKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_publickey_from_secretkey($secretKey); } if (self::use_fallback('crypto_sign_publickey_from_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey); } return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey); } /** * Extract an Ed25519 secret key from an Ed25519 keypair. * * @param string $keypair Keypair * @return string Secret key * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_secretkey( #[\SensitiveParameter] $keypair ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_secretkey($keypair); } if (self::use_fallback('crypto_sign_secretkey')) { return (string) call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair); } return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair); } /** * Calculate the Ed25519 signature of a message and return ONLY the signature. * * Algorithm: Ed25519 (EdDSA over Curve25519) * * @param string $message Message to be signed * @param string $secretKey Secret signing key * @return string Digital signature * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_detached( $message, #[\SensitiveParameter] $secretKey ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_detached($message, $secretKey); } if (self::use_fallback('crypto_sign_detached')) { return (string) call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign_detached($message, $secretKey); } return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey); } /** * Verify the Ed25519 signature of a message. * * @param string $signature Digital sginature * @param string $message Message to be verified * @param string $publicKey Public key * @return bool TRUE if this signature is good for this public key; * FALSE otherwise * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_verify_detached($signature, $message, $publicKey) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($signature, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) { throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_sign_verify_detached($signature, $message, $publicKey); } if (self::use_fallback('crypto_sign_verify_detached')) { return (bool) call_user_func( '\\Sodium\\crypto_sign_verify_detached', $signature, $message, $publicKey ); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message, $publicKey); } return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey); } /** * Convert an Ed25519 public key to a Curve25519 public key * * @param string $pk * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_ed25519_pk_to_curve25519($pk) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($pk) < self::CRYPTO_SIGN_PUBLICKEYBYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_PUBLICKEYBYTES long.'); } if (self::useNewSodiumAPI()) { if (is_callable('crypto_sign_ed25519_pk_to_curve25519')) { return (string) sodium_crypto_sign_ed25519_pk_to_curve25519($pk); } } if (self::use_fallback('crypto_sign_ed25519_pk_to_curve25519')) { return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519', $pk); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_Ed25519::pk_to_curve25519($pk); } return ParagonIE_Sodium_Core_Ed25519::pk_to_curve25519($pk); } /** * Convert an Ed25519 secret key to a Curve25519 secret key * * @param string $sk * @return string * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_sign_ed25519_sk_to_curve25519( #[\SensitiveParameter] $sk ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) { throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.'); } if (self::useNewSodiumAPI()) { if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) { return sodium_crypto_sign_ed25519_sk_to_curve25519($sk); } } if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) { return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk); } $h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true); $h[0] = ParagonIE_Sodium_Core_Util::intToChr( ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248 ); $h[31] = ParagonIE_Sodium_Core_Util::intToChr( (ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64 ); return ParagonIE_Sodium_Core_Util::substr($h, 0, 32); } /** * Expand a key and nonce into a keystream of pseudorandom bytes. * * @param int $len Number of bytes desired * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key XSalsa20 key * @return string Pseudorandom stream that can be XORed with messages * to provide encryption (but not authentication; see * Poly1305 or crypto_auth() for that, which is not * optional for security) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream( $len, $nonce, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_stream($len, $nonce, $key); } if (self::use_fallback('crypto_stream')) { return (string) call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce, $key); } return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key); } /** * DANGER! UNAUTHENTICATED ENCRYPTION! * * Unless you are following expert advice, do not use this feature. * * Algorithm: XSalsa20 * * This DOES NOT provide ciphertext integrity. * * @param string $message Plaintext message * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key Encryption key * @return string Encrypted text which is vulnerable to chosen- * ciphertext attacks unless you implement some * other mitigation to the ciphertext (i.e. * Encrypt then MAC) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xor( #[\SensitiveParameter] $message, $nonce, #[\SensitiveParameter] $key ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); } if (self::useNewSodiumAPI()) { return sodium_crypto_stream_xor($message, $nonce, $key); } if (self::use_fallback('crypto_stream_xor')) { return (string) call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message, $nonce, $key); } return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key); } /** * Return a secure random key for use with crypto_stream * * @return string * @throws Exception * @throws Error */ public static function crypto_stream_keygen() { return random_bytes(self::CRYPTO_STREAM_KEYBYTES); } /** * Expand a key and nonce into a keystream of pseudorandom bytes. * * @param int $len Number of bytes desired * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key XChaCha20 key * @param bool $dontFallback * @return string Pseudorandom stream that can be XORed with messages * to provide encryption (but not authentication; see * Poly1305 or crypto_auth() for that, which is not * optional for security) * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xchacha20( $len, $nonce, #[\SensitiveParameter] $key, $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_STREAM_XCHACHA20_KEYBYTES long.'); } if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_stream_xchacha20($len, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XChaCha20::stream($len, $nonce, $key); } return ParagonIE_Sodium_Core_XChaCha20::stream($len, $nonce, $key); } /** * DANGER! UNAUTHENTICATED ENCRYPTION! * * Unless you are following expert advice, do not use this feature. * * Algorithm: XChaCha20 * * This DOES NOT provide ciphertext integrity. * * @param string $message Plaintext message * @param string $nonce Number to be used Once; must be 24 bytes * @param string $key Encryption key * @return string Encrypted text which is vulnerable to chosen- * ciphertext attacks unless you implement some * other mitigation to the ciphertext (i.e. * Encrypt then MAC) * @param bool $dontFallback * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xchacha20_xor( #[\SensitiveParameter] $message, $nonce, #[\SensitiveParameter] $key, $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.'); } if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_stream_xchacha20_xor($message, $nonce, $key); } if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XChaCha20::streamXorIc($message, $nonce, $key); } return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key); } /** * DANGER! UNAUTHENTICATED ENCRYPTION! * * Unless you are following expert advice, do not use this feature. * * Algorithm: XChaCha20 * * This DOES NOT provide ciphertext integrity. * * @param string $message Plaintext message * @param string $nonce Number to be used Once; must be 24 bytes * @param int $counter * @param string $key Encryption key * @return string Encrypted text which is vulnerable to chosen- * ciphertext attacks unless you implement some * other mitigation to the ciphertext (i.e. * Encrypt then MAC) * @param bool $dontFallback * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function crypto_stream_xchacha20_xor_ic( #[\SensitiveParameter] $message, $nonce, $counter, #[\SensitiveParameter] $key, $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2); ParagonIE_Sodium_Core_Util::declareScalarType($counter, 'int', 3); ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4); /* Input validation: */ if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) { throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.'); } if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) { throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.'); } if (is_callable('sodium_crypto_stream_xchacha20_xor_ic') && !$dontFallback) { return sodium_crypto_stream_xchacha20_xor_ic($message, $nonce, $counter, $key); } $ic = ParagonIE_Sodium_Core_Util::store64_le($counter); if (PHP_INT_SIZE === 4) { return ParagonIE_Sodium_Core32_XChaCha20::streamXorIc($message, $nonce, $key, $ic); } return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key, $ic); } /** * Return a secure random key for use with crypto_stream_xchacha20 * * @return string * @throws Exception * @throws Error */ public static function crypto_stream_xchacha20_keygen() { return random_bytes(self::CRYPTO_STREAM_XCHACHA20_KEYBYTES); } /** * Cache-timing-safe implementation of hex2bin(). * * @param string $string Hexadecimal string * @param string $ignore List of characters to ignore; useful for whitespace * @return string Raw binary string * @throws SodiumException * @throws TypeError * @psalm-suppress TooFewArguments * @psalm-suppress MixedArgument */ public static function hex2bin( #[\SensitiveParameter] $string, $ignore = '' ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($ignore, 'string', 2); if (self::useNewSodiumAPI()) { if (is_callable('sodium_hex2bin')) { return (string) sodium_hex2bin($string, $ignore); } } if (self::use_fallback('hex2bin')) { return (string) call_user_func('\\Sodium\\hex2bin', $string, $ignore); } return ParagonIE_Sodium_Core_Util::hex2bin($string, $ignore); } /** * Increase a string (little endian) * * @param string $var * * @return void * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function increment( #[\SensitiveParameter] &$var ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1); if (self::useNewSodiumAPI()) { sodium_increment($var); return; } if (self::use_fallback('increment')) { $func = '\\Sodium\\increment'; $func($var); return; } $len = ParagonIE_Sodium_Core_Util::strlen($var); $c = 1; $copy = ''; for ($i = 0; $i < $len; ++$i) { $c += ParagonIE_Sodium_Core_Util::chrToInt( ParagonIE_Sodium_Core_Util::substr($var, $i, 1) ); $copy .= ParagonIE_Sodium_Core_Util::intToChr($c); $c >>= 8; } $var = $copy; } /** * @param string $str * @return bool * * @throws SodiumException */ public static function is_zero( #[\SensitiveParameter] $str ) { $d = 0; for ($i = 0; $i < 32; ++$i) { $d |= ParagonIE_Sodium_Core_Util::chrToInt($str[$i]); } return ((($d - 1) >> 31) & 1) === 1; } /** * The equivalent to the libsodium minor version we aim to be compatible * with (sans pwhash and memzero). * * @return int */ public static function library_version_major() { if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MAJOR_VERSION')) { return SODIUM_LIBRARY_MAJOR_VERSION; } if (self::use_fallback('library_version_major')) { /** @psalm-suppress UndefinedFunction */ return (int) call_user_func('\\Sodium\\library_version_major'); } return self::LIBRARY_VERSION_MAJOR; } /** * The equivalent to the libsodium minor version we aim to be compatible * with (sans pwhash and memzero). * * @return int */ public static function library_version_minor() { if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MINOR_VERSION')) { return SODIUM_LIBRARY_MINOR_VERSION; } if (self::use_fallback('library_version_minor')) { /** @psalm-suppress UndefinedFunction */ return (int) call_user_func('\\Sodium\\library_version_minor'); } return self::LIBRARY_VERSION_MINOR; } /** * Compare two strings. * * @param string $left * @param string $right * @return int * @throws SodiumException * @throws TypeError * @psalm-suppress MixedArgument */ public static function memcmp( #[\SensitiveParameter] $left, #[\SensitiveParameter] $right ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); if (self::useNewSodiumAPI()) { return sodium_memcmp($left, $right); } if (self::use_fallback('memcmp')) { return (int) call_user_func('\\Sodium\\memcmp', $left, $right); } /** @var string $left */ /** @var string $right */ return ParagonIE_Sodium_Core_Util::memcmp($left, $right); } /** * It's actually not possible to zero memory buffers in PHP. You need the * native library for that. * * @param string|null $var * @param-out string|null $var * * @return void * @throws SodiumException (Unless libsodium is installed) * @throws TypeError * @psalm-suppress TooFewArguments */ public static function memzero( #[\SensitiveParameter] &$var ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1); if (self::useNewSodiumAPI()) { /** @psalm-suppress MixedArgument */ sodium_memzero($var); return; } if (self::use_fallback('memzero')) { $func = '\\Sodium\\memzero'; $func($var); if ($var === null) { return; } } // This is the best we can do. throw new SodiumException( 'This is not implemented in sodium_compat, as it is not possible to securely wipe memory from PHP. ' . 'To fix this error, make sure libsodium is installed and the PHP extension is enabled.' ); } /** * @param string $unpadded * @param int $blockSize * @param bool $dontFallback * @return string * @throws SodiumException */ public static function pad( #[\SensitiveParameter] $unpadded, $blockSize, $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($unpadded, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2); $unpadded = (string) $unpadded; $blockSize = (int) $blockSize; if (self::useNewSodiumAPI() && !$dontFallback) { return (string) sodium_pad($unpadded, $blockSize); } if ($blockSize <= 0) { throw new SodiumException( 'block size cannot be less than 1' ); } $unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded); $xpadlen = ($blockSize - 1); if (($blockSize & ($blockSize - 1)) === 0) { $xpadlen -= $unpadded_len & ($blockSize - 1); } else { $xpadlen -= $unpadded_len % $blockSize; } $xpadded_len = $unpadded_len + $xpadlen; $padded = str_repeat("\0", $xpadded_len - 1); if ($unpadded_len > 0) { $st = 1; $i = 0; $k = $unpadded_len; for ($j = 0; $j <= $xpadded_len; ++$j) { $i = (int) $i; $k = (int) $k; $st = (int) $st; if ($j >= $unpadded_len) { $padded[$j] = "\0"; } else { $padded[$j] = $unpadded[$j]; } /** @var int $k */ $k -= $st; $st = (int) (~( ( ( ($k >> 48) | ($k >> 32) | ($k >> 16) | $k ) - 1 ) >> 16 ) ) & 1; $i += $st; } } $mask = 0; $tail = $xpadded_len; for ($i = 0; $i < $blockSize; ++$i) { # barrier_mask = (unsigned char) # (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT)); $barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1); # tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask); $padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr( (ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask) | (0x80 & $barrier_mask) ); # mask |= barrier_mask; $mask |= $barrier_mask; } return $padded; } /** * @param string $padded * @param int $blockSize * @param bool $dontFallback * @return string * @throws SodiumException */ public static function unpad( #[\SensitiveParameter] $padded, $blockSize, $dontFallback = false ) { /* Type checks: */ ParagonIE_Sodium_Core_Util::declareScalarType($padded, 'string', 1); ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2); $padded = (string) $padded; $blockSize = (int) $blockSize; if (self::useNewSodiumAPI() && !$dontFallback) { return (string) sodium_unpad($padded, $blockSize); } if ($blockSize <= 0) { throw new SodiumException('block size cannot be less than 1'); } $padded_len = ParagonIE_Sodium_Core_Util::strlen($padded); if ($padded_len < $blockSize) { throw new SodiumException('invalid padding'); } # tail = &padded[padded_len - 1U]; $tail = $padded_len - 1; $acc = 0; $valid = 0; $pad_len = 0; $found = 0; for ($i = 0; $i < $blockSize; ++$i) { # c = tail[-i]; $c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]); # is_barrier = # (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U; $is_barrier = ( ( ($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1) ) >> 7 ) & 1; $is_barrier &= ~$found; $found |= $is_barrier; # acc |= c; $acc |= $c; # pad_len |= i & (1U + ~is_barrier); $pad_len |= $i & (1 + ~$is_barrier); # valid |= (unsigned char) is_barrier; $valid |= ($is_barrier & 0xff); } # unpadded_len = padded_len - 1U - pad_len; $unpadded_len = $padded_len - 1 - $pad_len; if ($valid !== 1) { throw new SodiumException('invalid padding'); } return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len); } /** * Will sodium_compat run fast on the current hardware and PHP configuration? * * @return bool */ public static function polyfill_is_fast() { if (extension_loaded('sodium')) { return true; } if (extension_loaded('libsodium')) { return true; } return PHP_INT_SIZE === 8; } /** * Generate a string of bytes from the kernel's CSPRNG. * Proudly uses /dev/urandom (if getrandom(2) is not available). * * @param int $numBytes * @return string * @throws Exception * @throws TypeError */ public static function randombytes_buf($numBytes) { /* Type checks: */ if (!is_int($numBytes)) { if (is_numeric($numBytes)) { $numBytes = (int) $numBytes; } else { throw new TypeError( 'Argument 1 must be an integer, ' . gettype($numBytes) . ' given.' ); } } /** @var positive-int $numBytes */ if (self::use_fallback('randombytes_buf')) { return (string) call_user_func('\\Sodium\\randombytes_buf', $numBytes); } if ($numBytes < 0) { throw new SodiumException("Number of bytes must be a positive integer"); } return random_bytes($numBytes); } /** * Generate an integer between 0 and $range (non-inclusive). * * @param int $range * @return int * @throws Exception * @throws Error * @throws TypeError */ public static function randombytes_uniform($range) { /* Type checks: */ if (!is_int($range)) { if (is_numeric($range)) { $range = (int) $range; } else { throw new TypeError( 'Argument 1 must be an integer, ' . gettype($range) . ' given.' ); } } if (self::use_fallback('randombytes_uniform')) { return (int) call_user_func('\\Sodium\\randombytes_uniform', $range); } return random_int(0, $range - 1); } /** * Generate a random 16-bit integer. * * @return int * @throws Exception * @throws Error * @throws TypeError */ public static function randombytes_random16() { if (self::use_fallback('randombytes_random16')) { return (int) call_user_func('\\Sodium\\randombytes_random16'); } return random_int(0, 65535); } /** * @param string $p * @param bool $dontFallback * @return bool * @throws SodiumException */ public static function ristretto255_is_valid_point( #[\SensitiveParameter] $p, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_is_valid_point($p); } try { $r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p); return $r['res'] === 0 && ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1; } catch (SodiumException $ex) { if ($ex->getMessage() === 'S is not canonical') { return false; } throw $ex; } } /** * @param string $p * @param string $q * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_add( #[\SensitiveParameter] $p, #[\SensitiveParameter] $q, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_add($p, $q); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q); } /** * @param string $p * @param string $q * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_sub( #[\SensitiveParameter] $p, #[\SensitiveParameter] $q, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_sub($p, $q); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q); } /** * @param string $r * @param bool $dontFallback * @return string * * @throws SodiumException */ public static function ristretto255_from_hash( #[\SensitiveParameter] $r, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_from_hash($r); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r); } /** * @param bool $dontFallback * @return string * * @throws SodiumException */ public static function ristretto255_random($dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_random(); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random(); } /** * @param bool $dontFallback * @return string * * @throws SodiumException */ public static function ristretto255_scalar_random($dontFallback = false) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_random(); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random(); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_invert( #[\SensitiveParameter] $s, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_invert($s); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_negate( #[\SensitiveParameter] $s, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_negate($s); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_complement( #[\SensitiveParameter] $s, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_complement($s); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s); } /** * @param string $x * @param string $y * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_add( #[\SensitiveParameter] $x, #[\SensitiveParameter] $y, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_add($x, $y); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y); } /** * @param string $x * @param string $y * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_sub( #[\SensitiveParameter] $x, #[\SensitiveParameter] $y, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_sub($x, $y); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y); } /** * @param string $x * @param string $y * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_mul( #[\SensitiveParameter] $x, #[\SensitiveParameter] $y, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_mul($x, $y); } return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y); } /** * @param string $n * @param string $p * @param bool $dontFallback * @return string * @throws SodiumException */ public static function scalarmult_ristretto255( #[\SensitiveParameter] $n, #[\SensitiveParameter] $p, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_scalarmult_ristretto255($n, $p); } return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p); } /** * @param string $n * @param string $p * @param bool $dontFallback * @return string * @throws SodiumException */ public static function scalarmult_ristretto255_base( #[\SensitiveParameter] $n, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_scalarmult_ristretto255_base($n); } return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n); } /** * @param string $s * @param bool $dontFallback * @return string * @throws SodiumException */ public static function ristretto255_scalar_reduce( #[\SensitiveParameter] $s, $dontFallback = false ) { if (self::useNewSodiumAPI() && !$dontFallback) { return sodium_crypto_core_ristretto255_scalar_reduce($s); } return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s); } /** * Runtime testing method for 32-bit platforms. * * Usage: If runtime_speed_test() returns FALSE, then our 32-bit * implementation is to slow to use safely without risking timeouts. * If this happens, install sodium from PECL to get acceptable * performance. * * @param int $iterations Number of multiplications to attempt * @param int $maxTimeout Milliseconds * @return bool TRUE if we're fast enough, FALSE is not * @throws SodiumException */ public static function runtime_speed_test($iterations, $maxTimeout) { if (self::polyfill_is_fast()) { return true; } /** @var float $end */ $end = 0.0; /** @var float $start */ $start = microtime(true); /** @var ParagonIE_Sodium_Core32_Int64 $a */ $a = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16)); for ($i = 0; $i < $iterations; ++$i) { /** @var ParagonIE_Sodium_Core32_Int64 $b */ $b = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16)); $a->mulInt64($b); } /** @var float $end */ $end = microtime(true); /** @var int $diff */ $diff = (int) ceil(($end - $start) * 1000); return $diff < $maxTimeout; } /** * Add two numbers (little-endian unsigned), storing the value in the first * parameter. * * This mutates $val. * * @param string $val * @param string $addv * @return void * @throws SodiumException */ public static function sub( #[\SensitiveParameter] &$val, #[\SensitiveParameter] $addv ) { $val_len = ParagonIE_Sodium_Core_Util::strlen($val); $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv); if ($val_len !== $addv_len) { throw new SodiumException('values must have the same length'); } $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val); $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv); $c = 0; for ($i = 0; $i < $val_len; $i++) { $c = ($A[$i] - $B[$i] - $c); $A[$i] = ($c & 0xff); $c = ($c >> 8) & 1; } $val = ParagonIE_Sodium_Core_Util::intArrayToString($A); } /** * This emulates libsodium's version_string() function, except ours is * prefixed with 'polyfill-'. * * @return string * @psalm-suppress MixedInferredReturnType * @psalm-suppress UndefinedFunction */ public static function version_string() { if (self::useNewSodiumAPI()) { return (string) sodium_version_string(); } if (self::use_fallback('version_string')) { return (string) call_user_func('\\Sodium\\version_string'); } return (string) self::VERSION_STRING; } /** * Should we use the libsodium core function instead? * This is always a good idea, if it's available. (Unless we're in the * middle of running our unit test suite.) * * If ext/libsodium is available, use it. Return TRUE. * Otherwise, we have to use the code provided herein. Return FALSE. * * @param string $sodium_func_name * * @return bool */ protected static function use_fallback($sodium_func_name = '') { static $res = null; if ($res === null) { $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300; } if ($res === false) { // No libsodium installed return false; } if (self::$disableFallbackForUnitTests) { // Don't fallback. Use the PHP implementation. return false; } if (!empty($sodium_func_name)) { return is_callable('\\Sodium\\' . $sodium_func_name); } return true; } /** * Libsodium as implemented in PHP 7.2 * and/or ext/sodium (via PECL) * * @ref https://wiki.php.net/rfc/libsodium * @return bool */ protected static function useNewSodiumAPI() { static $res = null; if ($res === null) { $res = PHP_VERSION_ID >= 70000 && extension_loaded('sodium'); } if (self::$disableFallbackForUnitTests) { // Don't fallback. Use the PHP implementation. return false; } return (bool) $res; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMapper/Manager.php������������������������������������������������������������������������������0000644�����������������00000010745�15021223045�0010646 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; class Manager { public static function register_hooks() { $self = new Manager(); add_filter( 'posts_request', [ $self, 'set_custom_wp_query' ], 50, 2 ); add_filter( 'posts_fields', [ $self, 'set_custom_wp_query_fields' ], 50, 2 ); add_filter( 'posts_where', [ $self, 'set_custom_wp_query_where' ], 50, 2 ); add_filter( 'posts_groupby', [ $self, 'set_custom_wp_query_groupby' ], 50, 2 ); } /** * Sets a custom SQL query for the WP_Query class, when the Custom Post DataMapper implementation is used * * @param string $sql * @param \WP_Query $wp_query * @return string */ public function set_custom_wp_query( $sql, $wp_query ) { if ( $wp_query->get( 'datamapper' ) ) { // Set the custom query. if ( ( $custom_sql = $wp_query->get( 'custom_sql' ) ) ) { $sql = $custom_sql; } // Perhaps we're to initiate a delete query instead? elseif ( $wp_query->get( 'is_delete' ) ) { $sql = preg_replace( '/^SELECT.*FROM/i', 'DELETE FROM', $sql ); } if ( $wp_query->get( 'debug' ) ) { var_dump( $sql ); } } return $sql; } /** * Sets custom fields to select from the database * * @param string $fields * @param \WP_Query $wp_query * @return string */ public function set_custom_wp_query_fields( $fields, $wp_query ) { if ( $wp_query->get( 'datamapper' ) ) { if ( ( $custom_fields = $wp_query->get( 'fields' ) ) && $custom_fields != 'ids' ) { $fields = $custom_fields; } } return $fields; } /** * Sets custom where clauses for a query * * @param string $where * @param WP_Query $wp_query * @return string */ public function set_custom_wp_query_where( $where, $wp_query ) { if ( $wp_query->get( 'datamapper' ) ) { $this->add_post_title_where_clauses( $where, $wp_query ); $this->add_post_name_where_clauses( $where, $wp_query ); } return $where; } /** * Adds additional group by clauses to the SQL query * * @param string $group_by * @param \WP_Query $wp_query * @return string */ public function set_custom_wp_query_groupby( $group_by, $wp_query ) { $retval = $group_by; $group_by_columns = $wp_query->get( 'group_by_columns' ); if ( $group_by_columns ) { $retval = str_replace( 'GROUP BY', '', $retval ); $columns = explode( ',', $retval ); foreach ( array_reverse( $columns ) as $column ) { array_unshift( $group_by_columns, trim( $column ) ); } $retval = 'GROUP BY ' . implode( ', ', $group_by_columns ); } elseif ( $wp_query->get( 'datamapper' ) ) { // Not all mysql servers allow access to create temporary tables which are used when doing GROUP BY // statements; this can potentially ruin basic queries. If no group_by_columns is set AND the query originates // within the datamapper we strip the "GROUP BY" clause entirely in this filter. $retval = ''; } return $retval; } /** * Formats the value of used in a WHERE IN SQL clause for use in the WP_Query where clause * * @param string|array $values * @return string */ public function format_where_in_value( $values ) { if ( is_string( $values ) && strpos( $values, ',' ) !== false ) { $values = explode( ', ', $values ); } elseif ( ! is_array( $values ) ) { $values = [ $values ]; } // Quote the titles. foreach ( $values as $index => $value ) { $values[ $index ] = "'{$value}'"; } return implode( ', ', $values ); } /** * Adds post_title to the where clause * * @param string $where * @param WP_Query $wp_query * @return string */ public function add_post_title_where_clauses( &$where, &$wp_query ) { global $wpdb; // Handle post_title query var. if ( ( $titles = $wp_query->get( 'post_title' ) ) ) { $titles = $this->format_where_in_value( $titles ); $where .= " AND {$wpdb->posts}.post_title IN ({$titles})"; } elseif ( ( $value = $wp_query->get( 'post_title__like' ) ) ) { // Handle post_title_like query var. $where .= " AND {$wpdb->posts}.post_title LIKE '{$value}'"; } return $where; } /** * Adds post_name to the where clause * * @param string $where * @param \WP_Query $wp_query */ public function add_post_name_where_clauses( &$where, &$wp_query ) { global $wpdb; if ( ( $name = $wp_query->get( 'page_name__like' ) ) ) { $where .= " AND {$wpdb->posts}.post_name LIKE '{$name}'"; } elseif ( ( $names = $wp_query->get( 'page_name__in' ) ) ) { $names = $this->format_where_in_value( $names ); $where .= " AND {$wpdb->posts}.post_name IN ({$names})"; } } } ���������������������������DataMapper/WPModel.php������������������������������������������������������������������������������0000644�����������������00000001362�15021223045�0010576 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; abstract class WPModel extends Model { public $ID; public $comment_count; public $comment_status; public $extras_post_id; public $filter; public $guid; public $id_field; public $menu_order; public $ping_status; public $pinged; public $post_author; public $post_content; public $post_content_filtered; public $post_date; public $post_date_gmt; public $post_excerpt; public $post_id; public $post_mime_type; public $post_modified; public $post_modified_gmt; public $post_name; public $post_parent; public $post_password; public $post_status; public $post_title; public $post_type; public $pricelist_id; public $to_ping; public function get_primary_key_column() { return 'ID'; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMapper/WPPostDriver.php�������������������������������������������������������������������������0000644�����������������00000037347�15021223045�0011653 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; use Imagely\NGG\Util\Serializable; class WPPostDriver extends DriverBase { public $cache; public $primary_key_column = 'ID'; public $query_args = []; public $use_cache = true; public static $post_table_columns = []; public $ID; public $post_parent; /** * @throws \Exception */ public function __construct( $object_name = '' ) { if ( strlen( $object_name ) > 20 ) { throw new \Exception( 'The custom post name can be no longer than 20 characters long' ); } parent::__construct( $object_name ); } public function lookup_columns() { if ( empty( self::$post_table_columns ) ) { $columns = parent::lookup_columns(); foreach ( $columns as $column ) { self::$post_table_columns[] = $column; } } else { foreach ( self::$post_table_columns as $column ) { $this->_table_columns[] = $column; } } } /** * Gets the name of the table * * @global string $table_prefix * @return string */ public function get_table_name() { global $table_prefix; return $table_prefix . 'posts'; } /** * Returns a list of querable table columns for posts * * @return array */ public function _get_querable_table_columns() { return [ 'name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count' ]; } /** * Specifies an order clause * * @param string $order_by * @param string $direction * @return WPPostDriver */ public function order_by( $order_by, $direction = 'ASC' ) { // Make an exception for the rand() method. $order_by = preg_replace( '/rand\(\s*\)/', 'rand', $order_by ); if ( in_array( $order_by, $this->_get_querable_table_columns() ) ) { $this->query_args['orderby'] = $order_by; } else { // ordering by a meta value. $this->query_args['orderby'] = 'meta_value'; $this->query_args['meta_key'] = $order_by; } $this->query_args['order'] = $direction; return $this; } /** * Specifies a limit and optional offset * * @param int $max * @param int|bool $offset (optional) * @return object */ public function limit( $max, $offset = false ) { if ( $max ) { $this->query_args['paged'] = true; if ( $offset ) { $this->query_args['offset'] = $offset; } else { unset( $this->query_args['offset'] ); } $this->query_args['posts_per_page'] = $max; } return $this; } /** * Specifies a list of columns to group by * * @param array|string $columns * @return object */ public function group_by( $columns = [] ) { if ( ! isset( $this->query_args['group_by_columns'] ) ) { $this->query_args['group_by_columns'] = $columns; } else { $this->query_args['group_by_columns'] = array_merge( $this->query_args['group_by_columns'], $columns ); } return $this; } /** * Adds a WP_Query where clause * * @param array $where_clauses * @param string $join */ public function add_where_clause( $where_clauses, $join ) { foreach ( $where_clauses as $clause ) { // Determine where what the where clause is comparing. switch ( $clause['column'] ) { case 'author': case 'author_id': $this->query_args['author'] = $clause['value']; break; case 'author_name': $this->query_args['author_name'] = $clause['value']; break; case 'cat': case 'cat_id': case 'category_id': switch ( $clause['compare'] ) { case '=': case 'BETWEEN'; case 'IN'; if ( ! isset( $this->query_args['category__in'] ) ) { $this->query_args['category__in'] = []; } $this->query_args['category__in'][] = $clause['value']; break; case '!=': case 'NOT BETWEEN'; case 'NOT IN'; if ( ! isset( $this->query_args['category__not_in'] ) ) { $this->query_args['category__not_in'] = []; } $this->query_args['category__not_in'][] = $clause['value']; break; } break; case 'category_name': $this->query_args['category_name'] = $clause['value']; break; case 'post_id': case $this->get_primary_key_column(): switch ( $clause['compare'] ) { case '=': case 'IN'; case 'BETWEEN'; if ( ! isset( $this->query_args['post__in'] ) ) { $this->query_args['post__in'] = []; } $this->query_args['post__in'][] = $clause['value']; break; default: if ( ! isset( $this->query_args['post__not_in'] ) ) { $this->query_args['post__not_in'] = []; } $this->query_args['post__not_in'][] = $clause['value']; break; } break; case 'pagename': case 'postname': case 'page_name': case 'post_name': if ( $clause['compare'] == 'LIKE' ) { $this->query_args['page_name__like'] = $clause['value']; } elseif ( $clause['compare'] == '=' ) { $this->query_args['pagename'] = $clause['value']; } elseif ( $clause['compare'] == 'IN' ) { $this->query_args['page_name__in'] = $clause['value']; } break; case 'post_title': // Post title uses custom WHERE clause. if ( $clause['compare'] == 'LIKE' ) { $this->query_args['post_title__like'] = $clause['value']; } else { $this->query_args['post_title'] = $clause['value']; } break; default: // Must be metadata. $clause['key'] = $clause['column']; unset( $clause['column'] ); // Convert values to array, when required. if ( in_array( $clause['compare'], [ 'IN', 'BETWEEN' ] ) ) { $clause['value'] = explode( ',', $clause['value'] ); foreach ( $clause['value'] as &$val ) { if ( ! is_numeric( $val ) ) { // In the _parse_where_clause() method, we. // quote the strings and add slashes. $val = stripslashes( $val ); $val = substr( $val, 1, strlen( $val ) - 2 ); } } } if ( ! isset( $this->query_args['meta_query'] ) ) { $this->query_args['meta_query'] = []; } $this->query_args['meta_query'][] = $clause; break; } } // If any where clauses have been added, specify how the conditions. // will be conbined/joined. if ( isset( $this->query_args['meta_query'] ) ) { $this->query_args['meta_query']['relation'] = $join; } } /** * Converts a post to an entity. * * @param \stdClass $post * @param boolean $model * @return \stdClass */ public function convert_post_to_entity( $post, $model = false ) { $entity = new \stdClass(); // Unserialize the post_content_filtered field. if ( is_string( $post->post_content_filtered ) ) { if ( ( $post_content = Serializable::unserialize( $post->post_content_filtered ) ) ) { foreach ( $post_content as $key => $value ) { $post->$key = $value; } } } // Unserialize the post content field. if ( is_string( $post->post_content ) ) { if ( ( $post_content = Serializable::unserialize( $post->post_content ) ) ) { foreach ( $post_content as $key => $value ) { $post->$key = $value; } } } // Copy post fields to entity. unset( $post->post_content ); unset( $post->post_content_filtered ); foreach ( $post as $key => $value ) { $entity->$key = $value; } $this->_convert_to_entity( $entity ); return $model ? $this->convert_to_model( $entity ) : $entity; } /** * Converts an entity to a post * * @param object $entity * @return object */ public function _convert_entity_to_post( $entity ) { // Was a model passed instead of an entity? $post = $entity; // Create the post content. $post_content = clone $post; foreach ( $this->_table_columns as $column ) { unset( $post_content->$column ); } unset( $post->id_field ); unset( $post->post_content_filtered ); unset( $post->post_content ); $post->post_content = Serializable::serialize( $post_content ); $post->post_content_filtered = $post->post_content; $post->post_type = $this->get_object_name(); // Sometimes an entity can contain a data stored in an array or object // Those will be removed from the post, and serialized in the // post_content field. foreach ( $post as $key => $value ) { if ( in_array( strtolower( gettype( $value ) ), [ 'object', 'array' ] ) ) { unset( $post->$key ); } } // A post required a title. if ( empty( $post->post_title ) ) { $post->post_title = $this->get_post_title( $post ); } // A post also requires an excerpt. if ( empty( $post->post_excerpt ) ) { $post->post_excerpt = $this->get_post_excerpt( $post ); } return $post; } /** * Returns the WordPress database class * * @global \wpdb $wpdb * @return \wpdb */ public function _wpdb() { global $wpdb; return $wpdb; } /** * Flush and update all postmeta for a particular post * * @param int $post_id */ public function _flush_and_update_postmeta( $post_id, $entity, $omit = [] ) { // We need to insert post meta data for each property // Unfortunately, that means flushing all existing postmeta // and then inserting new values. Depending on the number of // properties, this could be slow. So, we directly access the database. /* @var \wpdb $wpdb */ global $wpdb; if ( ! is_array( $omit ) ) { $omit = [ $omit ]; } // By default, we omit creating meta values for columns in the posts table. $omit = array_merge( $omit, $this->_table_columns ); // Delete the existing meta values. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id = %s", $post_id ) ); // Create query for new meta values. $sql_parts = []; foreach ( $entity as $key => $value ) { if ( in_array( $key, $omit ) ) { continue; } if ( is_array( $value ) or is_object( $value ) ) { $value = Serializable::serialize( $value ); } $sql_parts[] = $wpdb->prepare( '(%s, %s, %s)', $post_id, $key, $value ); } // The following $sql_parts is already sent through $wpdb->prepare() -- look directly above this line // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) VALUES " . implode( ',', $sql_parts ) ); } /** * Determines whether the current statement is SELECT * * @return boolean */ public function is_select_statement() { return isset( $this->query_args['is_select'] ) && $this->query_args['is_select']; } /** * Runs the query * * @param string|bool $sql (optional) Run the specified query * @param object|bool $model (optional) * @param bool $convert_to_entities (optional) Default = true * @return array */ public function run_query( $sql = false, $model = true, $convert_to_entities = true ) { $retval = []; $results = []; // All of our custom fields are stored as post meta, but is also stored as a serialized value in the post_content // field. Because of this, we don't need to look up and cache the post meta values. $this->query_args['no_found_posts'] = false; $this->query_args['update_post_meta_cache'] = false; // Don't cache any manual SQL query. if ( $sql ) { $this->query_args['cache_results'] = false; $this->query_args['custom_sql'] = $sql; } // If this is a select query, then try fetching the results from cache. $cache_key = md5( json_encode( $this->query_args ) ); if ( $this->is_select_statement() && $this->use_cache ) { $results = $this->get_from_cache( $cache_key ); } // Execute the query. if ( ! $results ) { $query = new \WP_Query( [ 'datamapper' => true, 'fields' => '*' ] ); if ( isset( $this->debug ) ) { $this->query_args['debug'] = true; } $query->query_vars = $this->query_args; add_action( 'pre_get_posts', [ &$this, 'set_query_args' ], PHP_INT_MAX - 1, 1 ); $results = $query->get_posts(); // Cache the result. if ( $this->is_select_statement() ) { $this->cache( $cache_key, $results ); } remove_action( 'pre_get_posts', [ &$this, 'set_query_args' ], PHP_INT_MAX - 1 ); } // Convert the result. if ( $convert_to_entities ) { foreach ( $results as $row ) { $retval[] = $this->convert_post_to_entity( $row, $model ); } } else { $retval = $results; } // Ensure that we return an empty array when there are no results. if ( ! $retval ) { $retval = []; } return $retval; } /** * Ensure that the query args are set. We need to do this in case a third-party * plugin overrides our query. * * @param $query */ public function set_query_args( $query ) { if ( $query->get( 'datamapper' ) ) { $query->query_vars = $this->query_args; } $filter = isset( $query->query_vars['suppress_filters'] ) ? $query->query_vars['suppress_filters'] : false; $query->query_vars['suppress_filters'] = apply_filters( 'wpml_suppress_filters', $filter ); } /** * Returns the number of total records/entities that exist * * @return int */ public function count() { $this->select( $this->get_primary_key_column() ); $retval = $this->run_query( false, false, false ); return count( $retval ); } /** * Used to select which fields should be returned. NOT currently used by * this implementation of the datamapper driver * * @param string $fields * @return WPPostDriver */ public function select( $fields = '*' ) { $this->query_args = [ 'post_type' => $this->get_object_name(), 'paged' => false, 'fields' => $fields, 'post_status' => 'any', 'datamapper' => true, 'posts_per_page' => -1, 'is_select' => true, 'is_delete' => false, ]; return $this; } /** * Destroys/deletes an entity from the database * * @param \stdClass|Model|int $entity * @param bool $skip_trash (optional) Default = true * @return bool */ public function destroy( $entity, $skip_trash = true ) { $retval = false; $key = $this->get_primary_key_column(); // Find the id of the entity. if ( is_object( $entity ) && isset( $entity->$key ) ) { $id = (int) $entity->$key; } else { $id = (int) $entity; } // If we have an ID, then delete the post. if ( is_integer( $id ) ) { // TODO: We assume that we can skip the trash. Is that correct? // FYI, Deletes postmeta as wells. if ( is_object( wp_delete_post( $id, true ) ) ) { $retval = true; } } return $retval; } /** * Saves an entity to the database * * @param object $entity * @return int Post ID */ public function save_entity( $entity ) { $post = $this->_convert_entity_to_post( $entity ); $primary_key = $this->get_primary_key_column(); // Avoid pre_replace deprecation exception on sanitize_mime_type() by ensuring mime type is not null. if ( is_null( $post->post_mime_type ) ) { $post->post_mime_type = ''; } // TODO: unsilence this. WordPress 3.9-beta2 is generating an error that should be corrected before its final release. if ( ( $post_id = wp_insert_post( (array) $post ) ) ) { $new_entity = $this->find( $post_id, true ); if ( $new_entity ) { foreach ( get_object_vars( $new_entity ) as $key => $value ) { $entity->$key = $value; } } // Save properties as post meta. $this->_flush_and_update_postmeta( $post_id, $entity ); $entity->$primary_key = $post_id; // Clean cache. $this->cache = []; } $entity->id_field = $primary_key; return $post_id; } /** * Starts a new DELETE statement. */ public function delete() { $this->select(); $this->query_args['is_select'] = false; $this->query_args['is_delete'] = true; return $this; } /** * Returns the title of the post. Used when post_title is not set * * @param \stdClass $entity * @return string */ public function get_post_title( $entity ) { return "Untitled {$this->get_object_name()}"; } /** * Returns the excerpt of the post. Used when post_excerpt is not set * * @param \stdClass $entity * @return string */ public function get_post_excerpt( $entity ) { return ''; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMapper/DriverBase.php���������������������������������������������������������������������������0000644�����������������00000041207�15021223045�0011317 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; use Imagely\NGG\Util\Transient; abstract class DriverBase { public $_object_name; public $_columns = []; public $_table_columns = []; public $_serialized_columns = []; public $primary_key_column = ''; public $use_cache; public $cache = []; public $model_class = ''; public function __construct( $object_name = '' ) { $this->_object_name = $object_name; $this->lookup_columns(); } abstract public function add_where_clause( $where_clauses, $join ); abstract public function save_entity( $entity ); abstract public function select( $fields = null ); /** * @return string */ public function get_object_name() { return $this->_object_name; } /** * @global string $table_prefix * @return string */ public function get_table_name() { global $table_prefix; global $wpdb; $prefix = $table_prefix; if ( $wpdb != null && $wpdb->prefix != null ) { $prefix = $wpdb->prefix; } return \apply_filters( 'ngg_datamapper_table_name', $prefix . $this->_object_name, $this->_object_name ); } /** * Looks up using SQL the columns existing in the database, result is cached */ public function lookup_columns() { // Avoid doing multiple SHOW COLUMNS if we can help it. $key = Transient::create_key( 'col_in_' . $this->get_table_name(), 'columns' ); $this->_table_columns = Transient::fetch( $key, false ); if ( ! $this->_table_columns ) { $this->update_columns_cache(); } return $this->_table_columns; } /** * Looks up using SQL the columns existing in the database */ public function update_columns_cache() { global $wpdb; $key = Transient::create_key( 'col_in_' . $this->get_table_name(), 'columns' ); $this->_table_columns = []; // $wpdb->prepare() cannot be used just yet as it only supported the %i placeholder for column names as of // WordPress 6.2 which is newer than NextGEN's current minimum WordPress version. // // TODO: Once NextGEN's minimum WP version is 6.2 or higher use wpdb->prepare() here. // // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared foreach ( $wpdb->get_results( "SHOW COLUMNS FROM {$this->get_table_name()}" ) as $row ) { $this->_table_columns[] = $row->Field; } Transient::update( $key, $this->_table_columns ); } /** * @param string $column_name * @return bool */ public function has_column( $column_name ) { if ( empty( $this->_table_columns ) ) { $this->lookup_columns(); } return array_search( $column_name, $this->_table_columns ) !== false; } /** * @return string */ public function get_primary_key_column() { return $this->primary_key_column; } public function cache( $key, $results ) { if ( $this->use_cache ) { $this->cache[ $key ] = $results; } } public function get_from_cache( $key, $default = null ) { if ( $this->use_cache && isset( $this->cache[ $key ] ) ) { return $this->cache[ $key ]; } else { return $default; } } public function flush_query_cache() { $this->cache = []; } /** * Used to clean column or table names in a SQL query * * @param string $val * @return string */ public function _clean_column( $val ) { return str_replace( [ ';', "'", '"', '`' ], [ '' ], $val ); } /** * Notes that a particular columns is serialized, and should be deserialized when converted to an entity * * @param $column */ public function add_serialized_column( $column ) { $this->_serialized_columns[] = $column; } public function deserialize_columns( $object ) { foreach ( $this->_serialized_columns as $column ) { if ( isset( $object->$column ) && is_string( $object->$column ) ) { $object->$column = \Imagely\NGG\Util\Serializable::unserialize( $object->$column ); } } } /** * @param array $conditions (optional) * @param object|bool $model (optional) * @return null|object */ public function find_first( $conditions = [] ) { $results = $this->select()->where_and( $conditions )->limit( 1, 0 )->run_query(); if ( $results ) { return $this->convert_to_model( $results[0] ); } else { return null; } } /** * @param array $conditions (optional) * @return array */ public function find_all( $conditions = [] ) { $results = $this->select()->where_and( $conditions )->run_query(); if ( $results ) { foreach ( $results as &$result ) { $result = $this->convert_to_model( $result ); } } return $results; } /** * Filters the query: * array("post_title = %s", "Foo") * OR * array( * array("post_title = %s", "Foo") * ) * * @param array $conditions (optional) * @return self */ public function where_and( $conditions = [] ) { return $this->_where( $conditions, 'AND' ); } /** * @param array $conditions (optional) * @return self */ public function where( $conditions = [] ) { return $this->_where( $conditions, 'AND' ); } /** * Parses the where clauses. They could look like the following: * array( * "post_id = 1" * array("post_id = %d", 1), * ) * * or simply "post_id = 1" * * @param array|string $conditions * @param string $operator * @return self */ public function _where( $conditions, $operator ) { $where_clauses = []; // If conditions is not an array, make it one. if ( ! is_array( $conditions ) ) { $conditions = [ $conditions ]; } // Just a single condition was passed, but with a bind. elseif ( ! empty( $conditions ) && ! is_array( $conditions[0] ) ) { $conditions = [ $conditions ]; } // Iterate through each condition. foreach ( $conditions as $condition ) { if ( is_string( $condition ) ) { $clause = $this->_parse_where_clause( $condition ); if ( $clause ) { $where_clauses[] = $clause; } } else { $clause = array_shift( $condition ); $clause = $this->_parse_where_clause( $clause, $condition ); if ( $clause ) { $where_clauses[] = $clause; } } } // Add where clause to query. if ( $where_clauses ) { $this->add_where_clause( $where_clauses, $operator ); } return $this; } /** * Parses a where clause and returns an associative array * representing the query * * E.g. parse_where_clause("post_title = %s", "Foo Bar") * * @global wpdb $wpdb * @param string $condition * @return array */ public function _parse_where_clause( $condition ) { $column = ''; $operator = ''; $value = ''; $numeric = true; // Substitute any placeholders. global $wpdb; $binds = func_get_args(); $binds = isset( $binds[1] ) ? $binds[1] : []; // first argument is the condition. foreach ( $binds as &$bind ) { // A bind could be an array, used for the 'IN' operator // or a simple scalar value. We need to convert arrays // into scalar values. if ( is_object( $bind ) ) { $bind = (array) $bind; } if ( is_array( $bind ) && ! empty( $bind ) ) { foreach ( $bind as &$val ) { if ( ! is_numeric( $val ) ) { $val = '"' . addslashes( $val ) . '"'; $numeric = false; } } $bind = implode( ',', $bind ); } elseif ( is_array( $bind ) && empty( $bind ) ) { $bind = 'NULL'; } elseif ( ! is_numeric( $bind ) ) { $numeric = false; } } if ( $binds ) { // PHP-CS triggers a false positive on this; $condition is a string that contains the placeholders. // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $condition = $wpdb->prepare( $condition, $binds ); } // Parse the where clause. if ( preg_match( '/^[^\s]+/', $condition, $match ) ) { $column = trim( array_shift( $match ) ); $condition = str_replace( $column, '', $condition ); } if ( preg_match( '/(NOT )?IN|(NOT )?LIKE|(NOT )?BETWEEN|[=!<>]+/i', $condition, $match ) ) { $operator = trim( array_shift( $match ) ); $condition = str_replace( $operator, '', $condition ); $operator = strtolower( $operator ); $value = trim( $condition ); } // Values will automatically be quoted, so remove them // If the value is part of an IN clause or BETWEEN clause and // has multiple values, we attempt to split the values apart into an // array and iterate over them individually. if ( $operator == 'in' ) { $values = preg_split( "/'?\s?(,)\s?'?/i", $value ); } elseif ( $operator == 'between' ) { $values = preg_split( "/'?\s?(AND)\s?'?/i", $value ); } // If there's a single value, treat it as an array so that we can still iterate. if ( empty( $values ) ) { $values = [ $value ]; } foreach ( $values as $index => $value ) { $value = preg_replace( "/^(\()?'/", '', $value ); $value = preg_replace( "/'(\))?$/", '', $value ); $values[ $index ] = $value; } if ( count( $values ) > 1 ) { $value = $values; } // Return the WP Query meta query parameters. $retval = [ 'column' => $column, 'value' => $value, 'compare' => strtoupper( $operator ), 'type' => $numeric ? 'numeric' : 'string', ]; return $retval; } public function strip_slashes( $stdObject_or_array_or_string ) { /** * Some objects have properties that are recursive objects. To avoid this we have to keep track of what objects * we've already processed when we're running this method recursively. */ static $level = 0; static $processed_objects = []; ++$level; $processed_objects[] = $stdObject_or_array_or_string; if ( is_string( $stdObject_or_array_or_string ) ) { $stdObject_or_array_or_string = str_replace( "\\'", "'", str_replace( '\"', '"', str_replace( '\\\\', '\\', $stdObject_or_array_or_string ) ) ); } elseif ( is_object( $stdObject_or_array_or_string ) && ! in_array( $stdObject_or_array_or_string, $processed_objects ) ) { foreach ( get_object_vars( $stdObject_or_array_or_string ) as $key => $val ) { if ( $val != $stdObject_or_array_or_string && $key != '_mapper' ) { $stdObject_or_array_or_string->$key = $this->strip_slashes( $val ); } } $processed_objects[] = $stdObject_or_array_or_string; } elseif ( is_array( $stdObject_or_array_or_string ) ) { foreach ( $stdObject_or_array_or_string as $key => $val ) { if ( $key != '_mixins' ) { $stdObject_or_array_or_string[ $key ] = $this->strip_slashes( $val ); } } } --$level; if ( $level == 0 ) { $processed_objects = []; } return $stdObject_or_array_or_string; } /** * Converts a stdObject entity to a model * * @param object $stdObject * @param string|bool $context (optional) * @return object */ public function convert_to_model( $stdObject, $context = false ) { try { $this->_convert_to_entity( $stdObject ); } catch ( \Exception $ex ) { throw new \E_InvalidEntityException( $ex ); } return $this->create( $stdObject ); } /** * Determines whether an object is actually a model * * @param mixed $obj * @return bool */ public function is_model( $obj ) { return is_subclass_of( $obj, '\Imagely\NGG\DataMapper\Model' ); } /** * If a field has no value, then use the default value. * * @param \stdClass|Model $object */ public function set_default_value( $object ) { $array = null; $field = null; $default_value = null; // The first argument MUST be an object. if ( ! is_object( $object ) ) { throw new \E_InvalidEntityException(); } // This method has two signatures: // 1) _set_default_value($object, $field, $default_value) // 2) _set_default_value($object, $array_field, $field, $default_value). // Handle #1. $args = func_get_args(); if ( count( $args ) == 4 ) { list($object, $array, $field, $default_value) = $args; if ( ! isset( $object->{$array} ) ) { $object->{$array} = []; $object->{$array}[ $field ] = null; } else { $arr = &$object->{$array}; if ( ! isset( $arr[ $field ] ) ) { $arr[ $field ] = null; } } $array = &$object->{$array}; $value = &$array[ $field ]; if ( $value === '' or is_null( $value ) ) { $value = $default_value; } } // Handle #2. else { list($object, $field, $default_value) = $args; if ( ! isset( $object->$field ) ) { $object->$field = null; } $value = $object->$field; if ( $value === '' or is_null( $value ) ) { $object->$field = $default_value; } } } public function has_defined_column( $name ) { $columns = $this->_columns; return isset( $columns[ $name ] ); } public function cast_columns( $entity ) { foreach ( $this->_columns as $key => $properties ) { $value = property_exists( $entity, $key ) ? $entity->$key : null; $default_value = $properties['default_value']; if ( ! is_null( $value ) && $value !== $default_value ) { $column_type = $this->_columns[ $key ]['type']; if ( preg_match( '/varchar|text/i', $column_type ) ) { if ( ! is_array( $value ) && ! is_object( $value ) ) { $entity->$key = strval( $value ); } } elseif ( preg_match( '/decimal|numeric|double|float/i', $column_type ) ) { $entity->$key = floatval( $value ); } elseif ( preg_match( '/int/i', $column_type ) ) { $entity->$key = intval( $value ); } elseif ( preg_match( '/bool/i', $column_type ) ) { $entity->$key = ( $value ? true : false ); } } else { // Add property and default value. $entity->$key = $default_value; } } return $entity; } /** * Finds a particular entry by id * * @param int|\stdClass|Model $entity * @return null|object|Model */ public function find( $entity ) { $retval = null; // Get primary key of the entity. $pkey = $this->get_primary_key_column(); if ( ! is_numeric( $entity ) ) { $entity = isset( $entity->$pkey ) ? intval( $entity->$pkey ) : false; } // If we have an entity ID, then get the record. if ( $entity ) { $results = $this->select()->where_and( [ "{$pkey} = %d", $entity ] )->limit( 1, 0 )->run_query(); if ( $results ) { $retval = $this->convert_to_model( $results[0] ); } } return $retval; } /** * Converts a stdObject to an Entity * * @param \stdClass $entity * @return object */ public function _convert_to_entity( $entity ) { // Add extra columns to entity. if ( isset( $entity->extras ) ) { $extras = $entity->extras; unset( $entity->extras ); foreach ( explode( ',', $extras ) as $extra ) { if ( $extra ) { $parts = explode( '@@', $extra ); if ( count( $parts ) === 2 ) { // Ensure we have exactly two parts. list( $key, $value ) = $parts; if ( $this->has_defined_column( $key ) && ! isset( $entity->$key ) && $key !== 'extras_post_id' ) { $entity->$key = $value; } } } } } // Cast custom_post_id as integer. if ( isset( $entity->extras_post_id ) ) { $entity->extras_post_id = intval( $entity->extras_post_id ); } else { $entity->extras_post_id = 0; } // Add name of the id_field to the entity, and convert the ID to an integer. $entity->id_field = $this->get_primary_key_column(); // Cast columns to their appropriate data type. $this->cast_columns( $entity ); // Strip slashes. $this->strip_slashes( $entity ); // Deserialize columns. $this->deserialize_columns( $entity ); return $entity; } /** * Creates a new model * * @param array $properties (optional) * @return object */ public function create( $properties = [] ) { $entity = new \stdClass(); foreach ( $properties as $key => $value ) { $entity->$key = $value; } return new $this->model_class( $entity ); } /** * Saves an entity * * @param \stdClass|Model $entity * @return bool|int Resulting ID or false upon failure */ public function save( $entity ) { $retval = false; $model = $entity; $this->flush_query_cache(); if ( is_array( $entity ) ) { throw new \E_InvalidEntityException(); } elseif ( ! $this->is_model( $entity ) ) { // We can work with what we have. But we need to ensure that we've got a model. $model = $this->convert_to_model( $entity ); } if ( ! is_array( $model->validation() ) ) { $retval = $this->save_entity( $model ); } $this->flush_query_cache(); return $retval; } /** * Gets validation errors for the entity * * @param \stdClass|Model $entity * @return array */ public function get_errors( $entity ) { $model = $entity; if ( ! $this->is_model( $entity ) ) { $model = $this->convert_to_model( $entity ); } return $model->validation(); } /** * @param object $entity */ public function set_defaults( $entity ) {} /** * @param string $name * @param string $type * @param string|number $default_value * @param bool $extra * @return void */ public function define_column( $name, $type, $default_value = null, $extra = false ) { $this->_columns[ $name ] = [ 'type' => $type, 'default_value' => $default_value, 'extra' => $extra, ]; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMapper/TableDriver.php��������������������������������������������������������������������������0000644�����������������00000037475�15021223045�0011510 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; use Imagely\NGG\Util\Serializable; class TableDriver extends DriverBase { public $where_clauses = []; public $order_clauses = []; public $group_by_columns = []; public $limit_clause = ''; public $select_clause = ''; public $delete_clause = ''; public $use_cache = true; public $debug = false; public $_custom_post_mapper; // Necessary for backwards compatibility. public $custom_post_name = __CLASS__; public function __construct( $object_name = '' ) { parent::__construct( $object_name ); try { if ( ! isset( $this->primary_key_column ) ) { $this->primary_key_column = $this->_lookup_primary_key_column(); } $this->migrate(); } catch ( \Exception $exception ) { } // Each record in a NextGEN Gallery table has an associated custom post in the wp_posts table. $this->_custom_post_mapper = new WPPostDriver( $this->get_object_name() ); $this->_custom_post_mapper->model_class = 'Imagely\NGG\DataTypes\DataMapperExtraFields'; } /** * Returns the database connection object for WordPress * * @global \wpdb $wpdb * @return \wpdb */ public function _wpdb() { global $wpdb; return $wpdb; } /** * Looks up the primary key column for this table * * @throws \Exception */ public function _lookup_primary_key_column() { $key = $this->_wpdb()->get_row( "SHOW INDEX FROM {$this->get_table_name()} WHERE Key_name='PRIMARY'", ARRAY_A ); if ( ! $key ) { throw new \Exception( "Please specify the primary key for {$this->get_table_name ()}" ); } return $key['Column_name']; } /** * Gets the name of the primary key column * * @return string */ public function get_primary_key_column() { return $this->primary_key_column; } /** * Determines whether we're going to execute a SELECT statement * * @return boolean */ public function is_select_statement() { return (bool) $this->select_clause; } /** * Determines if we're going to be executing a DELETE statement * * @return bool */ public function is_delete_statement() { return (bool) $this->delete_clause; } /** * Orders the results of the query * This method may be used multiple of times to order by more than column * * @param $order_by * @param $direction * @return self */ public function order_by( $order_by, $direction = 'ASC' ) { // We treat the rand() function as an exception. if ( preg_match( '/rand\(\s*\)/', $order_by ) ) { $order = 'rand()'; } else { $order_by = $this->_clean_column( $order_by ); // If the order by clause is a column, then it should be backticked. if ( $this->has_column( $order_by ) ) { $order_by = "`{$order_by}`"; } $direction = $this->_clean_column( $direction ); $order = "{$order_by} {$direction}"; } $this->order_clauses[] = $order; return $this; } /** * Specifies a limit and optional offset * * @param integer $max * @param integer $offset * @return self */ public function limit( $max, $offset = 0 ) { if ( $offset ) { $limit = $this->_wpdb()->prepare( 'LIMIT %d, %d', max( 0, $offset ), $max ); } else { $limit = $this->_wpdb()->prepare( 'LIMIT %d', max( 0, $max ) ); } /*** * Set $limit to false when we want to display all records, that is $items_per_page = all. * LIMIT 0 results in no entries found error. So we remove limit_clause altogether. */ if ( (int) $max < 0 ) { $limit = false; $this->limit_clause = false; } if ( $limit ) { $this->limit_clause = $limit; } return $this; } /** * Specifics a group by clause for one or more columns * * @param array|string $columns * @return self */ public function group_by( $columns = [] ) { if ( ! is_array( $columns ) ) { $columns = [ $columns ]; } $this->group_by_columns = array_merge( $this->group_by_columns, $columns ); return $this; } /** * Adds a where clause to the driver * * @param array $where_clauses * @param string $join */ public function add_where_clause( $where_clauses, $join ) { $clauses = []; foreach ( $where_clauses as $clause ) { extract( $clause ); if ( $this->has_column( $column ) ) { $column = "`{$column}`"; } if ( ! is_array( $value ) ) { $value = [ $value ]; } foreach ( $value as $index => $v ) { $v = $clause['type'] == 'numeric' ? $v : "'{$v}'"; $value[ $index ] = $v; } if ( $compare == 'BETWEEN' ) { $value = "{$value[0]} AND {$value[1]}"; } else { $value = implode( ', ', $value ); if ( strpos( $compare, 'IN' ) !== false ) { $value = "({$value})"; } } $clauses[] = "{$column} {$compare} {$value}"; } $this->where_clauses[] = implode( " {$join} ", $clauses ); } /** * Returns the total number of entities known * * @return int */ public function count() { $retval = 0; $key = $this->get_primary_key_column(); /** @noinspection SqlResolve */ $results = $this->run_query( "SELECT COUNT(`{$key}`) AS `{$key}` FROM `{$this->get_table_name()}`" ); if ( $results && isset( $results[0]->$key ) ) { $retval = (int) $results[0]->$key; } return $retval; } /** * Run the query * * @param string|bool $sql (optional) run the specified SQL * @param object|bool $model (optional) * @param bool $no_entities (optional) * @return array */ public function run_query( $sql = false, $model = false, $no_entities = false ) { $results = false; $retval = []; // Or generate SQL query. if ( ! $sql ) { $sql = $this->get_generated_query( $no_entities ); } // If we have a SQL statement to execute, then heck, execute it!. if ( $sql ) { if ( $this->debug ) { var_dump( $sql ); } // Try getting the result from cache first. if ( $this->is_select_statement() && $this->use_cache ) { $results = $this->get_from_cache( $sql ); } } if ( ! $results ) { $this->_wpdb()->query( $sql ); $results = $this->_wpdb()->last_result; if ( $this->is_select_statement() ) { $this->cache( $sql, $results ); } } if ( $results ) { $retval = []; // For each row, create an entity, update its properties, and add it to the result set. if ( $no_entities ) { $retval = $results; } else { $id_field = $this->get_primary_key_column(); foreach ( $results as $row ) { if ( $row ) { if ( isset( $row->$id_field ) ) { if ( $model ) { $retval[] = $this->convert_to_model( $row ); } else { $retval[] = $this->_convert_to_entity( $row ); } } } } } } elseif ( $this->debug ) { var_dump( 'No entities returned from query' ); } // Just a safety check. if ( ! $retval ) { $retval = []; } return $retval; } /** * Converts an entity to something suitable for inserting into a database column * * @param object $entity * @return array */ public function _convert_to_table_data( $entity ) { $data = (array) $entity; foreach ( $data as $key => $value ) { if ( ! isset( $this->_columns[ $key ] ) || $this->_columns[ $key ]['extra'] ) { unset( $data[ $key ] ); continue; } if ( is_array( $value ) ) { $data[ $key ] = Serializable::serialize( $value ); } } return $data; } public function get_column_names() { return array_keys( $this->_columns ); } /** * Migrates the schema of the database * * @throws \Exception */ public function migrate() { if ( ! $this->_columns ) { throw new \Exception( "Columns not defined for {$this->get_table_name()}" ); } $added = false; $removed = false; // Add any missing columns. foreach ( $this->_columns as $key => $properties ) { if ( ! in_array( $key, $this->_table_columns ) ) { if ( $this->_add_column( $key, $properties['type'], $properties['default_value'] ) ) { $added = true; } } } if ( $added or $removed ) { $this->lookup_columns(); } } public function _init() { $this->where_clauses = []; $this->order_clauses = []; $this->group_by_columns = []; $this->limit_clause = ''; $this->select_clause = ''; } /** * Selects which fields to collect from the table. * NOTE: Not protected from SQL injection - DO NOT let your users specify DB columns * * @param string $fields * @return self */ public function select( $fields = null ) { // Create a fresh slate. $this->_init(); if ( ! $fields or $fields == '*' ) { $fields = $this->get_table_name() . '.*'; } $this->select_clause = "SELECT {$fields}"; return $this; } /** * Start a delete statement */ public function delete() { // Create a fresh slate. $this->_init(); $this->delete_clause = 'DELETE'; return $this; } /** * Stores the entity * * @param object $entity * @return bool|self */ public function save_entity( $entity ) { $retval = false; unset( $entity->id_field ); $primary_key = $this->get_primary_key_column(); if ( isset( $entity->$primary_key ) && $entity->$primary_key > 0 ) { if ( $this->_update( $entity ) ) { $retval = intval( $entity->$primary_key ); } } else { $retval = $this->_create( $entity ); if ( $retval ) { $new_entity = $this->find( $retval ); foreach ( $new_entity as $key => $value ) { $entity->$key = $value; } } } $entity->id_field = $primary_key; // Clean cache. if ( $retval ) { $this->cache = []; } return $retval; } /** * Destroys/deletes an entity * * @param object|Model|int $entity * @return boolean */ public function destroy( $entity ) { $retval = false; $key = $this->get_primary_key_column(); if ( isset( $entity->extras_post_id ) ) { \wp_delete_post( $entity->extras_post_id, true ); } // Find the id of the entity. if ( is_object( $entity ) && isset( $entity->$key ) ) { $id = (int) $entity->$key; } else { $id = (int) $entity; } // If we have an ID, then delete the post. if ( is_numeric( $id ) ) { $sql = $this->_wpdb()->prepare( "DELETE FROM `{$this->get_table_name()}` WHERE {$key} = %s", $id ); $retval = $this->_wpdb()->query( $sql ); } return $retval; } /** * @param object $entity * @return boolean */ public function _create( $entity ) { $retval = false; $custom_post_entity = $this->create_custom_post_entity( $entity ); // Try persisting the custom post type record first. if ( ( $custom_post_id = $this->_custom_post_mapper->save( $custom_post_entity ) ) ) { $entity->extras_post_id = $custom_post_id; } $table_data = $this->_convert_to_table_data( $entity ); $id = $this->_wpdb()->insert( $this->get_table_name(), $table_data ); if ( $id ) { $key = $this->get_primary_key_column(); $retval = $entity->$key = intval( $this->_wpdb()->insert_id ); } // Remove the custom post if saving the normal table entry failed. if ( ! $retval && isset( $custom_post_id ) ) { $this->_custom_post_mapper->destroy( $custom_post_id ); } return $retval; } /** * Updates a record in the database * * @param object $entity * @return int|bool */ public function _update( $entity ) { $key = $this->get_primary_key_column(); $custom_post_entity = $this->create_custom_post_entity( $entity ); $custom_post_id = $this->_custom_post_mapper->save( $custom_post_entity ); $entity->extras_post_id = $custom_post_id; $table_data = $this->_convert_to_table_data( $entity ); $retval = $this->_wpdb()->update( $this->get_table_name(), $table_data, [ $key => $entity->$key, ] ); foreach ( $this->get_extra_columns() as $key ) { if ( isset( $custom_post_entity->$key ) ) { $entity->$key = $custom_post_entity->$key; } } return $retval; } /** * @param string $column_name * @param string $datatype * @param string|number $default_value * @return bool */ public function _add_column( $column_name, $datatype, $default_value = null ) { if ( isset( $this->_columns[ $column_name ] ) && $this->_columns[ $column_name ]['extra'] ) { return false; } /** @noinspection SqlResolve */ $sql = "ALTER TABLE `{$this->get_table_name()}` ADD COLUMN `{$column_name}` {$datatype}"; if ( $default_value ) { if ( is_string( $default_value ) ) { $default_value = str_replace( "'", "\\'", $default_value ); } $sql .= ' NOT NULL DEFAULT ' . ( is_string( $default_value ) ? "'{$default_value}" : "{$default_value}" ); } $return = (bool) $this->_wpdb()->query( $sql ); $this->update_columns_cache(); return $return; } /** * @param bool $no_entities Default: false * @return array|string|string[] */ public function get_generated_query( $no_entities = false ) { // Add extras column. if ( $this->is_select_statement() && stripos( $this->select_clause, 'count(' ) === false ) { $table_name = $this->get_table_name(); $primary_key = "{$table_name}.{$this->get_primary_key_column()}"; if ( stripos( $this->select_clause, 'DISTINCT' ) === false ) { $this->select_clause = str_replace( 'SELECT', 'SELECT DISTINCT', $this->select_clause ); } $this->group_by( $primary_key ); $sql = $this->get_actual_generated_query( $no_entities ); // Sections may be omitted by wrapping them in mysql's C style comments. if ( stripos( $sql, '/*NGG_NO_EXTRAS_TABLE*/' ) !== false ) { $parts = explode( '/*NGG_NO_EXTRAS_TABLE*/', $sql ); foreach ( $parts as $ndx => $row ) { if ( $ndx % 2 != 0 ) { continue; } $parts[ $ndx ] = $this->_regex_replace( $row ); } $sql = implode( '', $parts ); } else { $sql = $this->_regex_replace( $sql ); } } else { $sql = $this->get_actual_generated_query( $no_entities ); } return $sql; } /** * @param bool $no_entities Default = false * @return string */ public function get_actual_generated_query( $no_entities = false ) { $sql = []; if ( $this->is_select_statement() ) { $sql[] = $this->select_clause; } elseif ( $this->is_delete_statement() ) { $sql[] = $this->delete_clause; } $sql[] = 'FROM `' . $this->get_table_name() . '`'; $where_clauses = []; foreach ( $this->where_clauses as $where ) { $where_clauses[] = '(' . $where . ')'; } if ( $where_clauses ) { $sql[] = 'WHERE ' . implode( ' AND ', $where_clauses ); } if ( $this->is_select_statement() ) { if ( $this->group_by_columns ) { $sql[] = 'GROUP BY ' . implode( ', ', $this->group_by_columns ); } if ( $this->order_clauses ) { $sql[] = 'ORDER BY ' . implode( ', ', $this->order_clauses ); } if ( $this->limit_clause ) { $sql[] = $this->limit_clause; } } return implode( ' ', $sql ); } /** * @return array */ public function get_extra_columns() { $retval = []; foreach ( $this->_columns as $key => $properties ) { if ( $properties['extra'] ) { $retval[] = $key; } } return $retval; } public function create_custom_post_entity( $entity ) { $custom_post_entity = new \stdClass(); // If the custom post entity already exists then it needs an ID. if ( isset( $entity->extras_post_id ) ) { $custom_post_entity->ID = $entity->extras_post_id; } // If a property isn't a column for the table, then it belongs to the custom post record. foreach ( get_object_vars( $entity ) as $key => $value ) { if ( ! $this->has_column( $key ) ) { unset( $entity->$key ); if ( $this->has_defined_column( $key ) && $key != $this->get_primary_key_column() ) { $custom_post_entity->$key = $value; } } } // Used to help find these type of records. $custom_post_entity->post_name = $this->custom_post_name; return $custom_post_entity; } public function _regex_replace( $in ) { global $wpdb; $from = 'FROM `' . $this->get_table_name() . '`'; $out = str_replace( 'FROM', ", GROUP_CONCAT(CONCAT_WS('@@', meta_key, meta_value)) AS 'extras' FROM", $in ); $out = str_replace( $from, "{$from} LEFT OUTER JOIN `{$wpdb->postmeta}` ON `{$wpdb->postmeta}`.`post_id` = `extras_post_id` ", $out ); return $out; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMapper/Model.php��������������������������������������������������������������������������������0000644�����������������00000004242�15021223045�0010327 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; abstract class Model { use Validation; // This attribute is no longer used, but serialized objects created before the POPE -> namespace transition will // still retain this attribute and generate a warning with PHP 8.0 when hydrating the object. public $__defaults_set; public function __construct( \stdClass $object = null ) { if ( $object ) { foreach ( get_object_vars( $object ) as $key => $value ) { $this->$key = $value; } } $this->set_defaults(); } abstract function get_mapper(); /** * This should be removed when POPE compat v1 is reached in Pro * * @deprecated * @return bool|array */ public function validate() { return $this->validation(); } public function validation() { return true; } public function set_defaults() { $mapper = $this->get_mapper(); if ( method_exists( $mapper, 'set_defaults' ) ) { $mapper->set_defaults( $this ); } } /** * @return bool */ public function is_new() { return ! $this->id(); } public function get_primary_key_column() { return 'id'; } /** * @param null|int|string $value (optional) * @return mixed */ public function id( $value = null ) { $key = $this->get_primary_key_column(); if ( $value ) { $this->$key = $value; } return $this->$key; } /** * This should be removed when POPE compat v1 is reached in Pro * * @deprecated * @return array */ public function get_errors() { return $this->validation(); } /** * Necessary for compatibility with some WP-Admin pages. * * @deprecated */ public function clear_errors() { return true; } /** * Determines if a particular field for the object has errors * * @param string $property * @return bool */ public function is_valid( $property = null ) { $errors = $this->validation(); return ! ( is_array( $errors ) && isset( $errors[ $property ] ) ); } /** * @param array $updated_attributes * @return int|bool Object ID or false upon failure */ public function save( $updated_attributes = [] ) { foreach ( $updated_attributes as $key => $value ) { $this->$key = $value; } return $this->get_mapper()->save( $this ); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMapper/Validation.php���������������������������������������������������������������������������0000644�����������������00000025454�15021223045�0011371 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMapper; trait Validation { /** * Hide the above attributes added to Models from var_dump() and the like * * @return array */ public function __debugInfo() { $properties = get_object_vars( $this ); unset( $properties['default_messages'] ); unset( $properties['default_patterns'] ); return $properties; } /** * @param string $validator * @return string */ public function _get_default_error_message_for( $validator ) { $retval = false; if ( isset( ValidationMessages::$default_messages[ $validator ] ) ) { $retval = ValidationMessages::$default_messages[ $validator ]; } return $retval; } /** * @param string $formatter * @return string */ public function get_default_pattern_for( $formatter ) { $retval = false; if ( isset( ValidationMessages::$default_patterns[ $formatter ] ) ) { $retval = ValidationMessages::$default_patterns[ $formatter ]; } return $retval; } /** * @param string|array<string> $str * @return string */ public function humanize_string( $str ) { $retval = []; if ( is_array( $str ) ) { foreach ( $str as $s ) { $retval[] = $this->humanize_string( $s ); } } else { $retval = ucfirst( str_replace( '_', ' ', $str ) ); } return $retval; } /** * Returns TRUE if a property is empty. * * @deprecated Don't use this, it's silly. * @param string $var * @return bool */ public function is_empty( $var, $element = false ) { if ( is_array( $var ) && $element ) { if ( isset( $var[ $element ] ) ) { $var = $var[ $element ]; } else { $var = false; } } return ( is_null( $var ) or ( is_string( $var ) and strlen( $var ) == 0 ) or $var === false ); } /** * @param string $property * @param int $length * @param string $comparison_operator ===, !=, <, >, <=, or >= * @param bool|string $msg * @return array */ public function validates_length_of( $property, $length, $comparison_operator = '=', $msg = false ) { $valid = true; $default_msg = $this->_get_default_error_message_for( __METHOD__ ); if ( ! $this->is_empty( $this->$property ) ) { switch ( $comparison_operator ) { case '=': case '==': $valid = strlen( $this->$property ) == $length; $default_msg = $this->_get_default_error_message_for( 'validates_equals' ); break; case '!=': case '!': $valid = strlen( $this->$property ) != $length; $default_msg = $this->_get_default_error_message_for( 'validates_equals' ); break; case '<': $valid = strlen( $this->$property ) < $length; $default_msg = $this->_get_default_error_message_for( 'validates_less_than' ); break; case '>': $valid = strlen( $this->$property ) > $length; $default_msg = $this->_get_default_error_message_for( 'validates_greater_than' ); break; case '<=': $valid = strlen( $this->$property ) <= $length; $default_msg = $this->_get_default_error_message_for( 'validates_less_than' ); break; case '>=': $valid = strlen( $this->$property ) >= $length; $default_msg = $this->_get_default_error_message_for( 'validates_greater_than' ); break; } } else { $valid = false; } if ( ! $valid ) { if ( ! $msg ) { $error_msg = sprintf( $default_msg, $this->humanize_string( $property ) ); } else { $error_msg = $msg; } return [ $property => [ $error_msg ] ]; } return []; } /** * @param string $property * @param int|float $comparison * @param string $comparison_operator * @param string $msg * @return array */ public function validates_numericality_of( $property, $comparison = false, $comparison_operator = false, $int_only = false, $msg = false ) { $default_msg = $this->_get_default_error_message_for( __METHOD__ ); if ( ! $this->is_empty( $this->$property ) ) { $invalid = false; if ( is_numeric( $this->$property ) ) { $this->$property += 0; if ( $int_only ) { $invalid = ! is_int( $this->$property ); } if ( ! $invalid ) { switch ( $comparison_operator ) { case '=': case '==': $invalid = ( $this->$property == $comparison ) ? false : true; $default_msg = $this->_get_default_error_message_for( 'validates_equals' ); break; case '!=': case '!': $invalid = ( $this->$property != $comparison ) ? false : true; $default_msg = $this->_get_default_error_message_for( 'validates_equals' ); break; case '<': $invalid = ( $this->$property < $comparison ) ? false : true; $default_msg = $this->_get_default_error_message_for( 'validates_less_than' ); break; case '>': $invalid = ( $this->$property > $comparison ) ? false : true; $default_msg = $this->_get_default_error_message_for( 'validates_greater_than' ); break; case '<=': $invalid = ( $this->$property <= $comparison ) ? false : true; $default_msg = $this->_get_default_error_message_for( 'validates_less_than' ); break; case '>=': $invalid = ( $this->$property >= $comparison ) ? false : true; $default_msg = $this->_get_default_error_message_for( 'validates_greater_than' ); break; } } } else { $invalid = true; } if ( $invalid ) { if ( ! $msg ) { $error_msg = sprintf( $default_msg, $this->humanize_string( $property ) ); } else { $error_msg = $msg; } return [ $property => [ $error_msg ] ]; } } return []; } /** * @param string $property * @param array $values * @param string $msg * @return array */ public function validates_inclusion_of( $property, $values = [], $msg = false ) { if ( ! is_array( $values ) ) { $values = [ $values ]; } if ( ! in_array( $this->$property, $values ) ) { if ( ! $msg ) { $msg = $this->_get_default_error_message_for( __METHOD__ ); $msg = sprintf( $msg, $this->humanize_string( $property ) ); } return [ $property => [ $msg ] ]; } return []; } /** * @param string|array $property * @param string $pattern * @param string $msg * @return array */ public function validates_format_of( $property, $pattern, $msg = false ) { // We do not validate blank values - we rely on "validates_presence_of" for that. if ( ! $this->is_empty( $this->$property ) ) { // If it doesn't match, then it's an error. if ( ! preg_match( $pattern, $this->$property ) ) { // Get default message. if ( ! $msg ) { $msg = $this->_get_default_error_message_for( __METHOD__ ); $msg = sprintf( $msg, $this->humanize_string( $property ) ); } return [ $property => [ $msg ] ]; } } return []; } /** * @param string $property * @param array $exclusions * @param string $msg (optional) * @return array */ public function validates_exclusion_of( $property, $exclusions, $msg = false ) { $invalid = false; foreach ( $exclusions as $exclusion ) { if ( $exclusion == $this->$property ) { $invalid = true; break; } } if ( $invalid ) { if ( ! $msg ) { $msg = $this->_get_default_error_message_for( __METHOD__ ); $msg = sprintf( $msg, $this->humanize_string( $property ) ); } return [ $property => [ $msg ] ]; } return []; } /** * @param string $property * @param string $confirmation * @param string $msg * @return array */ public function validates_confirmation_of( $property, $confirmation, $msg = false ) { if ( $this->$property != $this->$confirmation ) { if ( ! $msg ) { $msg = $this->_get_default_error_message_for( __METHOD__ ); $msg = sprintf( $msg, $this->humanize_string( $property ) ); } return [ $property => [ $msg ] ]; } return []; } /** * @param string $property * @param array $scope * @param string $msg * @return array */ public function validates_uniqueness_of( $property, $scope = [], $msg = false ) { // Get any entities that have the same property. $mapper = $this->get_mapper(); $key = $mapper->get_primary_key_column(); $mapper->select( $key ); $mapper->limit( 1 ); $mapper->where_and( [ "{$property} = %s", $this->$property ] ); if ( ! $this->is_new() ) { $mapper->where_and( [ "{$key} != %s", $this->id() ] ); } foreach ( $scope as $another_property ) { $mapper->where_and( [ "{$another_property} = %s", $another_property ] ); } $result = $mapper->run_query(); // If there's a result, it means that the entity is NOT unique. if ( $result ) { // Get default msg. if ( ! $msg ) { $msg = $this->_get_default_error_message_for( __METHOD__ ); $msg = sprintf( $msg, $this->humanize_string( $property ) ); } return [ $property => [ $msg ] ]; } return []; } /** * @param string $property * @param array $with * @param string $msg * @return array */ public function validates_presence_of( $property, $with = [], $msg = false ) { $missing = []; $invalid = true; // Is a value present? if ( ! $this->is_empty( $this->$property ) ) { $invalid = false; // This property must be present with at least another property. if ( $with ) { if ( ! is_array( $with ) ) { $with = [ $with ]; } foreach ( $with as $other ) { if ( $this->is_empty( $this->$other ) ) { $invalid = true; $missing[] = $other; } } } } // Add error. if ( $invalid ) { if ( ! $msg ) { // If missing isn't empty, it means that we're to use the "with" error message. if ( $missing ) { $missing = implode( ', ', $this->humanize_string( $missing ) ); $msg = sprintf( $this->_get_default_error_message_for( 'validates_presence_with' ), $property, $missing ); } else { // Has no 'with' arguments. Use the default error msg. $msg = sprintf( $this->_get_default_error_message_for( __METHOD__ ), $property ); } } return [ $property => [ $msg ] ]; } return []; } } /** * This class exists to prevent the Validation trait from adding any new attributes to the classes that use it and is * only used by the above Validation trait. */ class ValidationMessages { public static $default_messages = [ 'validates_presence_of' => '%s should be present', 'validates_presence_with' => '%s should be present with %s', 'validates_uniqueness_of' => '%s should be unique', 'validates_confirmation_of' => '%s should match confirmation', 'validates_exclusion_of' => '%s is reserved', 'validates_format_of' => '%s is invalid', 'validates_inclusion_of' => '%s is not included in the list', 'validates_numericality_of' => '%s is not numeric', 'validates_less_than' => '%s is too small', 'validates_greater_than' => '%s is too large', 'validates_equals' => '%s is invalid', ]; public static $default_patterns = [ 'email_address' => '//', ]; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataStorage/Manager.php�����������������������������������������������������������������������������0000644�����������������00000255564�15021223045�0011040 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataStorage; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataTypes\{ Gallery, Image, LegacyThumbnail }; use Imagely\NGG\Display\I18N; use Imagely\NGG\IGW\EventPublisher; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\{ Filesystem, Router, Security }; class Manager { public static $instance = null; protected $gallery_mapper; protected $image_mapper; /** @deprecated */ public $_image_mapper; /** @deprecated */ public $object; protected static $gallery_abspath_cache = []; protected static $image_abspath_cache = []; protected static $image_url_cache = []; public function __construct() { $this->gallery_mapper = GalleryMapper::get_instance(); $this->image_mapper = ImageMapper::get_instance(); /** * @TODO Remove in a later release - this fixes an issue with Imagify at the time of 3.50's release. */ $this->object = $this; $this->_image_mapper = $this->image_mapper; } /** * @return Manager */ static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new Manager(); } return self::$instance; } public function has_method( $name ) { return method_exists( $this, $name ); } /** * @TODO: Remove this 'magic' method so that our code is always understandable without needing deep context * @param string $method * @param array $args * @return mixed * @throws \Exception */ public function __call( $method, $args ) { if ( preg_match( '/^get_(\w+)_(abspath|url|dimensions|html|size_params)$/', $method, $match ) ) { if ( isset( $match[1] ) && isset( $match[2] ) && ! method_exists( $this, $method ) ) { $method = 'get_image_' . $match[2]; $args[] = $match[1]; return $this->$method( $args ); } } return $this->$method( $args ); } /** * Remove after Pro attains level 1 compatibility with the POPE removal */ public function get_wrapped_instance() { return $this; } /** * Remove after Pro attains level 1 compatibility with the POPE removal */ public function add_mixin( $unused = '' ) {} /** * Backs up an image file * * @param int|object $image * @param bool $save * @return bool */ public function backup_image( $image, $save = true ) { $retval = false; $image_path = $this->get_image_abspath( $image ); if ( $image_path && @file_exists( $image_path ) ) { $retval = copy( $image_path, $this->get_backup_abspath( $image ) ); // Store the dimensions of the image. if ( function_exists( 'getimagesize' ) ) { $mapper = ImageMapper::get_instance(); if ( ! is_object( $image ) ) { $image = $mapper->find( $image ); } if ( $image ) { if ( empty( $image->meta_data ) || ! is_array( $image->meta_data ) ) { $image->meta_data = []; } $dimensions = getimagesize( $image_path ); $image->meta_data['backup'] = [ 'filename' => basename( $image_path ), 'width' => $dimensions[0], 'height' => $dimensions[1], 'generated' => microtime(), ]; if ( $save ) { $mapper->save( $image ); } } } } return $retval; } /** * @param string $zipfile * @param string $dest_path * @return bool false on failure */ public function extract_zip( $zipfile, $dest_path ) { wp_mkdir_p( $dest_path ); if ( class_exists( 'ZipArchive', false ) && apply_filters( 'unzip_file_use_ziparchive', true ) ) { $zipObj = new \ZipArchive(); if ( $zipObj->open( $zipfile ) === false ) { return false; } for ( $i = 0; $i < $zipObj->numFiles; $i++ ) { $filename = $zipObj->getNameIndex( $i ); if ( ! $this->is_allowed_image_extension( $filename ) ) { continue; } $zipObj->extractTo( $dest_path, [ $zipObj->getNameIndex( $i ) ] ); } } else { require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; $zipObj = new \PclZip( $zipfile ); $zipContent = $zipObj->listContent(); $indexesToExtract = []; foreach ( $zipContent as $zipItem ) { if ( $zipItem['folder'] ) { continue; } if ( ! $this->is_allowed_image_extension( $zipItem['stored_filename'] ) ) { continue; } $indexesToExtract[] = $zipItem['index']; } if ( ! $zipObj->extractByIndex( implode( ',', $indexesToExtract ), $dest_path ) ) { return false; } } return true; } /** * Gets the id of a gallery, regardless of whether an integer or object was passed as an argument * * @param mixed $gallery_obj_or_id * @return null|int */ public function get_gallery_id( $gallery_obj_or_id ) { $retval = null; $gallery_key = $this->gallery_mapper->get_primary_key_column(); if ( is_object( $gallery_obj_or_id ) ) { if ( isset( $gallery_obj_or_id->$gallery_key ) ) { $retval = $gallery_obj_or_id->$gallery_key; } } elseif ( is_numeric( $gallery_obj_or_id ) ) { $retval = $gallery_obj_or_id; } return $retval; } /** * Empties the gallery cache directory of content * * @param object $gallery */ public function flush_cache( $gallery ) { $fs = Filesystem::get_instance(); $fs->flush_directory( $this->get_cache_abspath( $gallery ) ); } /** * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated * * @param object|int $image Image ID or an image object * @param string $size * @param array $params * @param bool $skip_defaults * @return bool|array */ public function calculate_image_size_dimensions( $image, $size, $params = null, $skip_defaults = false ) { $retval = false; // Get the image entity. if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } // Ensure we have a valid image. if ( $image ) { $params = $this->get_image_size_params( $image, $size, $params, $skip_defaults ); // Get the image filename. $image_path = $this->get_image_abspath( $image, 'full', true ); $clone_path = $this->get_image_abspath( $image, $size ); $retval = $this->calculate_image_clone_dimensions( $image_path, $clone_path, $params ); } return $retval; } /** * Generates a "clone" for an existing image, the clone can be altered using the $params array * * @param string $image_path * @param string $clone_path * @param array $params * @return null|object */ public function generate_image_clone( $image_path, $clone_path, $params ) { $crop = isset( $params['crop'] ) ? $params['crop'] : null; $watermark = isset( $params['watermark'] ) ? $params['watermark'] : null; $reflection = isset( $params['reflection'] ) ? $params['reflection'] : null; $rotation = isset( $params['rotation'] ) ? $params['rotation'] : null; $flip = isset( $params['flip'] ) ? $params['flip'] : ''; $destpath = null; $thumbnail = null; $result = $this->calculate_image_clone_result( $image_path, $clone_path, $params ); // XXX this should maybe be removed and extra settings go into $params? $settings = apply_filters( 'ngg_settings_during_image_generation', Settings::get_instance()->to_array() ); // Ensure we have a valid image. if ( $image_path && @file_exists( $image_path ) && null != $result && ! isset( $result['error'] ) ) { $image_dir = dirname( $image_path ); $clone_path = $result['clone_path']; $clone_dir = $result['clone_directory']; $clone_format = $result['clone_format']; $format_list = $this->get_image_format_list(); // Ensure target directory exists, but only create 1 subdirectory. if ( ! @file_exists( $clone_dir ) ) { if ( strtolower( realpath( $image_dir ) ) != strtolower( realpath( $clone_dir ) ) ) { if ( strtolower( realpath( $image_dir ) ) == strtolower( realpath( dirname( $clone_dir ) ) ) ) { wp_mkdir_p( $clone_dir ); } } } $method = $result['method']; $width = $result['width']; $height = $result['height']; $quality = $result['quality']; if ( null === $quality ) { $quality = 100; } // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText if ( $method == 'wordpress' ) { $original = wp_get_image_editor( $image_path ); $destpath = $clone_path; if ( ! is_wp_error( $original ) ) { $original->resize( $width, $height, $crop ); $original->set_quality( $quality ); $original->save( $clone_path ); } } elseif ( $method == 'nextgen' ) { $destpath = $clone_path; $thumbnail = new LegacyThumbnail( $image_path, true ); if ( ! $thumbnail->error ) { if ( $crop ) { $crop_area = $result['crop_area']; $crop_x = $crop_area['x']; $crop_y = $crop_area['y']; $crop_width = $crop_area['width']; $crop_height = $crop_area['height']; $thumbnail->crop( $crop_x, $crop_y, $crop_width, $crop_height ); } $thumbnail->resize( $width, $height ); } else { $thumbnail = null; } } // We successfully generated the thumbnail. if ( is_string( $destpath ) && ( @file_exists( $destpath ) || $thumbnail != null ) ) { if ( $clone_format != null ) { if ( isset( $format_list[ $clone_format ] ) ) { $clone_format_extension = $format_list[ $clone_format ]; $clone_format_extension_str = null; if ( $clone_format_extension != null ) { $clone_format_extension_str = '.' . $clone_format_extension; } $destpath_info = I18N::mb_pathinfo( $destpath ); $destpath_extension = $destpath_info['extension']; if ( strtolower( $destpath_extension ) != strtolower( $clone_format_extension ) ) { $destpath_dir = $destpath_info['dirname']; $destpath_basename = $destpath_info['filename']; $destpath_new = $destpath_dir . DIRECTORY_SEPARATOR . $destpath_basename . $clone_format_extension_str; if ( ( @file_exists( $destpath ) && rename( $destpath, $destpath_new ) ) || $thumbnail != null ) { $destpath = $destpath_new; } } } } if ( is_null( $thumbnail ) ) { $thumbnail = new LegacyThumbnail( $destpath, true ); if ( $thumbnail->error ) { $thumbnail = null; return null; } } else { $thumbnail->fileName = $destpath; } // This is quite odd, when watermark equals int(0) it seems all statements below ($watermark == 'image') and ($watermark == 'text') both evaluate as true // so we set it at null if it evaluates to any null-like value. if ( null === $watermark ) { $watermark = null; } if ( 1 == $watermark || true === $watermark ) { $watermark_setting_keys = [ 'wmFont', 'wmType', 'wmPos', 'wmXpos', 'wmYpos', 'wmPath', 'wmText', 'wmOpaque', 'wmFont', 'wmSize', 'wmColor', ]; foreach ( $watermark_setting_keys as $watermark_key ) { if ( ! isset( $params[ $watermark_key ] ) ) { $params[ $watermark_key ] = $settings[ $watermark_key ]; } } if ( in_array( strval( $params['wmType'] ), [ 'image', 'text' ], true ) ) { $watermark = $params['wmType']; } else { $watermark = 'text'; } } $watermark = strval( $watermark ); if ( $watermark == 'image' ) { $thumbnail->watermarkImgPath = $params['wmPath']; $thumbnail->watermarkImage( $params['wmPos'], $params['wmXpos'], $params['wmYpos'] ); } elseif ( $watermark == 'text' ) { $thumbnail->watermarkText = $params['wmText']; $thumbnail->watermarkCreateText( $params['wmColor'], $params['wmFont'], $params['wmSize'], $params['wmOpaque'] ); $thumbnail->watermarkImage( $params['wmPos'], $params['wmXpos'], $params['wmYpos'] ); } if ( $rotation && in_array( abs( $rotation ), [ 90, 180, 270 ], true ) ) { $thumbnail->rotateImageAngle( $rotation ); } $flip = strtolower( $flip ); if ( $flip && in_array( $flip, [ 'h', 'v', 'hv' ], true ) ) { $flip_h = in_array( $flip, [ 'h', 'hv' ], true ); $flip_v = in_array( $flip, [ 'v', 'hv' ], true ); $thumbnail->flipImage( $flip_h, $flip_v ); } if ( $reflection ) { $thumbnail->createReflection( 40, 40, 50, false, '#a4a4a4' ); } // Force format. if ( $clone_format != null && isset( $format_list[ $clone_format ] ) ) { $thumbnail->format = strtoupper( $format_list[ $clone_format ] ); } $thumbnail = apply_filters( 'ngg_before_save_thumbnail', $thumbnail ); // Always retrieve metadata from the backup when possible. $backup_path = $image_path . '_backup'; $exif_abspath = @file_exists( $backup_path ) ? $backup_path : $image_path; $exif_iptc = EXIFWriter::read_metadata( $exif_abspath ); $thumbnail->save( $destpath, $quality ); @EXIFWriter::write_metadata( $destpath, $exif_iptc ); } } return $thumbnail; } /** * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated * * @param string $image_path * @param string $clone_path * @param array $params * @return null|array */ public function calculate_image_clone_dimensions( $image_path, $clone_path, $params ) { $retval = null; $result = $this->calculate_image_clone_result( $image_path, $clone_path, $params ); if ( $result != null ) { $retval = [ 'width' => $result['width'], 'height' => $result['height'], 'real_width' => $result['real_width'], 'real_height' => $result['real_height'], ]; } return $retval; } /** * Returns an array of properties of a resulting clone image if and when generated * * @param string $image_path * @param string $clone_path * @param array $params * @return null|array */ public function calculate_image_clone_result( $image_path, $clone_path, $params ) { $width = isset( $params['width'] ) ? $params['width'] : null; $height = isset( $params['height'] ) ? $params['height'] : null; $quality = isset( $params['quality'] ) ? $params['quality'] : null; $type = isset( $params['type'] ) ? $params['type'] : null; $crop = isset( $params['crop'] ) ? $params['crop'] : null; $watermark = isset( $params['watermark'] ) ? $params['watermark'] : null; $rotation = isset( $params['rotation'] ) ? $params['rotation'] : null; $reflection = isset( $params['reflection'] ) ? $params['reflection'] : null; $crop_frame = isset( $params['crop_frame'] ) ? $params['crop_frame'] : null; $result = null; // Ensure we have a valid image. if ( $image_path && @file_exists( $image_path ) ) { // Ensure target directory exists, but only create 1 subdirectory. $image_dir = dirname( $image_path ); $clone_dir = dirname( $clone_path ); $image_extension = I18N::mb_pathinfo( $image_path, PATHINFO_EXTENSION ); $image_extension_str = null; $clone_extension = I18N::mb_pathinfo( $clone_path, PATHINFO_EXTENSION ); $clone_extension_str = null; if ( $image_extension != null ) { $image_extension_str = '.' . $image_extension; } if ( $clone_extension != null ) { $clone_extension_str = '.' . $clone_extension; } $image_basename = I18N::mb_basename( $image_path ); $clone_basename = I18N::mb_basename( $clone_path ); // We use a default suffix as passing in null as the suffix will make WordPress use a default. $clone_suffix = null; $format_list = $this->get_image_format_list(); $clone_format = null; // format is determined below and based on $type otherwise left to null. // suffix is only used to reconstruct paths for image_resize function. if ( strpos( $clone_basename, $image_basename ) === 0 ) { $clone_suffix = substr( $clone_basename, strlen( $image_basename ) ); } if ( $clone_suffix != null && $clone_suffix[0] == '-' ) { // WordPress adds '-' on its own. $clone_suffix = substr( $clone_suffix, 1 ); } // Get original image dimensions. $dimensions = getimagesize( $image_path ); if ( $width == null && $height == null ) { if ( $dimensions != null ) { if ( $width == null ) { $width = $dimensions[0]; } if ( $height == null ) { $height = $dimensions[1]; } } else { // XXX Don't think there's any other option here but to fail miserably...use some hard-coded defaults maybe? return null; } } if ( $dimensions != null ) { $dimensions_ratio = $dimensions[0] / $dimensions[1]; if ( $width == null ) { $width = (int) round( $height * $dimensions_ratio ); if ( $width == ( $dimensions[0] - 1 ) ) { $width = $dimensions[0]; } } elseif ( $height == null ) { $height = (int) round( $width / $dimensions_ratio ); if ( $height == ( $dimensions[1] - 1 ) ) { $height = $dimensions[1]; } } if ( $width > $dimensions[0] ) { $width = $dimensions[0]; } if ( $height > $dimensions[1] ) { $height = $dimensions[1]; } $image_format = $dimensions[2]; if ( $type != null ) { if ( is_string( $type ) ) { $type = strtolower( $type ); // Indexes in the $format_list array correspond to IMAGETYPE_XXX values appropriately. if ( ( $index = array_search( $type, $format_list ) ) !== false ) { $type = $index; if ( $type != $image_format ) { // Note: this only changes the FORMAT of the image but not the extension. $clone_format = $type; } } } } } if ( $width == null || $height == null ) { // Something went wrong... return null; } // We now need to estimate the 'quality' or level of compression applied to the original JPEG: *IF* the // original image has a quality lower than the $quality parameter we will end up generating a new image // that is MUCH larger than the original. 'Quality' as an EXIF or IPTC property is quite unreliable // and not all software honors or treats it the same way. This calculation is simple: just compare the size // that our image could become to what it currently is. '3' is important here as JPEG uses 3 bytes per pixel. // // First we attempt to use ImageMagick if we can; it has a more robust method of calculation. if ( ! empty( $dimensions['mime'] ) && $dimensions['mime'] == 'image/jpeg' ) { $possible_quality = null; $try_image_magick = true; if ( ( defined( 'NGG_DISABLE_IMAGICK' ) && NGG_DISABLE_IMAGICK ) || ( function_exists( 'is_wpe' ) && ( $dimensions[0] >= 8000 || $dimensions[1] >= 8000 ) ) ) { $try_image_magick = false; } if ( $try_image_magick && extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) ) { $img = new \Imagick( $image_path ); if ( method_exists( $img, 'getImageCompressionQuality' ) ) { $possible_quality = $img->getImageCompressionQuality(); } } // ImageMagick wasn't available or quality is zero so we guess it from the dimensions and filesize. if ( null === $possible_quality || 0 === $possible_quality ) { $filesize = filesize( $image_path ); $possible_quality = ( 101 - ( ( $width * $height ) * 3 ) / $filesize ); } if ( $possible_quality !== null && $possible_quality < $quality ) { $quality = $possible_quality; } } $result['clone_path'] = $clone_path; $result['clone_directory'] = $clone_dir; $result['clone_suffix'] = $clone_suffix; $result['clone_format'] = $clone_format; $result['base_width'] = $dimensions[0]; $result['base_height'] = $dimensions[1]; // image_resize() has limitations: // - no easy crop frame support // - fails if the dimensions are unchanged // - doesn't support filename prefix, only suffix so names like thumbs_original_name.jpg for $clone_path are not supported // also suffix cannot be null as that will make WordPress use a default suffix...we could use an object that returns empty string from __toString() but for now just fallback to ngg generator. if ( false ) { // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText $result['method'] = 'wordpress'; $new_dims = image_resize_dimensions( $dimensions[0], $dimensions[1], $width, $height, $crop ); if ( $new_dims ) { list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $new_dims; $width = $dst_w; $height = $dst_h; } else { $result['error'] = new \WP_Error( 'error_getting_dimensions', __( 'Could not calculate resized image dimensions', 'nggallery' ) ); } } else { $result['method'] = 'nextgen'; $original_width = $dimensions[0]; $original_height = $dimensions[1]; $aspect_ratio = $width / $height; $orig_ratio_x = $original_width / $width; $orig_ratio_y = $original_height / $height; if ( $crop ) { $algo = 'shrink'; // either 'adapt' or 'shrink'. if ( $crop_frame != null ) { $crop_x = (int) round( $crop_frame['x'] ); $crop_y = (int) round( $crop_frame['y'] ); $crop_width = (int) round( $crop_frame['width'] ); $crop_height = (int) round( $crop_frame['height'] ); $crop_final_width = (int) round( $crop_frame['final_width'] ); $crop_final_height = (int) round( $crop_frame['final_height'] ); $crop_width_orig = $crop_width; $crop_height_orig = $crop_height; $crop_factor_x = $crop_width / $crop_final_width; $crop_factor_y = $crop_height / $crop_final_height; $crop_ratio_x = $crop_width / $width; $crop_ratio_y = $crop_height / $height; if ( $algo == 'adapt' ) { // XXX not sure about this...don't use for now // $crop_width = (int) round($width * $crop_factor_x); // $crop_height = (int) round($height * $crop_factor_y);. } elseif ( $algo == 'shrink' ) { if ( $crop_ratio_x < $crop_ratio_y ) { $crop_width = max( $crop_width, $width ); $crop_height = (int) round( $crop_width / $aspect_ratio ); } else { $crop_height = max( $crop_height, $height ); $crop_width = (int) round( $crop_height * $aspect_ratio ); } if ( $crop_width == ( $crop_width_orig - 1 ) ) { $crop_width = $crop_width_orig; } if ( $crop_height == ( $crop_height_orig - 1 ) ) { $crop_height = $crop_height_orig; } } $crop_diff_x = (int) round( ( $crop_width_orig - $crop_width ) / 2 ); $crop_diff_y = (int) round( ( $crop_height_orig - $crop_height ) / 2 ); $crop_x += $crop_diff_x; $crop_y += $crop_diff_y; $crop_max_x = ( $crop_x + $crop_width ); $crop_max_y = ( $crop_y + $crop_height ); // Check if we're overflowing borders. // if ( $crop_x < 0 ) { $crop_x = 0; } elseif ( $crop_max_x > $original_width ) { $crop_x -= ( $crop_max_x - $original_width ); } if ( $crop_y < 0 ) { $crop_y = 0; } elseif ( $crop_max_y > $original_height ) { $crop_y -= ( $crop_max_y - $original_height ); } } else { if ( $orig_ratio_x < $orig_ratio_y ) { $crop_width = $original_width; $crop_height = (int) round( $height * $orig_ratio_x ); } else { $crop_height = $original_height; $crop_width = (int) round( $width * $orig_ratio_y ); } if ( $crop_width == ( $width - 1 ) ) { $crop_width = $width; } if ( $crop_height == ( $height - 1 ) ) { $crop_height = $height; } $crop_x = (int) round( ( $original_width - $crop_width ) / 2 ); $crop_y = (int) round( ( $original_height - $crop_height ) / 2 ); } $result['crop_area'] = [ 'x' => $crop_x, 'y' => $crop_y, 'width' => $crop_width, 'height' => $crop_height, ]; } else { // Just constraint dimensions to ensure there's no stretching or deformations. list($width, $height) = wp_constrain_dimensions( $original_width, $original_height, $width, $height ); } } $result['width'] = $width; $result['height'] = $height; $result['quality'] = $quality; $real_width = $width; $real_height = $height; if ( $rotation && in_array( abs( $rotation ), [ 90, 270 ], true ) ) { $real_width = $height; $real_height = $width; } if ( $reflection ) { // default for nextgen was 40%, this is used in generate_image_clone as well. $reflection_amount = 40; // Note, round() would probably be best here but using the same code that LegacyThumbnail uses for compatibility. $reflection_height = intval( $real_height * ( $reflection_amount / 100 ) ); $real_height = $real_height + $reflection_height; } $result['real_width'] = $real_width; $result['real_height'] = $real_height; } return $result; } public function generate_resized_image( $image, $save = true ) { $image_abspath = $this->get_image_abspath( $image, 'full' ); $generated = $this->generate_image_clone( $image_abspath, $image_abspath, $this->get_image_size_params( $image, 'full' ) ); if ( $generated && $save ) { $this->update_image_dimension_metadata( $image, $image_abspath ); } if ( $generated ) { $generated->destruct(); } } public function update_image_dimension_metadata( $image, $image_abspath ) { // Ensure that fullsize dimensions are added to metadata array. $dimensions = getimagesize( $image_abspath ); $full_meta = [ 'width' => $dimensions[0], 'height' => $dimensions[1], 'md5' => $this->get_image_checksum( $image, 'full' ), ]; if ( ! isset( $image->meta_data ) or ( is_string( $image->meta_data ) && strlen( $image->meta_data ) == 0 ) or is_bool( $image->meta_data ) ) { $image->meta_data = []; } $image->meta_data = array_merge( $image->meta_data, $full_meta ); $image->meta_data['full'] = $full_meta; // Don't forget to append the 'full' entry in meta_data in the db. $this->image_mapper->save( $image ); } /** * Most major browsers do not honor the Orientation meta found in EXIF. To prevent display issues we inspect * the EXIF data and rotate the image so that the EXIF field is not necessary to display the image correctly. * Note: generate_image_clone() will handle the removal of the Orientation tag inside the image EXIF. * Note: This only handles single-dimension rotation; at the time this method was written there are no known * camera manufacturers that both rotate and flip images. * * @param $image * @param bool $save */ public function correct_exif_rotation( $image, $save = true ) { $image_abspath = $this->get_image_abspath( $image, 'full' ); if ( ! EXIFWriter::is_jpeg_file( $image_abspath ) ) { return; } // This method is necessary. if ( ! function_exists( 'exif_read_data' ) ) { return; } // We only need to continue if the Orientation tag is set. $exif = @exif_read_data( $image_abspath, 'exif' ); if ( empty( $exif['Orientation'] ) || $exif['Orientation'] == 1 ) { return; } $degree = 0; if ( $exif['Orientation'] == 3 ) { $degree = 180; } if ( $exif['Orientation'] == 6 ) { $degree = 90; } if ( $exif['Orientation'] == 8 ) { $degree = 270; } $parameters = [ 'rotation' => $degree ]; $generated = $this->generate_image_clone( $image_abspath, $image_abspath, $this->get_image_size_params( $image, 'full', $parameters ), $parameters ); if ( $generated && $save ) { $this->update_image_dimension_metadata( $image, $image_abspath ); } if ( $generated ) { $generated->destruct(); } } /** * Flushes the cache we use for path/url calculation for galleries */ public function flush_gallery_path_cache( $gallery ) { $gallery = is_numeric( $gallery ) ? $gallery : $gallery->gid; unset( self::$gallery_abspath_cache[ $gallery ] ); } /** * Returns the absolute path to the cache directory of a gallery. * * Without the gallery parameter the legacy (pre 2.0) shared directory is returned. * * @param int|object|false|Gallery $gallery (optional) * @return string Absolute path to cache directory */ public function get_cache_abspath( $gallery = false ) { return path_join( $this->get_gallery_abspath( $gallery ), 'cache' ); } /** * Gets the absolute path where the full-sized image is stored * * @param int|object $image * @return null|string */ public function get_full_abspath( $image ) { return $this->get_image_abspath( $image, 'full' ); } /** * Alias to get_image_dimensions() * * @param int|object $image * @return array */ public function get_full_dimensions( $image ) { return $this->get_image_dimensions( $image, 'full' ); } /** * Alias for get_original_url() * * @param Image $image * @return string */ public function get_full_url( $image ) { return $this->get_image_url( $image, 'full' ); } public function get_gallery_root() { return wp_normalize_path( Filesystem::get_instance()->get_document_root( 'galleries' ) ); } public function get_computed_gallery_abspath( $gallery ) { $retval = null; $gallery_root = $this->get_gallery_root(); // Get the gallery entity from the database. if ( $gallery ) { if ( is_numeric( $gallery ) ) { $gallery = $this->gallery_mapper->find( $gallery ); } } // It just doesn't exist. if ( ! $gallery ) { return $retval; } // We we have a gallery, determine it's path. if ( $gallery ) { if ( isset( $gallery->path ) ) { $retval = $gallery->path; } elseif ( isset( $gallery->slug ) ) { $basepath = wp_normalize_path( Settings::get_instance()->gallerypath ); $retval = path_join( $basepath, $this->sanitize_directory_name( sanitize_title( $gallery->slug ) ) ); } // Normalize the gallery path. If the gallery path starts with /wp-content, and // NGG_GALLERY_ROOT_TYPE is set to 'content', then we need to strip out the /wp-content // from the start of the gallery path. if ( NGG_GALLERY_ROOT_TYPE === 'content' ) { $retval = preg_replace( '#^/?wp-content#', '', $retval ); } // Ensure that the path is absolute. if ( strpos( $retval, $gallery_root ) !== 0 ) { // path_join() behaves funny - if the second argument starts with a slash, // it won't join the two paths together. $retval = preg_replace( '#^/#', '', $retval ); $retval = path_join( $gallery_root, $retval ); } $retval = wp_normalize_path( $retval ); } return $retval; } /** * Get the abspath to the gallery folder for the given gallery * The gallery may or may not already be persisted * * @param int|object|Gallery $gallery * * @return string */ public function get_gallery_abspath( $gallery ) { $gallery_id = is_numeric( $gallery ) ? $gallery : ( is_object( $gallery ) && isset( $gallery->gid ) ? $gallery->gid : null ); if ( ! $gallery_id || ! isset( self::$gallery_abspath_cache[ $gallery_id ] ) ) { self::$gallery_abspath_cache[ $gallery_id ] = $this->get_computed_gallery_abspath( $gallery ); } return self::$gallery_abspath_cache[ $gallery_id ]; } public function get_gallery_relpath( $gallery ) { // Special hack for home.pl: their document root is just '/'. $root = $this->get_gallery_root(); if ( $root === '/' ) { return $this->get_gallery_abspath( $gallery ); } return str_replace( $this->get_gallery_root(), '', $this->get_gallery_abspath( $gallery ) ); } /** * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image. * * @param int|object $image * @param string $size (optional) Default = full * @return string */ public function get_computed_image_abspath( $image, $size = 'full', $check_existance = false ) { $retval = null; // If we have the id, get the actual image entity. if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } // Ensure we have the image entity - user could have passed in an incorrect id. if ( is_object( $image ) ) { if ( ( $gallery_path = $this->get_gallery_abspath( $image->galleryid ) ) ) { $folder = $prefix = $size; switch ( $size ) { // Images are stored in the associated gallery folder. case 'full': $retval = \path_join( $gallery_path, $image->filename ); break; case 'backup': $retval = \path_join( $gallery_path, $image->filename . '_backup' ); if ( ! @file_exists( $retval ) ) { $retval = \path_join( $gallery_path, $image->filename ); } break; case 'thumbnail': $size = 'thumbnail'; $folder = 'thumbs'; $prefix = 'thumbs'; // deliberately no break here. default: // NGG 2.0 stores relative filenames in the meta data of // an image. It does this because it uses filenames // that follow conventional WordPress naming scheme. $image_path = null; $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); if ( isset( $image->meta_data ) && isset( $image->meta_data[ $size ] ) && isset( $image->meta_data[ $size ]['filename'] ) ) { if ( $dynthumbs && $dynthumbs->is_size_dynamic( $size ) ) { $image_path = \path_join( $this->get_cache_abspath( $image->galleryid ), $image->meta_data[ $size ]['filename'] ); } else { $image_path = \path_join( $gallery_path, $folder ); $image_path = \path_join( $image_path, $image->meta_data[ $size ]['filename'] ); } } // Filename not found in meta, but is dynamic. elseif ( $dynthumbs && $dynthumbs->is_size_dynamic( $size ) ) { $params = $dynthumbs->get_params_from_name( $size, true ); $image_path = \path_join( $this->get_cache_abspath( $image->galleryid ), $dynthumbs->get_image_name( $image, $params ) ); // Filename is not found in meta, nor dynamic. } else { $settings = Settings::get_instance(); // This next bit is annoying but necessary for legacy reasons. NextGEN until 3.19 stored thumbnails // with a filename of "thumbs_(whatever.jpg)" which Google indexes as "thumbswhatever.jpg" which is // not good for SEO. From 3.19 on the default setting is "thumbs-" but we must account for legacy // sites. $image_path = \path_join( $gallery_path, $folder ); $new_thumb_path = \path_join( $image_path, "{$prefix}-{$image->filename}" ); $old_thumb_path = \path_join( $image_path, "{$prefix}_{$image->filename}" ); if ( $settings->get( 'dynamic_image_filename_separator_use_dash', false ) ) { // Check for thumbs- first. if ( file_exists( $new_thumb_path ) ) { $image_path = $new_thumb_path; } elseif ( file_exists( $old_thumb_path ) ) { // Check for thumbs_ as a fallback. $image_path = $old_thumb_path; } else { // The thumbnail file does not exist, default to thumbs-. $image_path = $new_thumb_path; } } else { // Reversed: the option is disabled so check for thumbs_. if ( file_exists( $old_thumb_path ) ) { $image_path = $old_thumb_path; } elseif ( file_exists( $new_thumb_path ) ) { // In case the user has switched back and forth, check for thumbs-. $image_path = $new_thumb_path; } else { // Default to thumbs_ per the site setting. $image_path = $old_thumb_path; } } } $retval = $image_path; break; } } } if ( $retval && $check_existance && ! @file_exists( $retval ) ) { $retval = null; } return $retval; } public function get_image_checksum( $image, $size = 'full' ) { $retval = null; if ( ( $image_abspath = $this->get_image_abspath( $image, $size, true ) ) ) { $retval = md5_file( $image_abspath ); } return $retval; } /** * Gets the dimensions for a particular-sized image * * @param int|object $image * @param string $size * @return null|array */ public function get_image_dimensions( $image, $size = 'full' ) { $retval = null; // If an image id was provided, get the entity. if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } // Ensure we have a valid image. if ( $image ) { $size = $this->normalize_image_size_name( $size ); if ( ! $size ) { $size = 'full'; } // Image dimensions are stored in the $image->meta_data // property for all implementations. if ( isset( $image->meta_data ) && isset( $image->meta_data[ $size ] ) ) { $retval = $image->meta_data[ $size ]; } // Didn't exist for meta data. We'll have to compute // dimensions in the meta_data after computing? This is most likely // due to a dynamic image size being calculated for the first time. else { $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); $abspath = $this->get_image_abspath( $image, $size, true ); if ( $abspath ) { $dims = @getimagesize( $abspath ); if ( $dims ) { $retval['width'] = $dims[0]; $retval['height'] = $dims[1]; } } elseif ( $size == 'backup' ) { $retval = $this->get_image_dimensions( $image, 'full' ); } if ( ! $retval && $dynthumbs && $dynthumbs->is_size_dynamic( $size ) ) { $new_dims = $this->calculate_image_size_dimensions( $image, $size ); // Prevent a possible PHP warning if the sizes weren't calculated. if ( isset( $new_dims['real_width'] ) && isset( $new_dims['real_height'] ) ) { $retval = [ 'width' => $new_dims['real_width'], 'height' => $new_dims['real_height'], ]; } } } } return $retval; } public function get_image_format_list() { $format_list = [ IMAGETYPE_GIF => 'gif', IMAGETYPE_JPEG => 'jpg', IMAGETYPE_PNG => 'png', IMAGETYPE_WEBP => 'webp', ]; return $format_list; } /** * Gets the HTML for an image * * @param int|object $image * @param string $size * @param array $attributes (optional) * @return string */ public function get_image_html( $image, $size = 'full', $attributes = [] ) { $retval = ''; if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } if ( $image ) { // Set alt text if not already specified. if ( ! isset( $attributes['alttext'] ) ) { $attributes['alt'] = esc_attr( $image->alttext ); } // Set the title if not already set. if ( ! isset( $attributes['title'] ) ) { $attributes['title'] = esc_attr( $image->alttext ); } // Set the dimensions if not set already. if ( ! isset( $attributes['width'] ) or ! isset( $attributes['height'] ) ) { $dimensions = $this->get_image_dimensions( $image, $size ); if ( ! isset( $attributes['width'] ) ) { $attributes['width'] = $dimensions['width']; } if ( ! isset( $attributes['height'] ) ) { $attributes['height'] = $dimensions['height']; } } // Set the url if not already specified. if ( ! isset( $attributes['src'] ) ) { $attributes['src'] = $this->get_image_url( $image, $size ); } // Format attributes. $attribs = []; foreach ( $attributes as $attrib => $value ) { $attribs[] = "{$attrib}=\"{$value}\""; } $attribs = implode( ' ', $attribs ); // Return HTML string. $retval = "<img {$attribs} />"; } return $retval; } public function get_computed_image_url( $image, $size = 'full' ) { $retval = null; $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); // Get the image abspath. $image_abspath = $this->get_image_abspath( $image, $size ); if ( $dynthumbs->is_size_dynamic( $size ) && ! file_exists( $image_abspath ) ) { if ( defined( 'NGG_DISABLE_DYNAMIC_IMG_URLS' ) && constant( 'NGG_DISABLE_DYNAMIC_IMG_URLS' ) ) { $params = [ 'watermark' => false, 'reflection' => false, 'crop' => true, ]; $result = $this->generate_image_size( $image, $size, $params ); if ( $result ) { $image_abspath = $this->get_image_abspath( $image, $size ); } } else { return null; } } // Assuming we have an abspath, we can translate that to a url. if ( $image_abspath ) { // Replace the gallery root with the proper url segment. $gallery_root = preg_quote( $this->get_gallery_root(), '#' ); $image_uri = preg_replace( "#^{$gallery_root}#", '', $image_abspath ); // Url encode each uri segment. $segments = explode( '/', $image_uri ); $segments = array_map( 'rawurlencode', $segments ); $image_uri = preg_replace( '#^/#', '', implode( '/', $segments ) ); // Join gallery root and image uri. $gallery_root = trailingslashit( NGG_GALLERY_ROOT_TYPE == 'site' ? site_url() : WP_CONTENT_URL ); $gallery_root = is_ssl() ? str_replace( 'http:', 'https:', $gallery_root ) : $gallery_root; $retval = $gallery_root . $image_uri; } return $retval; } public function normalize_image_size_name( $size = 'full' ) { switch ( $size ) { case 'full': case 'image': case 'orig': case 'original': case 'resized': $size = 'full'; break; case 'thumb': case 'thumbnail': case 'thumbnails': case 'thumbs': $size = 'thumbnail'; break; } return $size; } /** * Returns the named sizes available for images * * @return array */ public function get_image_sizes( $image = false ) { $retval = [ 'full', 'thumbnail' ]; if ( is_numeric( $image ) ) { $image = ImageMapper::get_instance()->find( $image ); } if ( $image ) { if ( $image->meta_data ) { $meta_data = is_object( $image->meta_data ) ? get_object_vars( $image->meta_data ) : $image->meta_data; foreach ( $meta_data as $key => $value ) { if ( is_array( $value ) && isset( $value['width'] ) && ! in_array( $key, $retval ) ) { $retval[] = $key; } } } } return $retval; } public function get_image_size_params( $image, $size, $params = [], $skip_defaults = false ) { // Get the image entity. if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); if ( $dynthumbs && $dynthumbs->is_size_dynamic( $size ) ) { $named_params = $dynthumbs->get_params_from_name( $size, true ); if ( ! $params ) { $params = []; } $params = array_merge( $params, $named_params ); } $params = apply_filters( 'ngg_get_image_size_params', $params, $size, $image ); // Ensure we have a valid image. if ( $image ) { $settings = Settings::get_instance(); if ( ! $skip_defaults ) { // Get default settings. if ( $size == 'full' ) { if ( ! isset( $params['quality'] ) ) { $params['quality'] = $settings->get( 'imgQuality' ); } } else { if ( ! isset( $params['crop'] ) ) { $params['crop'] = $settings->get( 'thumbfix' ); } if ( ! isset( $params['quality'] ) ) { $params['quality'] = $settings->get( 'thumbquality' ); } } } // width and height when omitted make generate_image_clone create a clone with original size, so try find defaults regardless of $skip_defaults. if ( ! isset( $params['width'] ) || ! isset( $params['height'] ) ) { // First test if this is a "known" image size, i.e. if we store these sizes somewhere when users re-generate these sizes from the UI...this is required to be compatible with legacy. // try the 2 default built-in sizes, first thumbnail... if ( $size == 'thumbnail' ) { if ( ! isset( $params['width'] ) ) { $params['width'] = $settings->thumbwidth; } if ( ! isset( $params['height'] ) ) { $params['height'] = $settings->thumbheight; } } // ...and then full, which is the size specified in the global resize options. elseif ( $size == 'full' ) { if ( ! isset( $params['width'] ) ) { if ( $settings->imgAutoResize ) { $params['width'] = $settings->imgWidth; } } if ( ! isset( $params['height'] ) ) { if ( $settings->imgAutoResize ) { $params['height'] = $settings->imgHeight; } } } // Only re-use old sizes as last resort. elseif ( isset( $image->meta_data ) && isset( $image->meta_data[ $size ] ) ) { $dimensions = $image->meta_data[ $size ]; if ( ! isset( $params['width'] ) ) { $params['width'] = $dimensions['width']; } if ( ! isset( $params['height'] ) ) { $params['height'] = $dimensions['height']; } } } if ( ! isset( $params['crop_frame'] ) ) { $crop_frame_size_name = 'thumbnail'; if ( isset( $image->meta_data[ $size ]['crop_frame'] ) ) { $crop_frame_size_name = $size; } if ( isset( $image->meta_data[ $crop_frame_size_name ]['crop_frame'] ) ) { $params['crop_frame'] = $image->meta_data[ $crop_frame_size_name ]['crop_frame']; if ( ! isset( $params['crop_frame']['final_width'] ) ) { $params['crop_frame']['final_width'] = $image->meta_data[ $crop_frame_size_name ]['width']; } if ( ! isset( $params['crop_frame']['final_height'] ) ) { $params['crop_frame']['final_height'] = $image->meta_data[ $crop_frame_size_name ]['height']; } } } else { if ( ! isset( $params['crop_frame']['final_width'] ) ) { $params['crop_frame']['final_width'] = $params['width']; } if ( ! isset( $params['crop_frame']['final_height'] ) ) { $params['crop_frame']['final_height'] = $params['height']; } } } return $params; } /** * Alias to get_image_dimensions() * * @param int|object $image * @return array */ public function get_original_dimensions( $image ) { return $this->get_image_dimensions( $image, 'full' ); } /** * @param object|bool $gallery (optional) * @return string */ public function get_upload_abspath( $gallery = false ) { // Base upload path. $retval = Settings::get_instance()->get( 'gallerypath' ); $fs = Filesystem::get_instance(); // Append the slug if a gallery has been specified. if ( $gallery ) { $retval = $this->get_gallery_abspath( $gallery ); } // We need to make this an absolute path. if ( ! empty( $retval ) && strpos( $retval, $fs->get_document_root( 'gallery' ) ) !== 0 ) { $retval = rtrim( $fs->join_paths( $fs->get_document_root( 'gallery' ), $retval ), '/\\' ); } // Convert slashes. return wp_normalize_path( $retval ); } /** * Gets the upload path, optionally for a particular gallery * * @param int|Gallery|object|false $gallery (optional) * * @return string */ public function get_upload_relpath( $gallery = false ) { $fs = Filesystem::get_instance(); $retval = str_replace( $fs->get_document_root( 'gallery' ), '', $this->get_upload_abspath( $gallery ) ); return '/' . wp_normalize_path( ltrim( $retval, '/' ) ); } public function delete_gallery_directory( $abspath ) { // Remove all image files and purge all empty directories left over. $iterator = new \DirectoryIterator( $abspath ); // Only delete image files! Other files may be stored incorrectly but it's not our place to delete them. $removable_extensions = apply_filters( 'ngg_allowed_file_types', NGG_DEFAULT_ALLOWED_FILE_TYPES ); foreach ( $removable_extensions as $extension ) { $removable_extensions[] = $extension . '_backup'; } foreach ( $iterator as $file ) { if ( in_array( $file->getBasename(), [ '.', '..' ] ) ) { continue; } elseif ( $file->isFile() || $file->isLink() ) { $extension = strtolower( pathinfo( $file->getPathname(), PATHINFO_EXTENSION ) ); if ( in_array( $extension, $removable_extensions, true ) ) { @unlink( $file->getPathname() ); } } elseif ( $file->isDir() ) { $this->delete_gallery_directory( $file->getPathname() ); } } // DO NOT remove directories that still have files in them. Note: '.' and '..' are included with getSize(). $empty = true; foreach ( $iterator as $file ) { if ( in_array( $file->getBasename(), [ '.', '..' ] ) ) { continue; } $empty = false; } if ( $empty ) { @rmdir( $iterator->getPath() ); } } /** * @param Image[] $images * @param Gallery|int $dst_gallery * * @return int[] */ public function copy_images( $images, $dst_gallery ) { $retval = []; // Ensure that the image ids we have are valid. $image_mapper = ImageMapper::get_instance(); foreach ( $images as $image ) { if ( is_numeric( $image ) ) { $image = $image_mapper->find( $image ); } $image_abspath = $this->get_image_abspath( $image, 'backup' ) ?: $this->get_image_abspath( $image ); if ( $image_abspath ) { // Import the image; this will copy the main file. $new_image_id = $this->import_image_file( $dst_gallery, $image_abspath, $image->filename ); if ( $new_image_id ) { // Copy the properties of the old image. $new_image = $image_mapper->find( $new_image_id ); foreach ( get_object_vars( $image ) as $key => $value ) { if ( in_array( $key, [ 'pid', 'galleryid', 'meta_data', 'filename', 'sortorder', 'extras_post_id' ] ) ) { continue; } $new_image->$key = $value; } $image_mapper->save( $new_image ); // Copy tags. $tags = wp_get_object_terms( $image->pid, 'ngg_tag', 'fields=ids' ); $tags = array_map( 'intval', $tags ); wp_set_object_terms( $new_image_id, $tags, 'ngg_tag', true ); // Copy all of the generated versions (resized versions, watermarks, etc). foreach ( $this->get_image_sizes( $image ) as $named_size ) { if ( in_array( $named_size, [ 'full', 'thumbnail' ] ) ) { continue; } $old_abspath = $this->get_image_abspath( $image, $named_size ); $new_abspath = $this->get_image_abspath( $new_image, $named_size ); if ( is_array( @stat( $old_abspath ) ) ) { $new_dir = dirname( $new_abspath ); // Ensure the target directory exists. if ( @stat( $new_dir ) === false ) { wp_mkdir_p( $new_dir ); } @copy( $old_abspath, $new_abspath ); } } // Mark as done. $retval[] = $new_image_id; } } } return $retval; } /** * Moves images from to another gallery * * @param array $images * @param int|object $gallery * @return int[] */ public function move_images( $images, $gallery ) { $retval = $this->copy_images( $images, $gallery ); if ( $images ) { foreach ( $images as $image_id ) { $this->delete_image( $image_id ); } } return $retval; } /** * @param string $abspath * @return bool */ public function delete_directory( $abspath ) { $retval = false; if ( @file_exists( $abspath ) ) { $files = scandir( $abspath ); array_shift( $files ); array_shift( $files ); foreach ( $files as $file ) { $file_abspath = implode( DIRECTORY_SEPARATOR, [ rtrim( $abspath, '/\\' ), $file ] ); if ( is_dir( $file_abspath ) ) { $this->delete_directory( $file_abspath ); } else { unlink( $file_abspath ); } } rmdir( $abspath ); $retval = @file_exists( $abspath ); } return $retval; } public function delete_gallery( $gallery ) { $fs = Filesystem::get_instance(); $safe_dirs = [ DIRECTORY_SEPARATOR, $fs->get_document_root( 'plugins' ), $fs->get_document_root( 'plugins_mu' ), $fs->get_document_root( 'templates' ), $fs->get_document_root( 'stylesheets' ), $fs->get_document_root( 'content' ), $fs->get_document_root( 'galleries' ), $fs->get_document_root(), ]; $abspath = $this->get_gallery_abspath( $gallery ); if ( $abspath && file_exists( $abspath ) && ! in_array( stripslashes( $abspath ), $safe_dirs ) ) { $this->delete_gallery_directory( $abspath ); } } /** * @param Image $image * @param string|false $size * @return bool */ public function delete_image( $image, $size = false ) { $retval = false; // Ensure that we have the image entity. if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } if ( $image ) { $image_id = $image->{$image->id_field}; do_action( 'ngg_delete_image', $image_id, $size ); // Delete only a particular image size. if ( $size ) { $abspath = $this->get_image_abspath( $image, $size ); if ( $abspath && @file_exists( $abspath ) ) { @unlink( $abspath ); } if ( isset( $image->meta_data ) && isset( $image->meta_data[ $size ] ) ) { unset( $image->meta_data[ $size ] ); $this->image_mapper->save( $image ); } } // Delete all sizes of the image. else { foreach ( $this->get_image_sizes( $image ) as $named_size ) { $image_abspath = $this->get_image_abspath( $image, $named_size ); @unlink( $image_abspath ); } // Delete the entity. $this->image_mapper->destroy( $image ); } $retval = true; } return $retval; } /** * Outputs/renders an image * * @param Image $image * @return bool */ public function render_image( $image, $size = false ) { $format_list = $this->get_image_format_list(); $abspath = $this->get_image_abspath( $image, $size, true ); if ( $abspath == null ) { $thumbnail = $this->generate_image_size( $image, $size ); if ( $thumbnail != null ) { $abspath = $thumbnail->fileName; $thumbnail->destruct(); } } if ( $abspath != null ) { $data = @getimagesize( $abspath ); $format = 'jpg'; if ( $data != null && is_array( $data ) && isset( $format_list[ $data[2] ] ) ) { $format = $format_list[ $data[2] ]; } // Clear output. while ( ob_get_level() > 0 ) { ob_end_clean(); } $format = strtolower( $format ); // output image and headers. header( 'Content-type: image/' . $format ); readfile( $abspath ); return true; } return false; } /** * Recover image from backup copy and reprocess it * * @param Image $image * @return bool|string result code */ public function recover_image( $image ) { $retval = false; if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } if ( $image ) { $full_abspath = $this->get_image_abspath( $image ); $backup_abspath = $this->get_image_abspath( $image, 'backup' ); if ( $backup_abspath != $full_abspath && @file_exists( $backup_abspath ) ) { if ( is_writable( $full_abspath ) && is_writable( dirname( $full_abspath ) ) ) { // Copy the backup. if ( @copy( $backup_abspath, $full_abspath ) ) { // Backup images are not altered at all; we must re-correct the EXIF/Orientation tag. $this->correct_exif_rotation( $image, true ); // Re-create non-fullsize image sizes. foreach ( $this->get_image_sizes( $image ) as $named_size ) { if ( in_array( $named_size, [ 'full', 'backup' ] ) ) { continue; } // Reset thumbnail cropping set by 'Edit thumb' dialog. if ( $named_size === 'thumbnail' ) { unset( $image->meta_data[ $named_size ]['crop_frame'] ); } $thumbnail = $this->generate_image_clone( $full_abspath, $this->get_image_abspath( $image, $named_size ), $this->get_image_size_params( $image, $named_size ) ); if ( $thumbnail ) { $thumbnail->destruct(); } } do_action( 'ngg_recovered_image', $image ); // Reimport all metadata. $retval = $this->image_mapper->reimport_metadata( $image ); } } } } return $retval; } /** * Copies a NGG image to the media library and returns the attachment_id * * @param Image $image * @return false|int attachment_id */ public function copy_to_media_library( $image ) { $retval = false; // Get the image. if ( is_int( $image ) ) { $imageId = $image; $mapper = ImageMapper::get_instance(); $image = $mapper->find( $imageId ); } if ( $image ) { $subdir = apply_filters( 'ngg_import_to_media_library_subdir', 'nggallery_import' ); $wordpress_upload_dir = wp_upload_dir(); $path = $wordpress_upload_dir['path'] . DIRECTORY_SEPARATOR . $subdir; if ( ! file_exists( $path ) ) { wp_mkdir_p( $path ); } $image_abspath = $this->get_image_abspath( $image, 'full' ); $new_file_path = $path . DIRECTORY_SEPARATOR . $image->filename; $image_data = getimagesize( $image_abspath ); $new_file_mime = $image_data['mime']; $i = 1; while ( file_exists( $new_file_path ) ) { ++$i; $new_file_path = $path . DIRECTORY_SEPARATOR . $i . '-' . $image->filename; } if ( @copy( $image_abspath, $new_file_path ) ) { $upload_id = wp_insert_attachment( [ 'guid' => $new_file_path, 'post_mime_type' => $new_file_mime, 'post_title' => preg_replace( '/\.[^.]+$/', '', $image->alttext ), 'post_content' => '', 'post_status' => 'inherit', ], $new_file_path ); update_post_meta( $upload_id, '_ngg_image_id', intval( $image->pid ) ); // wp_generate_attachment_metadata() comes from this file. require_once ABSPATH . 'wp-admin/includes/image.php'; $image_meta = wp_generate_attachment_metadata( $upload_id, $new_file_path ); // Generate and save the attachment metas into the database. wp_update_attachment_metadata( $upload_id, $image_meta ); $retval = $upload_id; } } return $retval; } /** * Delete the given NGG image from the media library * * @var int|stdClass $imageId */ public function delete_from_media_library( $imageId ) { // Get the image. if ( ! is_int( $imageId ) ) { $image = $imageId; $imageId = $image->pid; } if ( ( $postId = $this->is_in_media_library( $imageId ) ) ) { wp_delete_post( $postId ); } } /** * Determines if the given NGG image id has been uploaded to the media library * * @param integer $imageId * @return false|int attachment_id */ public function is_in_media_library( $imageId ) { $retval = false; // Get the image. if ( is_object( $imageId ) ) { $image = $imageId; $imageId = $image->pid; } // Try to find an attachment for the given image_id. if ( $imageId ) { $query = new \WP_Query( [ 'post_type' => 'attachment', 'meta_key' => '_ngg_image_id', 'meta_value_num' => $imageId, ] ); foreach ( $query->get_posts() as $post ) { $retval = $post->ID; } } return $retval; } /** * @param string $filename * @return bool */ public function is_allowed_image_extension( $filename ) { $extension = pathinfo( $filename, PATHINFO_EXTENSION ); $extension = strtolower( $extension ); $allowed_extensions = apply_filters( 'ngg_allowed_file_types', NGG_DEFAULT_ALLOWED_FILE_TYPES ); foreach ( $allowed_extensions as $extension ) { $allowed_extensions[] = $extension . '_backup'; } return in_array( $extension, $allowed_extensions ); } public function is_current_user_over_quota() { $retval = false; $settings = Settings::get_instance(); if ( ( is_multisite() ) && $settings->get( 'wpmuQuotaCheck' ) ) { require_once ABSPATH . 'wp-admin/includes/ms.php'; $retval = upload_is_user_over_quota( false ); } return $retval; } /** * @param string? $filename * @return bool */ public function is_image_file( $filename = null ): bool { $retval = false; // Security::verify_nonce() is a wrapper to wp_verify_nonce(). // // phpcs:disable WordPress.Security.NonceVerification.Missing // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( ! $filename && isset( $_FILES['file']['error'] ) && isset( $_FILES['file']['tmp_name'] ) && 0 === $_FILES['file']['error'] && isset( $_REQUEST['nonce'] ) && Security::verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'nextgen_upload_image' ) ) { // Windows' use of backslash characters for file paths means wp_unslash() here is destructive. if ( 0 === strncasecmp( PHP_OS, 'WIN', 3 ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash $filename = sanitize_text_field( $_FILES['file']['tmp_name'] ); } else { $filename = sanitize_text_field( wp_unslash( $_FILES['file']['tmp_name'] ) ); } } // phpcs:enable WordPress.Security.NonceVerification.Missing // phpcs:enable WordPress.Security.NonceVerification.Recommended $allowed_mime = apply_filters( 'ngg_allowed_mime_types', NGG_DEFAULT_ALLOWED_MIME_TYPES ); // If we can, we'll verify the mime type. if ( function_exists( 'exif_imagetype' ) ) { if ( ( $image_type = @exif_imagetype( $filename ) ) !== false ) { $retval = in_array( image_type_to_mime_type( $image_type ), $allowed_mime ); } } else { $file_info = @getimagesize( $filename ); if ( isset( $file_info[2] ) ) { $retval = in_array( image_type_to_mime_type( $file_info[2] ), $allowed_mime ); } } return $retval; } public function is_zip(): bool { $retval = false; // Security::verify_nonce() is a wrapper to wp_verify_nonce(). // // phpcs:disable WordPress.Security.NonceVerification.Missing // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( isset( $_FILES['file']['error'] ) && 0 === $_FILES['file']['error'] && isset( $_REQUEST['nonce'] ) && Security::verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'nextgen_upload_image' ) ) { $file_info = $_FILES['file']; if ( isset( $file_info['type'] ) ) { $type = $file_info['type']; $type_parts = explode( '/', $type ); if ( strtolower( $type_parts[0] ) == 'application' ) { $spec = $type_parts[1]; $spec_parts = explode( '-', $spec ); $spec_parts = array_map( 'strtolower', $spec_parts ); if ( in_array( $spec, [ 'zip', 'octet-stream' ] ) || in_array( 'zip', $spec_parts ) ) { $retval = true; } } } } // phpcs:enable WordPress.Security.NonceVerification.Missing // phpcs:enable WordPress.Security.NonceVerification.Recommended return $retval; } public function get_unique_abspath( $file_abspath ) { $filename = basename( $file_abspath ); $dir_abspath = dirname( $file_abspath ); $num = 1; $pattern = path_join( $dir_abspath, "*_{$filename}" ); if ( ( $found = glob( $pattern ) ) ) { natsort( $found ); $last = array_pop( $found ); $last = basename( $last ); if ( preg_match( '/^(\d+)_/', $last, $match ) ) { $num = intval( $match[1] ) + 1; } } return path_join( $dir_abspath, "{$num}_{$filename}" ); } /** * Determines whether a WebP image is animated which GD does not support. * * @see https://developers.google.com/speed/webp/docs/riff_container * @param string $filename * @return bool */ public function is_animated_webp( $filename ) { $retval = false; $handle = fopen( $filename, 'rb' ); fseek( $handle, 12 ); if ( fread( $handle, 4 ) === 'VP8X' ) { fseek( $handle, 20 ); $flag = fread( $handle, 1 ); $retval = (bool) ( ( ( ord( $flag ) >> 1 ) & 1 ) ); } fclose( $handle ); return $retval; } public function import_image_file( $dst_gallery, $image_abspath, $filename = null, $image = false, $override = false, $move = false ) { $image_abspath = wp_normalize_path( $image_abspath ); if ( $this->is_current_user_over_quota() ) { $message = sprintf( __( 'Sorry, you have used your space allocation. Please delete some files to upload more files.', 'nggallery' ) ); throw new \E_NoSpaceAvailableException( esc_html( $message ) ); } // Do we have a gallery to import to? if ( $dst_gallery ) { // Get the gallery abspath. This is where we will put the image files. $gallery_abspath = $this->get_gallery_abspath( $dst_gallery ); // If we can't write to the directory, then there's no point in continuing. if ( ! @file_exists( $gallery_abspath ) ) { @wp_mkdir_p( $gallery_abspath ); } if ( ! is_writable( $gallery_abspath ) ) { throw new \E_InsufficientWriteAccessException( false, $gallery_abspath, false ); } // Sanitize the filename for storing in the DB. $filename = $this->sanitize_filename_for_db( $filename ); // Ensure that the filename is valid. $extensions = apply_filters( 'ngg_allowed_file_types', NGG_DEFAULT_ALLOWED_FILE_TYPES ); $extensions[] = '_backup'; $ext_list = implode( '|', $extensions ); if ( ! preg_match( "/({$ext_list})\$/i", $filename ) ) { throw new \E_UploadException( __( 'Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery' ) ); } // GD does not support animated WebP and will generate a fatal error when we try to create thumbnails or resize. if ( $this->is_animated_webp( $image_abspath ) ) { throw new \E_UploadException( __( 'Animated WebP images are not supported.', 'nggallery' ) ); } // Compute the destination folder. $new_image_abspath = path_join( $gallery_abspath, $filename ); // Are the src and dst the same? If so, we don't have to copy or move files. if ( $image_abspath != $new_image_abspath ) { // If we're not to override, ensure that the filename is unique. if ( ! $override && @file_exists( $new_image_abspath ) ) { $new_image_abspath = $this->get_unique_abspath( $new_image_abspath ); $filename = $this->sanitize_filename_for_db( basename( $new_image_abspath ) ); } // Try storing the file. $copied = copy( $image_abspath, $new_image_abspath ); if ( $copied && $move ) { unlink( $image_abspath ); } // Ensure that we're not vulerable to CVE-2017-2416 exploit. if ( ( $dimensions = getimagesize( $new_image_abspath ) ) !== false ) { if ( ( isset( $dimensions[0] ) && intval( $dimensions[0] ) > 30000 ) || ( isset( $dimensions[1] ) && intval( $dimensions[1] ) > 30000 ) ) { unlink( $new_image_abspath ); throw new \E_UploadException( esc_html( __( 'Image file too large. Maximum image dimensions supported are 30k x 30k.' ) ) ); } } } // Save the image in the DB. $image_mapper = ImageMapper::get_instance(); $image_mapper->use_cache = false; if ( $image ) { if ( is_numeric( $image ) ) { $image = $image_mapper->find( $image ); } } if ( ! $image ) { $image = $image_mapper->create(); } $image->alttext = preg_replace( '#\.\w{2,4}$#', '', $filename ); $image->galleryid = is_numeric( $dst_gallery ) ? $dst_gallery : $dst_gallery->gid; $image->filename = $filename; $image->image_slug = \nggdb::get_unique_slug( sanitize_title_with_dashes( $image->alttext ), 'image' ); $image_id = $image_mapper->save( $image ); if ( ! $image_id ) { $exception = ''; $validation = $image->validation(); if ( is_array( $validation ) ) { foreach ( $validation as $field => $errors ) { foreach ( $errors as $error ) { if ( ! empty( $exception ) ) { $exception .= '<br/>'; } $exception .= __( sprintf( 'Error while uploading %s: %s', $filename, $error ), 'nextgen-gallery' ); } } throw new \E_UploadException( $exception ); } } // Important: do not remove this line. The image mapper's save() routine imports metadata // meaning we must re-acquire a new $image object after saving it above; if we do not our // existing $image object will lose any metadata retrieved during said save() method. $image = $image_mapper->find( $image_id ); $image_mapper->use_cache = true; $settings = Settings::get_instance(); // Backup the image. if ( $settings->get( 'imgBackup', false ) ) { $this->backup_image( $image, true ); } // Most browsers do not honor EXIF's Orientation header: rotate the image to prevent display issues. $this->correct_exif_rotation( $image, true ); // Create resized version of image. if ( $settings->get( 'imgAutoResize', false ) ) { $this->generate_resized_image( $image, true ); } // Generate a thumbnail for the image. $this->generate_thumbnail( $image ); // Set gallery preview image if missing. GalleryMapper::get_instance()->set_preview_image( $dst_gallery, $image_id, true ); // Automatically watermark the main image if requested. if ( $settings->get( 'watermark_automatically_at_upload', 0 ) ) { $image_abspath = $this->get_image_abspath( $image, 'full' ); $this->generate_image_clone( $image_abspath, $image_abspath, [ 'watermark' => true ] ); } // Notify other plugins that an image has been added. do_action( 'ngg_added_new_image', $image ); // delete dirsize after adding new images. delete_transient( 'dirsize_cache' ); // Seems redundant to above hook. Maintaining for legacy purposes. do_action( 'ngg_after_new_images_added', is_numeric( $dst_gallery ) ? $dst_gallery : $dst_gallery->gid, [ $image_id ] ); return $image_id; } else { throw new \E_EntityNotFoundException(); } return null; } /** * Generates a specific size for an image * * @param Image $image * @param string $size * @param array|null $params (optional) * @param bool $skip_defaults (optional) * @return bool|object */ public function generate_image_size( $image, $size, $params = null, $skip_defaults = false ) { $retval = false; // Get the image entity. if ( is_numeric( $image ) ) { $image = $this->image_mapper->find( $image ); } // Ensure we have a valid image. if ( $image ) { $params = $this->get_image_size_params( $image, $size, $params, $skip_defaults ); $settings = Settings::get_instance(); // Get the image filename. $filename = $this->get_image_abspath( $image, 'full' ); if ( ! @file_exists( $filename ) ) { return false; // bail out if the file doesn't exist. } $thumbnail = null; if ( $size == 'full' && $settings->get( 'imgBackup' ) == 1 ) { $backup_path = $this->get_backup_abspath( $image ); if ( ! @file_exists( $backup_path ) ) { @copy( $filename, $backup_path ); } } // Generate the thumbnail using WordPress. $existing_image_abpath = $this->get_image_abspath( $image, $size ); $existing_image_dir = dirname( $existing_image_abpath ); \wp_mkdir_p( $existing_image_dir ); $clone_path = $existing_image_abpath; $thumbnail = $this->generate_image_clone( $filename, $clone_path, $params ); // We successfully generated the thumbnail. if ( $thumbnail != null ) { $clone_path = $thumbnail->fileName; if ( function_exists( 'getimagesize' ) ) { $dimensions = getimagesize( $clone_path ); } else { $dimensions = [ $params['width'], $params['height'] ]; } if ( ! isset( $image->meta_data ) ) { $image->meta_data = []; } $size_meta = [ 'width' => $dimensions[0], 'height' => $dimensions[1], 'filename' => I18N::mb_basename( $clone_path ), 'generated' => microtime(), ]; if ( isset( $params['crop_frame'] ) ) { $size_meta['crop_frame'] = $params['crop_frame']; } $image->meta_data[ $size ] = $size_meta; if ( $size == 'full' ) { $image->meta_data['width'] = $size_meta['width']; $image->meta_data['height'] = $size_meta['height']; } $retval = $this->image_mapper->save( $image ); \do_action( 'ngg_generated_image', $image, $size, $params ); if ( $retval == 0 ) { $retval = false; } if ( $retval ) { $retval = $thumbnail; } } } return $retval; } /** * Generates a thumbnail for an image * * @param Image $image * @return bool */ public function generate_thumbnail( $image, $params = null, $skip_defaults = false ) { $sized_image = $this->generate_image_size( $image, 'thumbnail', $params, $skip_defaults ); $retval = false; if ( $sized_image != null ) { $retval = true; $sized_image->destruct(); } if ( is_admin() && ( $image = ImageMapper::get_instance()->find( $image ) ) ) { $app = Router::get_instance()->get_routed_app(); $image->thumb_url = $app->set_parameter_value( 'timestamp', time(), null, $this->get_image_url( $image, 'thumb' ), $app->get_routed_url( true ) ); $event = new \stdClass(); $event->pid = $image->{$image->id_field}; $event->id_field = $image->id_field; $event->thumb_url = $image->thumb_url; EventPublisher::get_instance()->add_event( [ 'event' => 'thumbnail_modified', 'image' => $event, ] ); } return $retval; } /** * Gets the absolute path of the backup of an original image * * @param object|string $image * @return null|string */ public function get_backup_abspath( $image ) { $retval = null; if ( ( $image_path = $this->get_image_abspath( $image ) ) ) { $retval = $image_path . '_backup'; } return $retval; } public function get_backup_dimensions( $image ) { return $this->get_image_dimensions( $image, 'backup' ); } /** * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image * * @param int|object $image * @param string $size (optional) Default = full * @param bool $check_existence (optional) Default = false * @return string */ public function get_image_abspath( $image, $size = 'full', $check_existence = false ) { $image_id = is_numeric( $image ) ? $image : $image->pid; $size = $this->normalize_image_size_name( $size ); $key = strval( $image_id ) . $size; if ( $check_existence || ! isset( self::$image_abspath_cache[ $key ] ) ) { self::$image_abspath_cache[ $key ] = $this->get_computed_image_abspath( $image, $size, $check_existence ); } return self::$image_abspath_cache[ $key ]; } /** * Gets the url of a particular-sized image * * @param int|object $image * @param string $size * @return string */ public function get_image_url( $image, $size = 'full' ) { $retval = null; $image_id = is_numeric( $image ) ? $image : $image->pid; $key = strval( $image_id ) . $size; $success = true; if ( ! isset( self::$image_url_cache[ $key ] ) ) { $url = $this->get_computed_image_url( $image, $size ); if ( $url ) { self::$image_url_cache[ $key ] = $url; $success = true; } else { $success = false; } } if ( $success ) { $retval = self::$image_url_cache[ $key ]; } else { $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); if ( $dynthumbs->is_size_dynamic( $size ) ) { $params = $dynthumbs->get_params_from_name( $size ); $retval = Router::get_instance()->get_url( $dynthumbs->get_image_uri( $image, $params ), false, 'root' ); } } return apply_filters( 'ngg_get_image_url', $retval, $image, $size ); } /** * Flushes the cache we use for path/url calculation for images */ public function flush_image_path_cache( $image, $size ) { $image = is_numeric( $image ) ? $image : $image->pid; $key = strval( $image ) . $size; unset( self::$image_abspath_cache[ $key ] ); unset( self::$image_url_cache[ $key ] ); } /** * @param string $abspath * @param int $gallery_id * @param bool $create_new_gallerypath * @param null|string $gallery_title * @param array[string] $filenames * @return array|bool false on failure */ public function import_gallery_from_fs( $abspath, $gallery_id = null, $create_new_gallerypath = true, $gallery_title = null, $filenames = [] ) { if ( @ ! file_exists( $abspath ) ) { return false; } $fs = Filesystem::get_instance(); $retval = [ 'image_ids' => [] ]; // Ensure that this folder has images. $files = []; $directories = []; foreach ( scandir( $abspath ) as $file ) { if ( $file == '.' || $file == '..' || strtoupper( $file ) == '__MACOSX' ) { continue; } $file_abspath = $fs->join_paths( $abspath, $file ); // Omit 'hidden' directories prefixed with a period. if ( is_dir( $file_abspath ) && strpos( $file, '.' ) !== 0 ) { $directories[] = $file_abspath; } elseif ( $this->is_image_file( $file_abspath ) ) { if ( $filenames && array_search( $file_abspath, $filenames ) !== false ) { $files[] = $file_abspath; } elseif ( ! $filenames ) { $files[] = $file_abspath; } } } if ( empty( $files ) && empty( $directories ) ) { return false; } // Get needed utilities. $gallery_mapper = GalleryMapper::get_instance(); // Recurse through the directory and pull in all of the valid images we find. if ( ! empty( $directories ) ) { foreach ( $directories as $dir ) { $subImport = $this->import_gallery_from_fs( $dir, $gallery_id, $create_new_gallerypath, $gallery_title, $filenames ); if ( $subImport ) { $retval['image_ids'] = array_merge( $retval['image_ids'], $subImport['image_ids'] ); } } } // If no gallery has been specified, then use the directory name as the gallery name. if ( ! $gallery_id ) { // Create the gallery. $gallery = $gallery_mapper->create( [ 'title' => $gallery_title ? $gallery_title : I18N::mb_basename( $abspath ), ] ); if ( ! $create_new_gallerypath ) { $gallery_root = $fs->get_document_root( 'gallery' ); $gallery->path = str_ireplace( $gallery_root, '', $abspath ); } // Save the gallery. if ( $gallery->save() ) { $gallery_id = $gallery->id(); } } // Ensure that we have a gallery id. if ( ! $gallery_id ) { return false; } else { $retval['gallery_id'] = $gallery_id; } // Remove full sized image if backup is included. $files_to_import = []; foreach ( $files as $file_abspath ) { if ( preg_match( '#_backup$#', $file_abspath ) ) { $files_to_import[] = $file_abspath; continue; } elseif ( in_array( [ $file_abspath . '_backup', 'thumbs_' . $file_abspath, 'thumbs-' . $file_abspath ], $files ) ) { continue; } $files_to_import[] = $file_abspath; } foreach ( $files_to_import as $file_abspath ) { $basename = preg_replace( '#_backup$#', '', pathinfo( $file_abspath, PATHINFO_BASENAME ) ); if ( $this->is_image_file( $file_abspath ) ) { if ( ( $image_id = $this->import_image_file( $gallery_id, $file_abspath, $basename, false, false, false ) ) ) { $retval['image_ids'][] = $image_id; } } } // Add the gallery name to the result. if ( ! isset( $gallery ) ) { $gallery = $gallery_mapper->find( $gallery_id ); } $retval['gallery_name'] = $gallery->title; return $retval; } public function maybe_base64_decode( $data ) { $decoded = base64_decode( $data ); if ( $decoded === false ) { return $data; } elseif ( base64_encode( $decoded ) == $data ) { return base64_decode( $data ); } return $data; } public static function register_custom_post_types() { $types = [ 'ngg_album' => 'NextGEN Gallery - Album', 'ngg_gallery' => 'NextGEN Gallery - Gallery', 'ngg_pictures' => 'NextGEN Gallery - Image', ]; foreach ( $types as $type => $label ) { \register_post_type( $type, [ 'label' => $label, 'publicly_queryable' => false, 'exclude_from_search' => true, ] ); } } /** * Sanitizes a directory path, replacing whitespace with dashes. * * Taken from WP' sanitize_file_name() and modified to not act on file extensions. * * Removes special characters that are illegal in filenames on certain * operating systems and special characters requiring special escaping * to manipulate at the command line. Replaces spaces and consecutive * dashes with a single dash. Trims period, dash and underscore from beginning * and end of filename. It is not guaranteed that this function will return a * filename that is allowed to be uploaded. * * @param string $dirname The directory name to be sanitized * @return string The sanitized directory name */ public function sanitize_directory_name( $dirname ) { $dirname_raw = $dirname; $special_chars = [ '?', '[', ']', '/', '\\', '=', '<', '>', ':', ';', ',', "'", '"', '&', '$', '#', '*', '(', ')', '|', '~', '`', '!', '{', '}', '%', '+', chr( 0 ) ]; $special_chars = apply_filters( 'sanitize_file_name_chars', $special_chars, $dirname_raw ); $dirname = preg_replace( "#\x{00a0}#siu", ' ', $dirname ); $dirname = str_replace( $special_chars, '', $dirname ); $dirname = str_replace( [ '%20', '+' ], '-', $dirname ); $dirname = preg_replace( '/[\r\n\t -]+/', '-', $dirname ); $dirname = trim( $dirname, '.-_' ); return $dirname; } public function sanitize_filename_for_db( $filename = null ) { $filename = $filename ? $filename : uniqid( 'nextgen-gallery' ); $filename = preg_replace( '#^/#', '', $filename ); $filename = sanitize_file_name( $filename ); if ( preg_match( '/\-(png|jpg|gif|jpeg|jpg_backup)$/i', $filename, $match ) ) { $filename = str_replace( $match[0], '.' . $match[1], $filename ); } return $filename; } /** * Sets a NGG image as a post thumbnail for the given post * * @param int $postId * @param Image $image * @param bool $only_create_attachment * @return int */ public function set_post_thumbnail( $postId, $image, $only_create_attachment = false ) { $retval = false; // Get the post ID. if ( is_object( $postId ) ) { $post = $postId; $postId = isset( $post->ID ) ? $post->ID : $post->post_id; } // Get the image. if ( is_int( $image ) ) { $imageId = $image; $mapper = ImageMapper::get_instance(); $image = $mapper->find( $imageId ); } if ( $image && $postId ) { $attachment_id = $this->is_in_media_library( $image->pid ); if ( $attachment_id === false ) { $attachment_id = $this->copy_to_media_library( $image ); } if ( $attachment_id ) { if ( ! $only_create_attachment ) { set_post_thumbnail( $postId, $attachment_id ); } $retval = $attachment_id; } } return $retval; } /** * Uploads an image for a particular gallery * * @param int|object|Gallery $gallery * @param string|bool $filename (optional) Specifies the name of the file * @param string|bool $data (optional) If specified, expects base64 encoded string of data * * @return array|array[]|bool|int $image */ public function upload_image( $gallery, $filename = false, $data = false ) { // Ensure that we have the data present that we require. // // Security::verify_nonce() is a wrapper to wp_verify_nonce(). // // phpcs:disable WordPress.Security.NonceVerification.Missing // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( isset( $_FILES['file'] ) && 0 === $_FILES['file']['error'] && isset( $_FILES['file']['tmp_name'] ) && isset( $_REQUEST['nonce'] ) && Security::verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'nextgen_upload_image' ) ) { $file = $_FILES['file']; if ( $this->is_zip() ) { $retval = $this->upload_zip( $gallery ); } elseif ( $this->is_image_file() ) { $retval = $this->import_image_file( $gallery, $file['tmp_name'], $filename ? $filename : ( isset( $file['name'] ) ? $file['name'] : false ), false, false, true ); } else { // Remove the non-valid (and potentially insecure) file from the PHP upload directory. if ( isset( $_FILES['file']['tmp_name'] ) ) { $filename = $_FILES['file']['tmp_name']; @unlink( $filename ); } throw new \E_UploadException( __( 'Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery' ) ); } } elseif ( $data ) { $retval = $this->upload_base64_image( $gallery, $data, $filename ); } else { throw new \E_UploadException(); } // phpcs:enable WordPress.Security.NonceVerification.Missing // phpcs:enable WordPress.Security.NonceVerification.Recommended return $retval; } /** * Uploads base64 file to a gallery * * @param int|\stdClass|Gallery $gallery * @param string $data base64-encoded string of data representing the image * @param string|false (optional) $filename specifies the name of the file * @param int|false $image_id (optional) * @param bool $override (optional) * * @return bool|int */ public function upload_base64_image( $gallery, $data, $filename = false, $image_id = false, $override = false, $move = false ) { $temp_abspath = tempnam( sys_get_temp_dir(), '' ); // Try writing the image. $fp = fopen( $temp_abspath, 'wb' ); fwrite( $fp, $this->maybe_base64_decode( $data ) ); fclose( $fp ); return $this->import_image_file( $gallery, $temp_abspath, $filename, $image_id, $override, $move ); } /** * @param int $gallery_id * @return array|bool */ public function upload_zip( $gallery_id ) { if ( ! $this->is_zip() ) { return false; } // Security::verify_nonce() is a wrapper to wp_verify_nonce(). // // phpcs:disable WordPress.Security.NonceVerification.Missing // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( ! isset( $_REQUEST['nonce'] ) || ! Security::verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'nextgen_upload_image' ) ) { return false; } // phpcs:enable WordPress.Security.NonceVerification.Missing // phpcs:enable WordPress.Security.NonceVerification.Recommended $retval = false; $memory_limit = intval( ini_get( 'memory_limit' ) ); if ( ! extension_loaded( 'suhosin' ) && $memory_limit < 256 ) { @ini_set( 'memory_limit', '256M' ); } $fs = Filesystem::get_instance(); // Uses the WordPress ZIP abstraction API. include_once $fs->join_paths( ABSPATH, 'wp-admin', 'includes', 'file.php' ); WP_Filesystem( false, get_temp_dir(), true ); // Ensure that we truly have the gallery id. $gallery_id = $this->get_gallery_id( $gallery_id ); // The nonce was already checked above, by Security::verify_nonce(). Also PHP-CS still flags this particular // line when using phpcs:ignore, thus the disable/enable pairing found here. // // phpcs:disable WordPress.Security.NonceVerification.Missing $zipfile = $_FILES['file']['tmp_name']; // phpcs:enable WordPress.Security.NonceVerification.Missing $dest_path = implode( DIRECTORY_SEPARATOR, [ rtrim( get_temp_dir(), '/\\' ), 'unpacked-' . I18N::mb_basename( $zipfile ), ] ); // Attempt to extract the zip file into the normal system directory. $extracted = $this->extract_zip( $zipfile, $dest_path ); // Now verify it worked. get_temp_dir() will check each of the following directories to ensure they are // a directory and against wp_is_writable(). Should ALL of those options fail we will fallback to wp_upload_dir(). $size = 0; $files = glob( $dest_path . DIRECTORY_SEPARATOR . '*' ); foreach ( $files as $file ) { if ( is_array( stat( $file ) ) ) { $size += filesize( $file ); } } // Extraction failed; attempt again with wp_upload_dir(). if ( $size == 0 ) { // Remove the empty directory we may have possibly created but could not write to. $this->delete_directory( $dest_path ); $destination = wp_upload_dir(); $destination_path = $destination['basedir']; $dest_path = implode( DIRECTORY_SEPARATOR, [ rtrim( $destination_path, '/\\' ), rand(), 'unpacked-' . I18N::mb_basename( $zipfile ), ] ); $extracted = $this->extract_zip( $zipfile, $dest_path ); } if ( $extracted ) { $retval = $this->import_gallery_from_fs( $dest_path, $gallery_id ); } $this->delete_directory( $dest_path ); if ( ! extension_loaded( 'suhosin' ) ) { @ini_set( 'memory_limit', $memory_limit . 'M' ); } return $retval; } public static function wp_query_order_by( $order_by, $wp_query ) { if ( $wp_query->get( 'datamapper_attachment' ) ) { $order_parts = explode( ' ', $order_by ); $order_name = array_shift( $order_parts ); $order_by = 'ABS(' . $order_name . ') ' . implode( ' ', $order_parts ) . ', ' . $order_by; } return $order_by; } /** * Gets the id of an image, regardless of whether an integer or object was passed as an argument. * * This method is, as of 3.50's release, used by EWWW and WP-SmushIt * * @param object|int $image_obj_or_id * @return null|int * @deprecated */ function _get_image_id( $image_obj_or_id ) { $retval = null; $image_key = $this->_image_mapper->get_primary_key_column(); if ( is_object( $image_obj_or_id ) ) { if ( isset( $image_obj_or_id->$image_key ) ) { $retval = $image_obj_or_id->$image_key; } } elseif ( is_numeric( $image_obj_or_id ) ) { $retval = $image_obj_or_id; } return $retval; } } ��������������������������������������������������������������������������������������������������������������������������������������������DataStorage/EXIFWriter.php��������������������������������������������������������������������������0000644�����������������00000017225�15021223045�0011404 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataStorage; // 0.9.10 is compatible with PHP 8.0 but requires 7.2.0 as its minimum. if ( version_compare( phpversion(), '7.2.0', '>=' ) ) { require_once NGG_PLUGIN_DIR . 'lib' . DIRECTORY_SEPARATOR . 'pel-0.9.12/autoload.php'; } else { require_once NGG_PLUGIN_DIR . 'lib' . DIRECTORY_SEPARATOR . 'pel-0.9.9/autoload.php'; } use Imagely\NGG\Display\I18N; use lsolesen\pel\PelDataWindow; use lsolesen\pel\PelJpeg; use lsolesen\pel\PelTiff; use lsolesen\pel\PelExif; use lsolesen\pel\PelIfd; use lsolesen\pel\PelTag; use lsolesen\pel\PelEntryShort; use lsolesen\pel\PelInvalidArgumentException; use lsolesen\pel\PelIfdException; use lsolesen\pel\PelInvalidDataException; use lsolesen\pel\PelJpegInvalidMarkerException; class EXIFWriter { /** * @param $filename * @return array|null */ public static function read_metadata( $filename ) { if ( ! self::is_jpeg_file( $filename ) ) { return null; } $retval = null; try { $data = new PelDataWindow( @file_get_contents( $filename ) ); $exif = new PelExif(); if ( PelJpeg::isValid( $data ) ) { $jpeg = new PelJpeg(); @$jpeg->load( $data ); $exif = $jpeg->getExif(); if ( null === $exif ) { $exif = new PelExif(); $jpeg->setExif( $exif ); $tiff = new PelTiff(); $exif->setTiff( $tiff ); } else { $tiff = $exif->getTiff(); } } elseif ( PelTiff::isValid( $data ) ) { $tiff = new PelTiff(); $tiff->load( $data ); } else { return null; } $ifd0 = $tiff->getIfd(); if ( null === $ifd0 ) { $ifd0 = new PelIfd( PelIfd::IFD0 ); $tiff->setIfd( $ifd0 ); } $tiff->setIfd( $ifd0 ); $exif->setTiff( $tiff ); $retval = [ 'exif' => $exif, 'iptc' => null, ]; @getimagesize( $filename, $iptc ); if ( ! empty( $iptc['APP13'] ) ) { $retval['iptc'] = $iptc['APP13']; } } catch ( PelIfdException $exception ) { return null; } catch ( PelInvalidArgumentException $exception ) { return null; } catch ( PelInvalidDataException $exception ) { return null; } catch ( PelJpegInvalidMarkerException $exception ) { return null; } catch ( \Exception $exception ) { return null; } finally { return $retval; } } /** * @param $origin_file * @param $destination_file * @return bool|int FALSE on failure or (int) number of bytes written */ public static function copy_metadata( $origin_file, $destination_file ) { if ( ! self::is_jpeg_file( $origin_file ) ) { return false; } // Read existing data from the source file. $metadata = self::read_metadata( $origin_file ); if ( ! empty( $metadata ) && is_array( $metadata ) ) { return self::write_metadata( $destination_file, $metadata ); } else { return false; } } /** * @param $filename * @param $metadata * @return bool|int FALSE on failure or (int) number of bytes written. */ public static function write_metadata( $filename, $metadata ) { if ( ! self::is_jpeg_file( $filename ) || ! is_array( $metadata ) ) { return false; } try { // Prevent the orientation tag from ever being anything other than normal horizontal. /** @var PelExif $exif */ $exif = $metadata['exif']; $tiff = $exif->getTiff(); $ifd0 = $tiff->getIfd(); $orientation = new PelEntryShort( PelTag::ORIENTATION, 1 ); $ifd0->addEntry( $orientation ); $tiff->setIfd( $ifd0 ); $exif->setTiff( $tiff ); $metadata['exif'] = $exif; // Copy EXIF data to the new image and write it. $new_image = new PelJpeg( $filename ); $new_image->setExif( $metadata['exif'] ); $new_image->saveFile( $filename ); // Copy IPTC / APP13 to the new image and write it. if ( $metadata['iptc'] ) { return self::write_IPTC( $filename, $metadata['iptc'] ); } } catch ( PelInvalidArgumentException $exception ) { return false; } catch ( PelInvalidDataException $exception ) { error_log( "Could not write data to {$filename}" ); error_log( print_r( $exception, true ) ); return false; } // This should never happen, but this line satisfies phpstan. return false; } // In case bcmath isn't enabled we use these simple wrappers. static function bcadd( $one, $two, $scale = null ) { if ( ! function_exists( 'bcadd' ) ) { return floatval( $one ) + floatval( $two ); } else { return bcadd( $one, $two, $scale ); } } static function bcmul( $one, $two, $scale = null ) { if ( ! function_exists( 'bcmul' ) ) { return floatval( $one ) * floatval( $two ); } else { return bcmul( $one, $two, $scale ); } } static function bcpow( $one, $two, $scale = null ) { if ( ! function_exists( 'bcpow' ) ) { return floatval( $one ) ** floatval( $two ); } else { return bcpow( $one, $two, $scale ); } } /** * Use bcmath as a replacement to hexdec() to handle numbers than PHP_INT_MAX. Also validates the $hex parameter using ctypes. * * @param string $hex * @return float|int|string|null */ public static function bchexdec( $hex ) { // Ensure $hex is actually a valid hex number and won't generate deprecated conversion warnings on PHP 7.4+. if ( ! ctype_xdigit( $hex ) ) { return null; } $decimal = 0; $length = strlen( $hex ); for ( $i = 1; $i <= $length; $i++ ) { $decimal = self::bcadd( $decimal, self::bcmul( strval( hexdec( $hex[ $i - 1 ] ) ), self::bcpow( '16', strval( $length - $i ) ) ) ); } return $decimal; } /** * @param string $filename * @param array $data * @return bool|int FALSE on failure or (int) number of bytes written */ public static function write_IPTC( $filename, $data ) { if ( ! self::is_jpeg_file( $filename ) ) { return false; } $length = strlen( $data ) + 2; // Avoid invalid APP13 regions. if ( $length > 0xFFFF ) { return false; } // Wrap existing data in segment container we can embed new content in. $data = chr( 0xFF ) . chr( 0xED ) . chr( ( $length >> 8 ) & 0xFF ) . chr( $length & 0xFF ) . $data; $new_file_contents = @file_get_contents( $filename ); if ( ! $new_file_contents || strlen( $new_file_contents ) <= 0 ) { return false; } $new_file_contents = substr( $new_file_contents, 2 ); // Create new image container wrapper. $new_iptc = chr( 0xFF ) . chr( 0xD8 ); // Track whether content was modified. $new_fields_added = ! $data; // This can cause errors if incorrectly pointed at a non-JPEG file. try { // Loop through each JPEG segment in search of region 13. while ( ( self::bchexdec( substr( $new_file_contents, 0, 2 ) ) & 0xFFF0 ) === 0xFFE0 ) { $segment_length = ( hexdec( substr( $new_file_contents, 2, 2 ) ) & 0xFFFF ); $segment_number = ( hexdec( substr( $new_file_contents, 1, 1 ) ) & 0x0F ); // Not a segment we're interested in. if ( $segment_length <= 2 ) { return false; } $current_segment = substr( $new_file_contents, 0, $segment_length + 2 ); if ( ( 13 <= $segment_number ) && ( ! $new_fields_added ) ) { $new_iptc .= $data; $new_fields_added = true; if ( 13 === $segment_number ) { $current_segment = ''; } } $new_iptc .= $current_segment; $new_file_contents = substr( $new_file_contents, $segment_length + 2 ); } } catch ( \Exception $exception ) { return false; } if ( ! $new_fields_added ) { $new_iptc .= $data; } if ( $file = @fopen( $filename, 'wb' ) ) { return @fwrite( $file, $new_iptc . $new_file_contents ); } else { return false; } } /** * Determines if the file extension is .jpg or .jpeg * * @param $filename * @return bool */ public static function is_jpeg_file( $filename ) { $extension = I18N::mb_pathinfo( $filename, PATHINFO_EXTENSION ); return in_array( strtolower( $extension ), [ 'jpeg', 'jpg', 'jpeg_backup', 'jpg_backup' ] ); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataStorage/Sanitizer.php���������������������������������������������������������������������������0000644�����������������00000003077�15021223045�0011424 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataStorage; class Sanitizer { public static function strip_html( $data, $just_scripts = false ) { // NGG 3.3.11 fix. Some of the data persisted with 3.3.11 didn't strip out all HTML. if ( strpos( $data, 'ngg_data_strip_html_placeholder' ) !== false ) { if ( class_exists( 'DomDocument' ) ) { $dom = new \DOMDocument( '1.0', 'UTF-8' ); $dom->loadHTML( $data ); $el = $dom->getElementById( 'ngg_data_strip_html_placeholder' ); $parts = array_map( function ( $el ) use ( $dom ) { $part = $dom->saveHTML( $el ); return $part instanceof \DOMText ? $part->data : (string) $part; }, $el->childNodes ? iterator_to_array( $el->childNodes ) : [] ); return self::strip_html( implode( ' ', $parts ), $just_scripts ); } else { return \wp_strip_all_tags( $data ); } } // Remove all HTML elements. if ( ! $just_scripts ) { return \wp_strip_all_tags( $data ); } elseif ( class_exists( 'DOMDocument' ) ) { // Remove unsafe HTML. This can generate a *lot* of warnings when given improper texts. libxml_use_internal_errors( true ); libxml_clear_errors(); $config = \HTMLPurifier_Config::createDefault(); $config->set( 'Cache.DefinitionImpl', null ); $purifier = new \HTMLPurifier( $config ); $default_return = $purifier->purify( $data ); return \apply_filters( 'ngg_html_sanitization', $default_return, $data ); } else { // wp_strip_all_tags() is misleading in a way - it only removes <script> and <style> tags. return \wp_strip_all_tags( $data, true ); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataStorage/MetaData.php����������������������������������������������������������������������������0000644�����������������00000044474�15021223045�0011142 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataStorage; use Imagely\NGG\DataMappers\Image as ImageMapper; class MetaData { // Image data. public $image = ''; // The image object. public $file_path = ''; // Path to the image file. public $size = false; // The image size. public $exif_data = false; // EXIF data array. public $iptc_data = false; // IPTC data array. public $xmp_data = false; // XMP data array. // Filtered Data. public $exif_array = false; // EXIF data array. public $iptc_array = false; // IPTC data array. public $xmp_array = false; // XMP data array. public $sanitize = false; // sanitize meta data on request. /** * Class constructor * * @param int $image Image ID * @param bool $onlyEXIF TRUE = will parse only EXIF data * @return bool FALSE if the file does not exist or metadat could not be read */ public function __construct( $image, $onlyEXIF = false ) { if ( is_numeric( $image ) ) { $image = ImageMapper::get_instance()->find( $image ); } $this->image = \apply_filters( 'ngg_find_image_meta', $image ); $this->file_path = Manager::get_instance()->get_image_abspath( $this->image ); if ( ! @file_exists( $this->file_path ) ) { return false; } $this->size = @getimagesize( $this->file_path, $metadata ); if ( $this->size && is_array( $metadata ) ) { // get exif - data. if ( is_callable( 'exif_read_data' ) ) { $this->exif_data = @exif_read_data( $this->file_path, null, true ); } // stop here if we didn't need other meta data. if ( $onlyEXIF ) { return true; } // get the iptc data - should be in APP13. if ( is_callable( 'iptcparse' ) && isset( $metadata['APP13'] ) ) { $this->iptc_data = @iptcparse( $metadata['APP13'] ); } // get the xmp data in a XML format. if ( is_callable( 'xml_parser_create' ) ) { $this->xmp_data = $this->extract_XMP( $this->file_path ); } return true; } return false; } /** * return the saved metadata from the database * * @since 1.4.0 * @param string $object (optional) * @return array|mixed return either the complete array or the single object */ public function get_saved_meta( $object = false ) { $meta = $this->image->meta_data; // Check if we already import the meta data to the database. if ( ! is_array( $meta ) || ! isset( $meta['saved'] ) || ( $meta['saved'] !== true ) ) { return false; } // return one element if requested. if ( $object ) { return $meta[ $object ]; } // removed saved parameter we don't need that to show. unset( $meta['saved'] ); // and remove empty tags or arrays. foreach ( $meta as $key => $value ) { if ( empty( $value ) or is_array( $value ) ) { unset( $meta[ $key ] ); } } // on request sanitize the output. if ( $this->sanitize == true ) { array_walk( $meta, 'esc_html' ); } return $meta; } /** * nggMeta::get_EXIF() * See also http://trac.wordpress.org/changeset/6313 * * @return bool|array */ public function get_EXIF( $object = false ) { if ( ! $this->exif_data ) { return false; } if ( ! is_array( $this->exif_array ) ) { $meta = []; if ( isset( $this->exif_data['EXIF'] ) ) { $exif = $this->exif_data['EXIF']; if ( ! empty( $exif['FNumber'] ) ) { $meta['aperture'] = 'F ' . round( $this->exif_frac2dec( $exif['FNumber'] ), 2 ); } if ( ! empty( $exif['Model'] ) ) { $meta['camera'] = trim( $exif['Model'] ); } if ( ! empty( $exif['DateTimeDigitized'] ) ) { $meta['created_timestamp'] = $this->exif_date2ts( $exif['DateTimeDigitized'] ); } elseif ( ! empty( $exif['DateTimeOriginal'] ) ) { $meta['created_timestamp'] = $this->exif_date2ts( $exif['DateTimeOriginal'] ); } elseif ( ! empty( $exif['FileDateTime'] ) ) { $meta['created_timestamp'] = $this->exif_date2ts( $exif['FileDateTime'] ); } if ( ! empty( $exif['FocalLength'] ) ) { $meta['focal_length'] = $this->exif_frac2dec( $exif['FocalLength'] ) . __( ' mm', 'nggallery' ); } if ( ! empty( $exif['ISOSpeedRatings'] ) ) { $meta['iso'] = $exif['ISOSpeedRatings']; } if ( ! empty( $exif['ExposureTime'] ) ) { $meta['shutter_speed'] = $this->exif_frac2dec( $exif['ExposureTime'] ); $meta['shutter_speed'] = ( $meta['shutter_speed'] > 0.0 and $meta['shutter_speed'] < 1.0 ) ? ( '1/' . round( 1 / $meta['shutter_speed'], -1 ) ) : ( $meta['shutter_speed'] ); $meta['shutter_speed'] .= __( ' sec', 'nggallery' ); } // Bit 0 indicates the flash firing status. On some images taken on older iOS versions, this may be // incorrectly stored as an array. if ( isset( $exif['Flash'] ) && is_array( $exif['Flash'] ) ) { $meta['flash'] = __( 'Fired', 'nggallery' ); } elseif ( ! empty( $exif['Flash'] ) ) { $meta['flash'] = ( $exif['Flash'] & 1 ) ? __( 'Fired', 'nggallery' ) : __( 'Not fired', 'nggallery' ); } } // additional information. if ( isset( $this->exif_data['IFD0'] ) ) { $exif = $this->exif_data['IFD0']; if ( ! empty( $exif['Model'] ) ) { $meta['camera'] = $exif['Model']; } if ( ! empty( $exif['Make'] ) ) { $meta['make'] = $exif['Make']; } if ( ! empty( $exif['ImageDescription'] ) ) { $meta['title'] = $this->utf8_encode( $exif['ImageDescription'] ); } if ( ! empty( $exif['Orientation'] ) ) { $meta['Orientation'] = $exif['Orientation']; } } // this is done by Windows. if ( isset( $this->exif_data['WINXP'] ) ) { $exif = $this->exif_data['WINXP']; if ( ! empty( $exif['Title'] ) && empty( $meta['title'] ) ) { $meta['title'] = $this->utf8_encode( $exif['Title'] ); } if ( ! empty( $exif['Author'] ) ) { $meta['author'] = $this->utf8_encode( $exif['Author'] ); } if ( ! empty( $exif['Keywords'] ) ) { $meta['keywords'] = $this->utf8_encode( $exif['Keywords'] ); } if ( ! empty( $exif['Subject'] ) ) { $meta['subject'] = $this->utf8_encode( $exif['Subject'] ); } if ( ! empty( $exif['Comments'] ) ) { $meta['caption'] = $this->utf8_encode( $exif['Comments'] ); } } $this->exif_array = $meta; } // return one element if requested. if ( $object == true ) { $value = isset( $this->exif_array[ $object ] ) ? $this->exif_array[ $object ] : false; return $value; } // on request sanitize the output. if ( $this->sanitize == true ) { array_walk( $this->exif_array, 'esc_html' ); } return $this->exif_array; } // convert a fraction string to a decimal. public function exif_frac2dec( $str ) { @list( $n, $d ) = explode( '/', $str ); if ( ! empty( $d ) ) { return $n / $d; } return $str; } // convert the exif date format to a unix timestamp. public function exif_date2ts( $str ) { $retval = is_numeric( $str ) ? $str : @strtotime( $str ); if ( ! $retval && $str ) { @list( $date, $time ) = explode( ' ', trim( $str ) ); @list( $y, $m, $d ) = explode( ':', $date ); $retval = strtotime( "{$y}-{$m}-{$d} {$time}" ); } return $retval; } /** * nggMeta::readIPTC() - IPTC Data Information for EXIF Display * * @param object $object (optional) * @return null|bool|array */ public function get_IPTC( $object = false ) { if ( ! $this->iptc_data ) { return false; } if ( ! is_array( $this->iptc_array ) ) { // --------- Set up Array Functions --------- // $iptcTags = [ '2#005' => 'title', '2#007' => 'status', '2#012' => 'subject', '2#015' => 'category', '2#025' => 'keywords', '2#055' => 'created_date', '2#060' => 'created_time', '2#080' => 'author', '2#085' => 'position', '2#090' => 'city', '2#092' => 'location', '2#095' => 'state', '2#100' => 'country_code', '2#101' => 'country', '2#105' => 'headline', '2#110' => 'credit', '2#115' => 'source', '2#116' => 'copyright', '2#118' => 'contact', '2#120' => 'caption', ]; $meta = []; foreach ( $iptcTags as $key => $value ) { if ( isset( $this->iptc_data[ $key ] ) ) { $meta[ $value ] = trim( $this->utf8_encode( implode( ', ', $this->iptc_data[ $key ] ) ) ); } } $this->iptc_array = $meta; } // return one element if requested. if ( $object ) { return ( isset( $this->iptc_array[ $object ] ) ) ? $this->iptc_array[ $object ] : null; } // on request sanitize the output. if ( $this->sanitize == true ) { array_walk( $this->iptc_array, 'esc_html' ); } return $this->iptc_array; } /** * nggMeta::extract_XMP() * get XMP DATA * code by Pekka Saarinen http://photography-on-the.net * * @param mixed $filename * @return bool|string */ public function extract_XMP( $filename ) { // TODO:Require a lot of memory, could be better. ob_start(); @readfile( $filename ); $source = ob_get_contents(); ob_end_clean(); $start = strpos( $source, '<x:xmpmeta' ); $end = strpos( $source, '</x:xmpmeta>' ); if ( ( ! $start === false ) && ( ! $end === false ) ) { $lenght = $end - $start; $xmp_data = substr( $source, $start, $lenght + 12 ); unset( $source ); return $xmp_data; } unset( $source ); return false; } /** * nggMeta::get_XMP() * * @package Taken from http://php.net/manual/en/function.xml-parse-into-struct.php * @author Alf Marius Foss Olsen & Alex Rabe * @return bool|array */ public function get_XMP( $object = false ) { if ( ! $this->xmp_data ) { return false; } if ( ! is_array( $this->xmp_array ) ) { $parser = xml_parser_create(); xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 ); // Dont mess with my cAsE sEtTings. xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 ); // Dont bother with empty info. xml_parse_into_struct( $parser, $this->xmp_data, $values ); xml_parser_free( $parser ); $xmlarray = []; // The XML array. $this->xmp_array = []; // The returned array. $stack = []; // tmp array used for stacking. $list_array = []; // tmp array for list elements. $list_element = false; // rdf:li indicator. foreach ( $values as $val ) { if ( $val['type'] == 'open' ) { array_push( $stack, $val['tag'] ); } elseif ( $val['type'] == 'close' ) { // reset the compared stack. if ( $list_element == false ) { array_pop( $stack ); } // reset the rdf:li indicator & array. $list_element = false; $list_array = []; } elseif ( $val['type'] == 'complete' ) { if ( $val['tag'] == 'rdf:li' ) { // first go one element back. if ( $list_element == false ) { array_pop( $stack ); } $list_element = true; // do not parse empty tags. if ( empty( $val['value'] ) ) { continue; } // save it in our temp array. $list_array[] = $val['value']; // in the case it's a list element we seralize it. $value = implode( ',', $list_array ); $this->setArrayValue( $xmlarray, $stack, $value ); } else { array_push( $stack, $val['tag'] ); // do not parse empty tags. if ( ! empty( $val['value'] ) ) { $this->setArrayValue( $xmlarray, $stack, $val['value'] ); } array_pop( $stack ); } } } // foreach // don't parse a empty array. if ( empty( $xmlarray ) || empty( $xmlarray['x:xmpmeta'] ) ) { return false; } // cut off the useless tags. $xmlarray = $xmlarray['x:xmpmeta']['rdf:RDF']['rdf:Description']; // --------- Some values from the XMP format--------- // $xmpTags = [ 'xap:CreateDate' => 'created_timestamp', 'xap:ModifyDate' => 'last_modfied', 'xap:CreatorTool' => 'tool', 'dc:format' => 'format', 'dc:title' => 'title', 'dc:creator' => 'author', 'dc:subject' => 'keywords', 'dc:description' => 'caption', 'photoshop:AuthorsPosition' => 'position', 'photoshop:City' => 'city', 'photoshop:Country' => 'country', ]; foreach ( $xmpTags as $key => $value ) { // if the kex exist. if ( isset( $xmlarray[ $key ] ) ) { switch ( $key ) { case 'xap:CreateDate': case 'xap:ModifyDate': $this->xmp_array[ $value ] = strtotime( $xmlarray[ $key ] ); break; default: $this->xmp_array[ $value ] = $xmlarray[ $key ]; } } } } // return one element if requested. if ( $object != false ) { return isset( $this->xmp_array[ $object ] ) ? $this->xmp_array[ $object ] : false; } // on request sanitize the output. if ( $this->sanitize == true ) { array_walk( $this->xmp_array, 'esc_html' ); } return $this->xmp_array; } public function setArrayValue( &$array, $stack, $value ) { if ( $stack ) { $key = array_shift( $stack ); $this->setArrayValue( $array[ $key ], $stack, $value ); return $array; } else { $array = $value; } return $array; } /** * nggMeta::get_META() - return a meta value form the available list * * @param string $object * @return mixed $value */ public function get_META( $object = false ) { if ( $value = $this->get_saved_meta( $object ) ) { return $value; } if ( $object == 'created_timestamp' && ( $d = $this->get_IPTC( 'created_date' ) ) && ( $t = $this->get_IPTC( 'created_time' ) ) ) { return $this->exif_date2ts( $d . ' ' . $t ); } $order = apply_filters( 'ngg_metadata_parse_order', [ 'XMP', 'IPTC', 'EXIF' ] ); foreach ( $order as $method ) { $method = 'get_' . $method; if ( method_exists( $this, $method ) && $value = $this->$method( $object ) ) { return $value; } } return false; } /** * nggMeta::i8n_name() - localize the tag name * * @param mixed $key * @return string Translated $key */ public function i18n_name( $key ) { $tagnames = [ 'aperture' => __( 'Aperture', 'nggallery' ), 'author' => __( 'Author', 'nggallery' ), 'camera' => __( 'Camera', 'nggallery' ), 'caption' => __( 'Caption', 'nggallery' ), 'category' => __( 'Category', 'nggallery' ), 'city' => __( 'City', 'nggallery' ), 'contact' => __( 'Contact', 'nggallery' ), 'copyright' => __( 'Copyright Notice', 'nggallery' ), 'country' => __( 'Country', 'nggallery' ), 'country_code' => __( 'Country code', 'nggallery' ), 'created_date' => __( 'Date Created', 'nggallery' ), 'created_time' => __( 'Time Created', 'nggallery' ), 'created_timestamp' => __( 'Date/Time', 'nggallery' ), 'credit' => __( 'Credit', 'nggallery' ), 'flash' => __( 'Flash', 'nggallery' ), 'focal_length' => __( 'Focal length', 'nggallery' ), 'format' => __( 'Format', 'nggallery' ), 'headline' => __( 'Headline', 'nggallery' ), 'height' => __( 'Image Height', 'nggallery' ), 'iso' => __( 'ISO', 'nggallery' ), 'keywords' => __( 'Keywords', 'nggallery' ), 'last_modfied' => __( 'Last modified', 'nggallery' ), 'location' => __( 'Location', 'nggallery' ), 'make' => __( 'Make', 'nggallery' ), 'position' => __( 'Author Position', 'nggallery' ), 'shutter_speed' => __( 'Shutter speed', 'nggallery' ), 'source' => __( 'Source', 'nggallery' ), 'state' => __( 'Province/State', 'nggallery' ), 'status' => __( 'Edit Status', 'nggallery' ), 'subject' => __( 'Subject', 'nggallery' ), 'tags' => __( 'Tags', 'nggallery' ), 'title' => __( 'Title', 'nggallery' ), 'tool' => __( 'Program tool', 'nggallery' ), 'width' => __( 'Image Width', 'nggallery' ), ]; if ( isset( $tagnames[ $key ] ) ) { $key = $tagnames[ $key ]; } return( $key ); } /** * Return the Timestamp from the image , if possible it's read from exif data * * @return string */ public function get_date_time() { // Try getting the created_timestamp field. $date = $this->exif_date2ts( $this->get_META( 'created_timestamp' ) ); if ( ! $date ) { $image_path = Manager::get_instance()->get_backup_abspath( $this->image ); $date = @filectime( $image_path ); } // Failback. if ( ! $date ) { $date = time(); } // Return the MySQL format. $date_time = date( 'Y-m-d H:i:s', $date ); return $date_time; } /** * This function return the most common metadata, via a filter we can add more * Reason : GD manipulation removes that options * * @since V1.4.0 * @return array|false */ public function get_common_meta() { global $wpdb; $meta = [ 'aperture' => 0, 'credit' => '', 'camera' => '', 'caption' => '', 'created_timestamp' => 0, 'copyright' => '', 'focal_length' => 0, 'iso' => 0, 'shutter_speed' => 0, 'flash' => 0, 'title' => '', 'keywords' => '', ]; $meta = apply_filters( 'ngg_read_image_metadata', $meta ); // meta should be still an array. if ( ! is_array( $meta ) ) { return false; } foreach ( $meta as $key => $value ) { $meta[ $key ] = $this->get_META( $key ); } // let's add now the size of the image. $meta['width'] = $this->size[0]; $meta['height'] = $this->size[1]; return $meta; } /** * If needed sanitize each value before output * * @return void */ public function sanitize() { $this->sanitize = true; } /** * Wrapper to utf8_encode() that avoids double encoding * * Regex adapted from http://www.w3.org/International/questions/qa-forms-utf-8.en.php * to determine if the given string is already UTF-8. mb_detect_encoding() is not * always available and is limited in accuracy * * @param string $str * @return string */ public function utf8_encode( $str ) { $is_utf8 = preg_match( '%^(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*$%xs', $str ); if ( ! $is_utf8 ) { utf8_encode( $str ); } return $str; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayType/Controller.php��������������������������������������������������������������������������0000644�����������������00000054567�15021223045�0011662 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayType; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DataTypes\{DisplayType, DisplayedGallery, LegacyImage, LegacyImageCollection}; use Imagely\NGG\Display\{DisplayManager, LightboxManager, StaticAssets}; use Imagely\NGG\DisplayedGallery\{Renderer, TriggerManager}; use Imagely\NGG\Util\{Filesystem, Router, Transient}; class Controller { public $run_once = false; public static $alternate_displayed_galleries = []; /** * @deprecated This method is only used by NextGEN Pro * @param DisplayedGallery $displayed_gallery * @return bool */ public function enqueue_displayed_gallery_trigger_buttons_resources( $displayed_gallery = false ) { $retval = false; DisplayManager::enqueue_fontawesome(); if ( ! $this->run_once && ! empty( $displayed_gallery ) && ! empty( $displayed_gallery->display_settings['ngg_triggers_display'] ) && $displayed_gallery->display_settings['ngg_triggers_display'] !== 'never' ) { $pro_active = false; if ( defined( 'NGG_PRO_PLUGIN_VERSION' ) ) { $pro_active = 'NGG_PRO_PLUGIN_VERSION'; } if ( defined( 'NEXTGEN_GALLERY_PRO_VERSION' ) ) { $pro_active = 'NEXTGEN_GALLERY_PRO_VERSION'; } if ( ! empty( $pro_active ) ) { $pro_active = constant( $pro_active ); } if ( ! is_admin() && ( empty( $pro_active ) || version_compare( $pro_active, '1.0.11' ) >= 0 ) ) { \wp_enqueue_style( 'fontawesome' ); $retval = true; $this->run_once = true; } } return $retval; } public function is_cachable() { return true; } public function enqueue_pagination_resources() { wp_enqueue_style( 'nextgen_pagination_style', StaticAssets::get_url( 'GalleryDisplay/pagination_style.css', 'photocrati-nextgen_pagination#style.css' ), [], NGG_SCRIPT_VERSION ); } public function enqueue_frontend_resources( $displayed_gallery ) { // This script provides common JavaScript among all display types. \wp_enqueue_script( 'ngg_common' ); \wp_add_inline_script( 'ngg_common', ' var nggLastTimeoutVal = 1000; var nggRetryFailedImage = function(img) { setTimeout(function(){ img.src = img.src; }, nggLastTimeoutVal); nggLastTimeoutVal += 500; }' ); // Add "galleries = {};". DisplayManager::add_script_data( 'ngg_common', 'galleries', new \stdClass(), true, false ); // Add "galleries.gallery_1 = {};".. DisplayManager::add_script_data( 'ngg_common', 'galleries.gallery_' . $displayed_gallery->id(), (array) $displayed_gallery->get_entity(), false ); DisplayManager::add_script_data( 'ngg_common', 'galleries.gallery_' . $displayed_gallery->id() . '.wordpress_page_root', get_permalink(), false ); // Enqueue trigger button resources. TriggerManager::get_instance()->enqueue_resources( $displayed_gallery ); // Enqueue the selected lightbox. LightboxManager::get_instance()->enqueue(); $this->enqueue_displayed_gallery_trigger_buttons_resources( $displayed_gallery ); if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { \C_Display_Type_Controller::get_instance()->enqueue_frontend_resources( $displayed_gallery, false ); } \do_action( 'ngg_display_type_controller_enqueue_frontend_resources', $displayed_gallery ); } public function get_template_directory_name(): string { return ''; } /** * Allows the admin forms that display available templates to limit the selection to one directory. */ public function get_template_directory_abspath(): string { return path_join( NGG_PLUGIN_DIR, 'templates' . DIRECTORY_SEPARATOR . $this->get_template_directory_name() ); } public function get_preview_image_url() { return ''; } /** * Ensures that the minimum configuration of parameters are sent to a view * * @param DisplayedGallery $displayed_gallery * @param null|array $params * @return array|null */ public function prepare_display_parameters( $displayed_gallery, $params = null ) { if ( $params == null ) { $params = []; } $params['display_type_rendering'] = true; $params['displayed_gallery'] = $displayed_gallery; return $params; } /** * Renders the frontend display of the display type * * @param bool $return (optional) * @return string */ public function index_action( $displayed_gallery, $return = false ) { return ''; } /** * This effectively busts the standard template rendering cache * * @param DisplayedGallery $displayed_gallery * @return string Rendered HTML */ public function cache_action( $displayed_gallery ) { return ''; } /** * Returns the effect "effect code" used to inject lightbox attributes into image anchor elements * * @return string */ public function get_effect_code( $displayed_gallery, $legacy_compat = true ) { global $post; $retval = ''; $lightbox = LightboxManager::get_instance()->get_selected(); if ( 'arifancybox' === $lightbox->name ) { return apply_filters( 'ngg_effect_code', $lightbox->code, $displayed_gallery ); } if ( $lightbox->is_supported( $displayed_gallery ) ) { $retval = $lightbox->code; $retval = str_replace( '%GALLERY_ID%', $displayed_gallery->id(), $retval ); $retval = str_replace( '%GALLERY_NAME%', $displayed_gallery->id(), $retval ); if ( $post && isset( $post->ID ) && $post->ID ) { $retval = str_replace( '%PAGE_ID%', $post->ID, $retval ); } } if ( $legacy_compat && \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $retval = \C_Display_Type_Controller::get_instance()->get_effect_code( $displayed_gallery ); } return apply_filters( 'ngg_effect_code', $retval, $displayed_gallery ); } /** * Returns the longest and widest dimensions from a list of entities. Only used by Pro Film. * * @param $entities * @param $named_size * @param bool $style_images Unused * @deprecated This should be moved into the Pro Film controller and removed when POPE-compat level 1 is reached * @return array */ public function get_entity_statistics( $entities, $named_size, $style_images = false ) { $longest = $widest = 0; $storage = StorageManager::get_instance(); $image_mapper = ImageMapper::get_instance(); foreach ( $entities as $entity ) { $image = null; if ( isset( $entity->pid ) ) { $image = $entity; } elseif ( isset( $entity->previewpic ) ) { $image = $image_mapper->find( $entity->previewpic ); } // Once we have the image, get its dimensions. if ( $image ) { $dimensions = $storage->get_image_dimensions( $image, $named_size ); if ( $dimensions['width'] > $widest ) { $widest = $dimensions['width']; } if ( $dimensions['height'] > $longest ) { $longest = $dimensions['height']; } } } return [ 'entities' => $entities, 'longest' => $longest, 'widest' => $widest, ]; } /** * Finds the absolute path of template given file name and list of possible directories * * @param string $template * @param array $params * @return string $template */ public function get_display_type_view_abspath( $template, $params ) { // Identify display type and display_type_view. $displayed_gallery = $params['displayed_gallery']; $display_type_name = $params['displayed_gallery']->display_type; $display_settings = $displayed_gallery->display_settings; $display_type_view = null; if ( isset( $display_settings['display_type_view'] ) ) { $display_type_view = $display_settings['display_type_view']; } if ( isset( $display_settings['display_view'] ) ) { $display_type_view = $display_settings['display_view']; } if ( $display_type_view && $display_type_view != 'default' ) { /* * A display type view or display template value looks like this: * * "default" * "imagebrowser-dark-template.php" ("default" category is implicit) * "custom/customized-template.php" ("custom" category is explicit) * * Templates can be found in multiple directories, and each directory is given * a key, which is used to distinguish it's "category". */ $fs = Filesystem::get_instance(); /* Fetch array of template directories */ $dirs = DisplayManager::get_display_type_view_dirs( $display_type_name ); // Add the missing "default" category name prefix to the template to make it more consistent to evaluate. if ( strpos( $display_type_view, DIRECTORY_SEPARATOR ) === false ) { $display_type_view = join( DIRECTORY_SEPARATOR, [ 'default', $display_type_view ] ); } foreach ( $dirs as $category => $dir ) { $category = preg_quote( $category . DIRECTORY_SEPARATOR ); if ( preg_match( "#^{$category}(.*)$#", $display_type_view, $match ) ) { $display_type_view = $match[1]; $template_abspath = $fs->join_paths( $dir, $display_type_view ); if ( @file_exists( $template_abspath ) ) { $template = $template_abspath; break; } } } } // Return template. If no match is found, returns the original template. return $template; } /** * The basic thumbnails and slideshow have options to display galleries with the other display type, and albums * of course display child of an entirely different kind. Implementing this method allows displays to alter * the displayed gallery passed to their index_action() method. * * @param DisplayedGallery $displayed_gallery * @return DisplayedGallery */ public function get_alternative_displayed_gallery( $displayed_gallery ) { return $displayed_gallery; } public function set_alternative_displayed_gallery( array $params, DisplayedGallery $displayed_gallery, string $new_display_type ): DisplayedGallery { // Render the new display type. $renderer = Renderer::get_instance(); $params['original_display_type'] = $displayed_gallery->display_type; $params['original_settings'] = $displayed_gallery->display_settings; $params['display_type'] = $new_display_type; $params['display_settings'] = []; $id = $displayed_gallery->id(); $alt_displayed_gallery = $renderer->params_to_displayed_gallery( $params ); if ( is_null( $alt_displayed_gallery->id() ) ) { $alt_displayed_gallery->id( md5( json_encode( $alt_displayed_gallery->get_entity() ) ) ); } self::$alternate_displayed_galleries[ $id ] = $alt_displayed_gallery; return self::$alternate_displayed_galleries[ $id ]; } /** * Renders legacy NextGen templates * * @param string $template_name File name * @param array $vars (optional) Specially formatted array of parameters * @param bool $return (optional) * @param string $prefix (optional) * @return string */ public function legacy_render( $template_name, $vars = [], $return = false, $prefix = null ) { $retval = '[Not a valid template]'; $template_locator = LegacyTemplateLocator::get_instance(); // search first for files with their prefix. $template_abspath = $template_locator->find( $prefix . '-' . $template_name ); if ( ! $template_abspath ) { $template_abspath = $template_locator->find( $template_name ); } if ( $template_abspath ) { // render the template. extract( $vars ); if ( $return ) { ob_start(); } include $template_abspath; if ( $return ) { $retval = ob_get_contents(); ob_end_clean(); } } return $retval; } /** * Returns the parameter objects necessary for legacy template rendering using legacy_render() * * @param array $images * @param DisplayedGallery $displayed_gallery * @param array $params * * @return array */ public function prepare_legacy_parameters( $images, $displayed_gallery, $params = [] ) { // setup. $image_map = ImageMapper::get_instance(); $gallery_map = GalleryMapper::get_instance(); $image_key = $image_map->get_primary_key_column(); $gallery_id = $displayed_gallery->id(); $pid = Router::get_instance()->get_routed_app()->get_parameter( 'pid' ); // because picture_list implements ArrayAccess any array-specific actions must be taken on // $picture_list->container or they won't do anything. $picture_list = new LegacyImageCollection(); $current_pid = null; // begin processing. $current_page = ( @\get_the_ID() == false ) ? 0 : @\get_the_ID(); // determine what the "current image" is; used mostly for carousel. if ( ! is_numeric( $pid ) && ! empty( $pid ) ) { $picture = $image_map->find_first( [ 'image_slug = %s', $pid ] ); $pid = $picture->$image_key; } // create our new wrappers. foreach ( $images as &$image ) { if ( $image && isset( $params['effect_code'] ) ) { if ( is_object( $image ) ) { $image->thumbcode = $params['effect_code']; } elseif ( is_array( $image ) ) { $image['thumbcode'] = $params['effect_code']; } } $new_image = new LegacyImage( $image, $displayed_gallery ); if ( $pid == $new_image->$image_key ) { $current_pid = $new_image; } $picture_list[] = $new_image; } reset( $picture_list->container ); // assign current_pid. $current_pid = ( is_null( $current_pid ) ) ? current( $picture_list->container ) : $current_pid; foreach ( $picture_list as &$image ) { if ( isset( $image->hidden ) && $image->hidden ) { $tmp = $displayed_gallery->display_settings['number_of_columns']; $image->style = ( $tmp > 0 ) ? 'style="width:' . floor( 100 / $tmp ) . '%;display: none;"' : 'style="display: none;"'; } } // find our gallery to build the new one on. $orig_gallery = $gallery_map->find( current( $picture_list->container )->galleryid ); // create the 'gallery' object. $gallery = new \stdclass(); $gallery->ID = $displayed_gallery->id(); $gallery->name = stripslashes( $orig_gallery->name ); $gallery->title = stripslashes( $orig_gallery->title ); $gallery->description = \html_entity_decode( \stripslashes( $orig_gallery->galdesc ) ); $gallery->pageid = $orig_gallery->pageid; $gallery->anchor = 'ngg-gallery-' . $gallery_id . '-' . $current_page; $gallery->displayed_gallery = &$displayed_gallery; $gallery->columns = @intval( $displayed_gallery->display_settings['number_of_columns'] ); $gallery->imagewidth = ( $gallery->columns > 0 ) ? 'style="width:' . floor( 100 / $gallery->columns ) . '%;"' : ''; if ( ! empty( $displayed_gallery->display_settings['show_slideshow_link'] ) ) { $gallery->show_slideshow = true; $gallery->slideshow_link = $params['slideshow_link']; $gallery->slideshow_link_text = $displayed_gallery->display_settings['slideshow_link_text']; } else { $gallery->show_slideshow = false; } $gallery = apply_filters( 'ngg_gallery_object', $gallery, 4 ); // build our array of things to return. $return = [ 'gallery' => $gallery ]; // single_image is an internally added flag. if ( ! empty( $params['single_image'] ) ) { $return['image'] = $picture_list[0]; } else { $return['current'] = $current_pid; $return['images'] = $picture_list->container; } // this is expected to always exist. if ( ! empty( $params['pagination'] ) ) { $return['pagination'] = $params['pagination']; } else { $return['pagination'] = null; } if ( ! empty( $params['next'] ) ) { $return['next'] = $params['next']; } else { $return['next'] = false; } if ( ! empty( $params['prev'] ) ) { $return['prev'] = $params['prev']; } else { $return['prev'] = false; } return $return; } /** * Returns an url to view the displayed gallery using an alternate display type * * @param DisplayedGallery $displayed_gallery * @param string $display_type * @return string */ public function get_url_for_alternate_display_type( $displayed_gallery, $display_type, $origin_url = false ) { $app = Router::get_instance()->get_routed_app(); if ( ! $origin_url && ! empty( $displayed_gallery->display_settings['original_display_type'] ) && ! empty( $_SERVER['NGG_ORIG_REQUEST_URI'] ) ) { $origin_url = $_SERVER['NGG_ORIG_REQUEST_URI']; } $url = ( $origin_url ?: $app->get_app_url( false, true ) ); $url = $app->remove_parameter( 'show', $displayed_gallery->id(), $url ); $url = $app->set_parameter( 'show', $display_type, $displayed_gallery->id(), false, $url ); return $url; } /** * Returns a formatted HTML string of a pagination widget * * @param mixed $selected_page * @param int $number_of_entities * @param int $entities_per_page * @param string|null $current_url (optional) * @return array Of data holding prev & next url locations and a formatted HTML string */ public function create_pagination( $selected_page, $number_of_entities, $entities_per_page = 0, $current_url = null ) { $router = Router::get_instance(); $app = $router->get_routed_app(); $prev_symbol = \apply_filters( 'ngg_prev_symbol', '◄' ); $next_symbol = \apply_filters( 'ngg_next_symbol', '►' ); if ( empty( $current_url ) ) { $current_url = $app->get_app_url( false, true ); if ( \is_archive() ) { $id = \get_the_ID(); if ( $id == null ) { global $post; $id = $post ? $post->ID : null; } if ( $id != null && \in_the_loop() ) { $current_url = \get_permalink( $id ); } } } // Early exit. $return = [ 'prev' => '', 'next' => '', 'output' => "<div class='ngg-clear'></div>", ]; if ( $entities_per_page <= 0 || $number_of_entities <= 0 ) { return $return; } // Construct array of page urls. $ending_ellipsis = $starting_ellipsis = false; $number_of_pages = ceil( $number_of_entities / $entities_per_page ); $pages = []; for ( $i = 1; $i <= $number_of_pages; $i++ ) { if ( $selected_page === $i ) { $pages['current'] = "<span class='current'>{$i}</span>"; } else { $link = esc_attr( $app->set_parameter( 'nggpage', $i, null, false, $current_url ) ); $pages[ $i ] = "<a class='page-numbers' data-pageid='{$i}' href='{$link}'>{$i}</a>"; } } $after = $this->array_slice_from( 'current', $pages ); if ( count( $after ) > 3 ) { $after = array_merge( $this->array_take_from_start( 2, $after ), [ "<span class='ellipsis'>...</span>" ], $this->array_take_from_end( 1, $after ) ); } $before = $this->array_slice_to( 'current', $pages ); if ( count( $before ) > 3 ) { $before = array_merge( $this->array_take_from_start( 1, $before ), [ "<span class='ellipsis'>...</span>" ], $this->array_take_from_end( 2, $before ) ); array_pop( $before ); } $pages = array_merge( $before, $after ); if ( $pages && count( $pages ) > 1 ) { // Next page. if ( $selected_page + 1 <= $number_of_pages ) { $next_page = $selected_page + 1; $link = $return['next'] = $app->set_parameter( 'nggpage', $next_page, null, false, $current_url ); $pages[] = "<a class='prev' href='{$link}' data-pageid={$next_page}>{$next_symbol}</a>"; } // Prev page. if ( $selected_page - 1 > 0 ) { $prev_page = $selected_page - 1; $link = $return['next'] = $app->set_parameter( 'nggpage', $prev_page, null, false, $current_url ); array_unshift( $pages, "<a class='next' href='{$link}' data-pageid={$prev_page}>{$prev_symbol}</a>" ); } $return['output'] = "<div class='ngg-navigation'>" . implode( "\n", $pages ) . '</div>'; } return $return; } /** * This is necessary for the SinglePicture display type. * * @return false */ public function is_hidden_from_igw() { return false; } public function array_slice_from( $find_key, $arr ) { $retval = []; reset( $arr ); foreach ( $arr as $key => $value ) { if ( $key == $find_key || $retval ) { $retval[ $key ] = $value; } } reset( $arr ); return $retval; } public function array_slice_to( $find_key, $arr ) { $retval = []; reset( $arr ); foreach ( $arr as $key => $value ) { $retval[ $key ] = $value; if ( $key == $find_key ) { break; } } reset( $arr ); return $retval; } public function array_take_from_start( $number, $arr ) { $retval = []; foreach ( $arr as $key => $value ) { if ( count( $retval ) < $number ) { $retval[ $key ] = $value; } else { break; } } return $retval; } public function array_take_from_end( $number, $arr ) { return array_reverse( $this->array_take_from_start( $number, array_reverse( $arr ) ) ); } /* The following methods manage the installation and removal of display types */ /** * @param $name */ public function delete_duplicates( $name ) { $mapper = DisplayTypeMapper::get_instance(); $results = $mapper->find_all( [ 'name = %s', $name ] ); if ( count( $results ) > 0 ) { array_pop( $results ); // the last should be the latest. foreach ( $results as $display_type ) { $mapper->destroy( $display_type ); } } $mapper->flush_query_cache(); } /** * Method for installing a display type. * * @param string $name Display type name. * @param array $properties Display type properties. * @param bool $reset True: revert to default setting. * @return bool|int */ public function install_display_type( string $name, array $properties = [], bool $reset = false ) { $this->delete_duplicates( $name ); // Try to find the existing entity. If it doesn't exist, we'll create. $mapper = DisplayTypeMapper::get_instance(); $display_type = $mapper->find_by_name( $name ); $mapper->flush_query_cache(); if ( ! $display_type ) { $display_type = new DisplayType(); } // Update the properties of the display type. $properties['name'] = $name; $changed = false; foreach ( $properties as $key => $val ) { if ( ! isset( $display_type->$key ) || empty( $display_type->$key ) || is_null( $display_type->$key ) || $reset ) { $display_type->$key = $val; $changed = true; } } // Save the entity. if ( $changed ) { return $mapper->save( $display_type ); } return false; } /** * Uninstalls all display types */ public function uninstall_display_types() { $mapper = DisplayTypeMapper::get_instance(); $mapper->delete()->run_query(); } /** * @param bool $reset (optional) Unused */ public function install( $reset = false ) { } /** * @param bool $hard (optional) Unused */ public function uninstall( $hard = false ) { Transient::flush(); $this->uninstall_display_types(); } public function get_default_settings() { return []; } } �����������������������������������������������������������������������������������������������������������������������������������������DisplayType/Manager.php�����������������������������������������������������������������������������0000644�����������������00000022005�15021223045�0011067 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayType; use Imagely\NGG\DisplayTypes\Taxonomy; use Imagely\NGG\Display\Shortcodes; use Imagely\NGG\Settings\Settings; class Manager { public static function register() { ControllerFactory::register_controller( 'photocrati-nextgen_basic_imagebrowser', '\Imagely\NGG\DisplayTypes\ImageBrowser', [ // Aliases. 'imagebrowser', 'basic_imagebrowser', 'nextgen_basic_imagebrowser', ] ); ControllerFactory::register_controller( 'photocrati-nextgen_basic_singlepic', '\Imagely\NGG\DisplayTypes\SinglePicture', [ 'singlepicture', 'singlepic', 'basic_singlepic', 'nextgen_basic_singlepic', ] ); ControllerFactory::register_controller( 'photocrati-nextgen_basic_tagcloud', '\Imagely\NGG\DisplayTypes\TagCloud', [ 'tagcloud', 'basic_tagcloud', 'nextgen_basic_tagcloud', ] ); ControllerFactory::register_controller( 'photocrati-nextgen_basic_thumbnails', '\Imagely\NGG\DisplayTypes\Thumbnails', [ 'basic_thumbnails', 'nextgen_basic_thumbnails', ] ); ControllerFactory::register_controller( 'photocrati-nextgen_basic_slideshow', '\Imagely\NGG\DisplayTypes\Slideshow', [ 'basic_slideshow', 'nextgen_basic_slideshow', ] ); ControllerFactory::register_controller( 'photocrati-nextgen_basic_compact_album', '\Imagely\NGG\DisplayTypes\CompactAlbum', [ 'compact_album', 'basic_album_compact', 'basic_compact_album', 'nextgen_basic_album', ] ); ControllerFactory::register_controller( 'photocrati-nextgen_basic_extended_album', '\Imagely\NGG\DisplayTypes\ExtendedAlbum', [ 'extended_album', 'basic_extended_album', 'nextgen_basic_extended_album', ] ); $self = new Manager(); if ( ! defined( 'NGG_DISABLE_LEGACY_SHORTCODES' ) || ! NGG_DISABLE_LEGACY_SHORTCODES ) { Shortcodes::add( 'imagebrowser', null, [ $self, 'render_legacy_imagebrowser_shortcode' ] ); Shortcodes::add( 'nggimagebrowser', null, [ $self, 'render_legacy_imagebrowser_shortcode' ] ); Shortcodes::add( 'singlepic', null, [ $self, 'render_legacy_single_picture_shortcode' ] ); Shortcodes::add( 'nggsinglepic', null, [ $self, 'render_legacy_single_picture_shortcode' ] ); Shortcodes::add( 'tagcloud', null, [ $self, 'render_legacy_tag_cloud_shortcode' ] ); Shortcodes::add( 'nggtagcloud', null, [ $self, 'render_legacy_tag_cloud_shortcode' ] ); Shortcodes::add( 'random', null, [ $self, 'render_legacy_random_images' ] ); Shortcodes::add( 'recent', null, [ $self, 'render_legacy_recent_images' ] ); Shortcodes::add( 'thumb', null, [ $self, 'render_legacy_thumb_shortcode' ] ); Shortcodes::add( 'slideshow', null, [ $self, 'render_legacy_slideshow' ] ); Shortcodes::add( 'nggallery', null, [ $self, 'render_legacy_nggallery' ] ); Shortcodes::add( 'nggtags', null, [ $self, 'render_legacy_based_on_tags' ] ); Shortcodes::add( 'nggslideshow', null, [ $self, 'render_legacy_slideshow' ] ); Shortcodes::add( 'nggrandom', null, [ $self, 'render_legacy_random_images' ] ); Shortcodes::add( 'nggrecent', null, [ $self, 'render_legacy_recent_images' ] ); Shortcodes::add( 'nggthumb', null, [ $self, 'render_legacy_thumb_shortcode' ] ); Shortcodes::add( 'album', null, [ $self, 'render_legacy_album_shortcode' ] ); Shortcodes::add( 'nggalbum', null, [ $self, 'render_legacy_album_shortcode' ] ); if ( ! Settings::get_instance()->get( 'disable_ngg_tags_page', false ) ) { \add_filter( 'the_posts', [ Taxonomy::get_instance(), 'detect_ngg_tag' ], -10, 2 ); } } \do_action( 'ngg_register_display_types' ); \add_action( 'ngg_routes', [ $self, 'define_routes' ] ); } public function define_routes( $router ) { $slug = '/' . Settings::get_instance()->get( 'router_param_slug', 'nggallery' ); // ImageBrowser. $router->rewrite( "{*}{$slug}{*}/image/{\\w}", "{1}{$slug}{2}/pid--{3}" ); // TagCloud. $router->rewrite( "{*}{$slug}{*}/tags/{\\w}{*}", "{1}{$slug}{2}/gallerytag--{3}{4}" ); // Thumbnails, Slideshow. $router->rewrite( "{*}{$slug}{*}/image/{*}", "{1}{$slug}{2}/pid--{3}" ); $router->rewrite( "{*}{$slug}{*}/slideshow/{*}", "{1}{$slug}{2}/show--" . NGG_BASIC_SLIDESHOW . '/{3}' ); $router->rewrite( "{*}{$slug}{*}/thumbnails/{*}", "{1}{$slug}{2}/show--" . NGG_BASIC_THUMBNAILS . '/{3}' ); $router->rewrite( "{*}{$slug}{*}/show--slide/{*}", "{1}{$slug}{2}/show--" . NGG_BASIC_SLIDESHOW . '/{3}' ); $router->rewrite( "{*}{$slug}{*}/show--gallery/{*}", "{1}{$slug}{2}/show--" . NGG_BASIC_THUMBNAILS . '/{3}' ); $router->rewrite( "{*}{$slug}{*}/page/{\\d}{*}", "{1}{$slug}{2}/nggpage--{3}{4}" ); } /** * Gets a value from the parameter array, and if not available, uses the default value * * @param string $name * @param mixed $default * @param array $params * @return mixed */ public function get_param( $name, $default, $params ) { return ( isset( $params[ $name ] ) ) ? $params[ $name ] : $default; } public function render_legacy_album_shortcode( $params ) { $params['source'] = $this->get_param( 'source', 'albums', $params ); $params['container_ids'] = $this->get_param( 'id', null, $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_COMPACT_ALBUM, $params ); unset( $params['id'] ); return $params; } public function render_legacy_imagebrowser_shortcode( $params ) { $params['gallery_ids'] = $this->get_param( 'id', null, $params ); $params['source'] = $this->get_param( 'source', 'galleries', $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_IMAGEBROWSER, $params ); unset( $params['id'] ); return $params; } public function render_legacy_single_picture_shortcode( $params ) { $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_SINGLEPIC, $params ); $params['image_ids'] = $this->get_param( 'id', null, $params ); unset( $params['id'] ); return $params; } public function render_legacy_tag_cloud_shortcode( $params ) { $params['tagcloud'] = $this->get_param( 'tagcloud', 'yes', $params ); $params['source'] = $this->get_param( 'source', 'tags', $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_TAGCLOUD, $params ); return $params; } public function render_legacy_nggallery( $params ) { $params['gallery_ids'] = $this->get_param( 'id', null, $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_THUMBNAILS, $params ); if ( isset( $params['images'] ) ) { $params['images_per_page'] = $this->get_param( 'images', null, $params ); } unset( $params['id'] ); unset( $params['images'] ); return $params; } public function render_legacy_based_on_tags( $params ) { $params['tag_ids'] = $this->get_param( 'gallery', $this->get_param( 'album', [], $params ), $params ); $params['source'] = $this->get_param( 'source', 'tags', $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_THUMBNAILS, $params ); unset( $params['gallery'] ); return $params; } public function render_legacy_random_images( $params ) { $params['source'] = $this->get_param( 'source', 'random', $params ); $params['images_per_page'] = $this->get_param( 'max', null, $params ); $params['disable_pagination'] = $this->get_param( 'disable_pagination', true, $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_THUMBNAILS, $params ); // Inside if because DisplayedGallery->get_entities() doesn't handle NULL container_ids correctly. if ( isset( $params['id'] ) ) { $params['container_ids'] = $this->get_param( 'id', null, $params ); } unset( $params['max'] ); unset( $params['id'] ); return $params; } public function render_legacy_recent_images( $params ) { $params['source'] = $this->get_param( 'source', 'recent', $params ); $params['images_per_page'] = $this->get_param( 'max', null, $params ); $params['disable_pagination'] = $this->get_param( 'disable_pagination', true, $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_THUMBNAILS, $params ); if ( isset( $params['id'] ) ) { $params['container_ids'] = $this->get_param( 'id', null, $params ); } unset( $params['max'] ); unset( $params['id'] ); return $params; } public function render_legacy_thumb_shortcode( $params ) { $params['entity_ids'] = $this->get_param( 'id', null, $params ); $params['source'] = $this->get_param( 'source', 'galleries', $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_THUMBNAILS, $params ); unset( $params['id'] ); return $params; } public function render_legacy_slideshow( $params ) { $params['gallery_ids'] = $this->get_param( 'id', null, $params ); $params['display_type'] = $this->get_param( 'display_type', NGG_BASIC_SLIDESHOW, $params ); $params['gallery_width'] = $this->get_param( 'w', null, $params ); $params['gallery_height'] = $this->get_param( 'h', null, $params ); unset( $params['id'], $params['w'], $params['h'] ); return $params; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayType/LegacyTemplateLocator.php���������������������������������������������������������������0000644�����������������00000010555�15021223045�0013750 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayType; class LegacyTemplateLocator { static $instance = null; /** * @return LegacyTemplateLocator */ static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new LegacyTemplateLocator(); } return self::$instance; } /** * Returns an array of template storing directories * * @return array Template storing directories */ public function get_template_directories() { return apply_filters( 'ngg_legacy_template_directories', [ 'Child Theme' => get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'nggallery' . DIRECTORY_SEPARATOR, 'Parent Theme' => get_template_directory() . DIRECTORY_SEPARATOR . 'nggallery' . DIRECTORY_SEPARATOR, 'NextGEN Legacy' => NGGALLERY_ABSPATH . 'view' . DIRECTORY_SEPARATOR, 'NextGEN Overrides' => implode( DIRECTORY_SEPARATOR, [ WP_CONTENT_DIR, 'ngg', 'legacy', 'templates', ] ), ] ); } /** * Returns an array of all available template files * * @return array All available template files */ public function find_all( $prefix = false ) { $files = []; foreach ( $this->get_template_directories() as $label => $dir ) { $tmp = $this->get_templates_from_dir( $dir, $prefix ); if ( ! $tmp ) { continue; } $files[ $label ] = $tmp; } return $files; } /** * Recursively scans $dir for files ending in .php * * @param string $dir Directory * @return array All php files in $dir */ public function get_templates_from_dir( $dir, $prefix = false ) { if ( ! is_dir( $dir ) ) { return []; } $dir = new \RecursiveDirectoryIterator( $dir ); $iterator = new \RecursiveIteratorIterator( $dir ); // convert single-item arrays to string. if ( is_array( $prefix ) && count( $prefix ) <= 1 ) { $prefix = end( $prefix ); } // we can filter results by allowing a set of prefixes, one prefix, or by showing all available files. if ( is_array( $prefix ) ) { $str = implode( '|', $prefix ); $regex_iterator = new \RegexIterator( $iterator, "/({$str})-.+\\.php$/i", \RecursiveRegexIterator::GET_MATCH ); } elseif ( is_string( $prefix ) ) { $regex_iterator = new \RegexIterator( $iterator, "#(.*)[/\\\\]{$prefix}\\-?.*\\.php$#i", \RecursiveRegexIterator::GET_MATCH ); } else { $regex_iterator = new \RegexIterator( $iterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH ); } $files = []; foreach ( $regex_iterator as $filename ) { $files[] = reset( $filename ); } return $files; } /** * Find a particular template by name * * @param string $template_name * @return string */ public function find( $template_name ) { $template_abspath = false; // Legacy templates may be an absolute path to a file that was moved in NextGEN 3.50. Here we remap the legacy // path to the current one. if ( false !== strpos( $template_name, 'nextgen-gallery/products/photocrati_nextgen/modules/ngglegacy' ) ) { $template_name = str_replace( 'nextgen-gallery/products/photocrati_nextgen/modules/ngglegacy', 'nextgen-gallery/src/Legacy', $template_name ); } // hook into the render feature to allow other plugins to include templates. $custom_template = apply_filters( 'ngg_render_template', false, $template_name ); if ( $custom_template === false ) { $custom_template = $template_name; } // Ensure we have a PHP extension. if ( strpos( $custom_template, '.php' ) === false ) { $custom_template .= '.php'; } // Find the abspath of the template to render. if ( ! @file_exists( $custom_template ) ) { foreach ( $this->get_template_directories() as $dir ) { if ( $template_abspath ) { break; } $filename = implode( DIRECTORY_SEPARATOR, [ rtrim( $dir, '/\\' ), $custom_template ] ); if ( @file_exists( $filename ) ) { $template_abspath = $filename; } elseif ( strpos( $custom_template, '-template' ) === false ) { $filename = implode( DIRECTORY_SEPARATOR, [ rtrim( $dir, '/\\' ), str_replace( '.php', '', $custom_template ) . '-template.php', ] ); if ( @file_exists( $filename ) ) { $template_abspath = $filename; } } } } elseif ( ! preg_match( '#\.\.[/\\\]#', $custom_template ) ) { // An absolute path was already given. $template_abspath = $custom_template; } return $template_abspath; } } ���������������������������������������������������������������������������������������������������������������������������������������������������DisplayType/InstallerProxy.php����������������������������������������������������������������������0000644�����������������00000002000�15021223045�0012505 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayType; /** * This class exists entirely because Pro's Film module extends C_Gallery_Display_Installer (which is now renamed to * \Imagely\NGG\DisplayType\Installer) but lacks the $hard = FALSE parameter in it's uninstall() method which creates * a fatal error. Until Pro no longer uses the legacy class this proxy is used. * * @deprecated * @TODO Remove this when POPE compatibility level one is reached */ class InstallerProxy { static $_proxy = null; public function get_proxy() { if ( ! self::$_proxy ) { self::$_proxy = new Installer(); } return self::$_proxy; } public function install( $reset = false ) { $this->get_proxy()->install( $reset ); } public function uninstall() { $this->get_proxy()->uninstall(); } public function __call( $method, $args ) { try { $klass = new \ReflectionMethod( $this->get_proxy(), $method ); return $klass->invokeArgs( $this->get_proxy(), $args ); } catch ( \Exception $exception ) { return null; } } } DisplayType/ControllerFactory.php�������������������������������������������������������������������0000644�����������������00000002744�15021223045�0013200 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayType; class ControllerFactory { protected static $registration = []; protected static $handlers = []; protected static $instances = []; protected static $mapping = []; /** * @param string $id * @param string $class_name * @return void */ public static function register_controller( $id, $class_name, $aliases = [] ) { self::$registration[ $id ] = $class_name; self::$handlers[ $id ] = $class_name; self::$mapping[ $id ] = $aliases; if ( is_array( $aliases ) ) { foreach ( $aliases as $alias ) { self::$handlers[ $alias ] = $class_name; } } \Imagely\NGG\Util\Installer::add_handler( $id, $class_name ); } public static function get_registered() { return self::$registration; } /** * @param string $id * @return bool */ public static function has_controller( $id ) { return isset( self::$handlers[ $id ] ); } /** * @param string $id * @return Controller|void */ public static function get_controller( $id ) { if ( ! self::has_controller( $id ) ) { return; } if ( ! isset( self::$instances[ $id ] ) ) { self::$instances[ $id ] = new self::$handlers[ $id ](); } return self::$instances[ $id ]; } public static function get_display_type_id( $name_or_alias ) { if ( isset( self::$mapping[ $name_or_alias ] ) ) { return $name_or_alias; } foreach ( self::$mapping as $id => $ids ) { if ( in_array( $name_or_alias, $ids, true ) ) { return $id; } } } } ����������������������������DisplayType/Installer.php���������������������������������������������������������������������������0000644�����������������00000005235�15021223045�0011460 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayType; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\DataTypes\DisplayType; use Imagely\NGG\Util\Transient; /** * @deprecated * @TODO Remove this when get_pro_api_version() is at least 4.0 */ class Installer { public function delete_duplicates( $name ) { $mapper = DisplayTypeMapper::get_instance(); $results = $mapper->find_all( [ 'name = %s', $name ] ); if ( count( $results ) > 0 ) { array_pop( $results ); // the last should be the latest. foreach ( $results as $display_type ) { $mapper->destroy( $display_type ); } } $mapper->flush_query_cache(); } /** * Installs a display type * * @param string $name * @param array $properties */ public function install_display_type( $name, $properties = [] ) { $this->delete_duplicates( $name ); // Try to find the existing entity. If it doesn't exist, we'll create. if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $mapper = \C_Display_Type_Mapper::get_instance(); } else { $mapper = DisplayTypeMapper::get_instance(); } $display_type = $mapper->find_by_name( $name ); $mapper->flush_query_cache(); if ( ! $display_type ) { if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $display_type = new \stdClass(); } else { $display_type = new DisplayType(); } } // Update the properties of the display type. $properties['name'] = $name; foreach ( $properties as $key => $val ) { $display_type->$key = $val; } // Save the entity. return $mapper->save( $display_type ); } /** * Uninstalls all display types */ public function uninstall_display_types() { $mapper = DisplayTypeMapper::get_instance(); $mapper->delete()->run_query(); } /** * Installs displayed gallery sources * * @param bool $reset (optional) Unused */ public function install( $reset = false ) { if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { return; } // Force Pro display types to register themselves. if ( class_exists( 'C_NextGen_Pro_Installer' ) ) { $pro_installer = new \C_NextGen_Pro_Installer(); $pro_installer->install_display_types(); } elseif ( class_exists( 'C_NextGen_Plus_Installer' ) ) { $plus_installer = new \C_NextGen_Plus_Installer(); $plus_installer->install_display_types(); } elseif ( class_exists( 'C_NextGen_Starter_Installer' ) ) { $plus_installer = new \C_NextGen_Starter_Installer(); $plus_installer->install_display_types(); } } /** * Uninstalls this module * * @param bool $hard (optional) Unused */ public function uninstall( $hard = false ) { Transient::flush(); $this->uninstall_display_types(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XMLRPC/Controller.php�������������������������������������������������������������������������������0000644�����������������00000045377�15021223045�0010417 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\XMLRPC; use Imagely\NGG\DataMappers\Album as AlbumMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\Util\Security; class Controller { /** * Gets the version of NextGEN Gallery installed * * @return array */ public function get_version() { return [ 'version' => NGG_PLUGIN_VERSION ]; } /** * Login a user * * @param string $username * @param string $password * @param int $blog_id * @return bool|\WP_Error|\WP_User */ public function _login( $username, $password, $blog_id = 1 ) { $retval = false; if ( ! is_a( ( $user_obj = wp_authenticate( $username, $password ) ), 'WP_Error' ) ) { wp_set_current_user( $user_obj->ID ); $retval = $user_obj; if ( is_multisite() ) { switch_to_blog( $blog_id ); } } return $retval; } public function _can_manage_gallery( $gallery_id_or_obj, $check_upload_capability = false ) { $retval = false; // Get the gallery object, if we don't have it already. if ( is_int( $gallery_id_or_obj ) ) { $gallery_mapper = GalleryMapper::get_instance(); $gallery = $gallery_mapper->find( $gallery_id_or_obj ); } else { $gallery = $gallery_id_or_obj; } if ( $gallery ) { if ( \get_current_user_id() === $gallery->author ) { $retval = true; } elseif ( Security::is_allowed( 'nextgen_edit_gallery_unowned' ) ) { $retval = true; } // Optionally, check if the user can upload to this gallery. if ( $retval && $check_upload_capability ) { $retval = Security::is_allowed( 'nextgen_upload_image' ); } } return $retval; } public function _add_gallery_properties( $gallery ) { if ( is_object( $gallery ) ) { $image_mapper = ImageMapper::get_instance(); $storage = StorageManager::get_instance(); // Vladimir's Lightroom plugins requires the 'id' to be a string // Ask if he can accept integers as well. Currently, integers break // his plugin. $gallery->gid = (string) $gallery->gid; // Set other gallery properties. $tmp = $image_mapper->select( 'DISTINCT COUNT(*) as counter' )->where( [ 'galleryid = %d', $gallery->gid ] )->run_query( false, false, true ); $image_counter = array_pop( $tmp ); $gallery->counter = $image_counter->counter; $gallery->abspath = $storage->get_gallery_abspath( $gallery ); } else { return false; } return true; } /** * Returns a single image object * * @param array $args (blog_id, username, password, pid) * @param bool $return_model (optional) * @return object|\IXR_Error */ public function get_image( $args, $return_model = false ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $image_id = intval( $args[3] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Try to find the image. $image_mapper = ImageMapper::get_instance(); if ( ( $image = $image_mapper->find( $image_id, true ) ) ) { // Try to find the gallery that the image belongs to. $gallery_mapper = GalleryMapper::get_instance(); if ( ( $gallery = $gallery_mapper->find( $image->galleryid ) ) ) { // Does the user have sufficient capabilities? if ( $this->_can_manage_gallery( $gallery ) ) { $storage = StorageManager::get_instance(); $image->imageURL = $storage->get_image_url( $image, 'full', true ); $image->thumbURL = $storage->get_image_url( $image, 'thumb' ); $image->imagePath = $storage->get_image_abspath( $image ); $image->thumbPath = $storage->get_thumb_abspath( $image ); $retval = $image; } else { $retval = new \IXR_Error( 403, "You don't have permission to manage gallery #{$image->galleryid}" ); } } else { // No gallery found. $retval = new \IXR_Error( 404, "Gallery not found (with id #{$image->galleryid})" ); } } else { // No image found. $retval = new \IXR_Error( 404, "Image not found (with id #{$image_id})" ); } } return $retval; } /** * Returns a collection of images * * @param array $args (blog_id, username, password, gallery_id * @return array|\IXR_Error */ public function get_images( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $gallery_id = intval( $args[3] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Try to find the gallery. $mapper = GalleryMapper::get_instance(); if ( ( $gallery = $mapper->find( $gallery_id, true ) ) ) { // Does the user have sufficient capabilities? if ( $this->_can_manage_gallery( $gallery ) ) { $retval = $gallery->get_images(); } else { $retval = new \IXR_Error( 403, "You don't have permission to manage gallery #{$gallery_id}" ); } } // No gallery found. else { $retval = new \IXR_Error( 404, "Gallery not found (with id #{$gallery_id}" ); } } return $retval; } /** * Uploads an image to a particular gallery * * @param $args (blog_id, username, password, data) * * Data is an assoc array: * o string name * o string type (optional) * o base64 bits * o bool overwrite (optional) * o int gallery * o int image_id (optional) * @return object|\IXR_Error */ public function upload_image( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $data = $args[3]; $gallery_id = isset( $data['gallery_id'] ) ? $data['gallery_id'] : $data['gallery']; if ( ! isset( $data['override'] ) ) { $data['override'] = false; } if ( ! isset( $data['overwrite'] ) ) { $data['overwrite'] = false; } if ( ! isset( $data['image_id'] ) ) { $data['image_id'] = false; } $data['override'] = $data['overwrite']; // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Try to find the gallery. $mapper = GalleryMapper::get_instance(); if ( ( $gallery = $mapper->find( $gallery_id, true ) ) ) { // Does the user have sufficient capabilities? if ( $this->_can_manage_gallery( $gallery, true ) ) { // Upload the image. $storage = StorageManager::get_instance(); try { $image = $storage->upload_base64_image( $gallery, $data['bits'], $data['name'], $data['image_id'], $data['override'] ); if ( $image ) { $image = is_int( $image ) ? ImageMapper::get_instance()->find( $image, true ) : $image; $storage = StorageManager::get_instance(); $image->imageURL = $storage->get_image_url( $image ); $image->thumbURL = $storage->get_image_url( $image, 'thumb' ); $image->imagePath = $storage->get_image_abspath( $image ); $image->thumbPath = $storage->get_thumb_abspath( $image ); $retval = $image->get_entity(); } else { $retval = new \IXR_Error( 500, 'Could not upload image' ); } } catch ( \Exception $exception ) { $retval = new \IXR_Error( 500, 'Could not upload image: ' . $exception->getMessage() ); } } else { $retval = new \IXR_Error( 403, "You don't have permission to upload to gallery #{$gallery_id}" ); } } else { // No gallery found. $retval = new \IXR_Error( 404, "Gallery not found (with id #{$gallery_id}" ); } } return $retval; } /** * Edits an image object * * @param $args (blog_id, username, password, image_id, alttext, description, exclude, other_properties * @return \IXR_Error|object */ public function edit_image( $args ) { $alttext = strval( $args[4] ); $description = strval( $args[5] ); $exclude = intval( $args[6] ); $properties = isset( $args[7] ) ? (array) $args[7] : []; $retval = $this->get_image( $args, true ); if ( ! ( $retval instanceof \IXR_Error ) ) { $retval->alttext = $alttext; $retval->description = $description; $retval->exclude = $exclude; // Other properties can be specified using an associative array. foreach ( $properties as $key => $value ) { $retval->$key = $value; } // Unset any dynamic properties not part of the schema. foreach ( [ 'imageURL', 'thumbURL', 'imagePath', 'thumbPath' ] as $key ) { unset( $retval->$key ); } $retval = $retval->save(); } return $retval; } /** * Deletes an existing image from a gallery * * @param array $args (blog_id, username, password, image_id) * @return bool */ public function delete_image( $args ) { $image = $this->get_image( $args, true ); if ( ! ( $image instanceof \IXR_Error ) ) { return ImageMapper::get_instance()->destroy( $image ); } return false; } /** * Creates a new gallery * * @param array $args (blog_id, username, password, title) * @return int|\IXR_Error */ public function create_gallery( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $title = strval( $args[3] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { if ( Security::is_allowed( 'nextgen_edit_gallery' ) ) { $mapper = GalleryMapper::get_instance(); if ( ( $gallery = $mapper->create( [ 'title' => $title ] ) ) && $gallery->save() ) { $retval = $gallery->id(); } else { $retval = new \IXR_Error( 500, 'Unable to create gallery' ); } } else { $retval = new \IXR_Error( 403, 'Sorry, but you must be able to manage galleries. Check your roles/capabilities.' ); } } return $retval; } /** * Edits an existing gallery * * @param array $args (blog_id, username, password, gallery_id, name, title, description, preview_pic_id) * @return int|bool|\IXR_Error */ public function edit_gallery( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $gallery_id = intval( $args[3] ); $name = strval( $args[4] ); $title = strval( $args[5] ); $galdesc = strval( $args[6] ); $image_id = intval( $args[7] ); $properties = isset( $args[8] ) ? (array) $args[8] : []; // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { $mapper = GalleryMapper::get_instance(); if ( ( $gallery = $mapper->find( $gallery_id, true ) ) ) { if ( $this->_can_manage_gallery( $gallery ) ) { $gallery->name = $name; $gallery->title = $title; $gallery->galdesc = $galdesc; $gallery->previewpic = $image_id; foreach ( $properties as $key => $value ) { $gallery->$key = $value; } // Unset dynamic properties not part of the schema. unset( $gallery->counter ); unset( $gallery->abspath ); $retval = $gallery->save(); } else { $retval = new \IXR_Error( 403, "You don't have permission to modify this gallery" ); } } else { $retval = new \IXR_Error( 404, "Gallery #{$gallery_id} doesn't exist" ); } } return $retval; } /** * Returns all galleries * * @param array $args (blog_id, username, password) * @return array|\IXR_Error */ public function get_galleries( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Do we have permission? if ( Security::is_allowed( 'nextgen_edit_gallery' ) ) { $mapper = GalleryMapper::get_instance(); $retval = []; foreach ( $mapper->find_all() as $gallery ) { $this->_add_gallery_properties( $gallery ); $retval[ $gallery->{$gallery->id_field} ] = (array) $gallery; } } else { $retval = new \IXR_Error( 401, __( 'Sorry, you must be able to manage galleries' ) ); } } return $retval; } /** * Gets a single gallery instance * * @param array $args (blog_id, username, password, gallery_id) * @param bool $return_model * @return object|bool|\IXR_Error */ public function get_gallery( $args, $return_model = false ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $gallery_id = intval( $args[3] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { $mapper = GalleryMapper::get_instance(); if ( ( $gallery = $mapper->find( $gallery_id, true ) ) ) { if ( $this->_can_manage_gallery( $gallery ) ) { $this->_add_gallery_properties( $gallery ); $retval = $gallery; } else { $retval = new \IXR_Error( 403, "Sorry, but you don't have permission to manage gallery #{$gallery->gid}" ); } } else { $retval = false; } } return $retval; } /** * Deletes a gallery * * @param array $args (blog_id, username, password, gallery_id) * @return bool */ public function delete_gallery( $args ) { $gallery = $this->get_gallery( $args, true ); if ( ! ( $gallery instanceof \IXR_Error ) && is_object( $gallery ) ) { return GalleryMapper::get_instance()->destroy( $gallery ); } return false; } /** * Creates a new album * * @param array $args (blog_id, username, password, title, previewpic, description, galleries * @return int|\IXR_Error */ public function create_album( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $title = strval( $args[3] ); $previewpic = isset( $args[4] ) ? intval( $args[4] ) : 0; $desc = isset( $args[5] ) ? strval( $args[5] ) : ''; $sortorder = isset( $args[6] ) ? $args[6] : ''; $page_id = isset( $args[7] ) ? intval( $args[7] ) : 0; // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Is request allowed? if ( Security::is_allowed( 'nextgen_edit_album' ) ) { $mapper = AlbumMapper::get_instance(); $album = $mapper->create( [ 'name' => $title, 'previewpic' => $previewpic, 'albumdesc' => $desc, 'sortorder' => $sortorder, 'pageid' => $page_id, ] ); if ( $album->save() ) { $retval = $album->id(); } else { $retval = new \IXR_Error( 500, 'Unable to create album' ); } } } return $retval; } /** * Returns all albums * * @param $args (blog_id, username, password) * @return \IXR_Error */ public function get_albums( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Are we allowed? if ( Security::is_allowed( 'nextgen_edit_album' ) ) { // Fetch all albums. $mapper = AlbumMapper::get_instance(); $retval = []; foreach ( $mapper->find_all() as $album ) { // Vladimir's Lightroom plugins requires the 'id' to be a string // Ask if he can accept integers as well. Currently, integers break // his plugin. $album->id = (string) $album->id; $album->galleries = $album->sortorder; $retval[ $album->{$album->id_field} ] = (array) $album; } } else { $retval = new \IXR_Error( 403, 'Sorry, you must be able to manage albums' ); } } return $retval; } /** * Gets a single album * * @param array $args (blog_id, username, password, album_id) * @param bool $return_model (optional) * @return object|bool|\IXR_Error */ public function get_album( $args, $return_model = false ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $album_id = intval( $args[3] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { // Are we allowed? if ( Security::is_allowed( 'nextgen_edit_album' ) ) { $mapper = AlbumMapper::get_instance(); if ( ( $album = $mapper->find( $album_id, true ) ) ) { // Vladimir's Lightroom plugins requires the 'id' to be a string // Ask if he can accept integers as well. Currently, integers break // his plugin. $album->id = (string) $album->id; $album->galleries = $album->sortorder; $retval = $album; } else { $retval = false; } } else { $retval = new \IXR_Error( 403, 'Sorry, you must be able to manage albums' ); } } return $retval; } /** * Deletes an existing album * * @param array $args (blog_id, username, password, album_id) * @return bool */ public function delete_album( $args ) { $album = $this->get_album( $args, true ); if ( ! ( $album instanceof \IXR_Error ) ) { return AlbumMapper::get_instance()->destroy( $album ); } return false; } /** * Edit an existing album * * @param array $args (blog_id, username, password, album_id, name, preview pic id, description, galleries). * @return object|\IXR_Error */ public function edit_album( $args ) { $retval = $this->get_album( $args, true ); if ( ! ( $retval instanceof \IXR_Error ) ) { $retval->name = strval( $args[4] ); $retval->previewpic = intval( $args[5] ); $retval->albumdesc = strval( $args[6] ); $retval->sortorder = $args[7]; $properties = isset( $args[8] ) ? $args[8] : []; foreach ( $properties as $key => $value ) { $retval->$key = $value; } unset( $retval->galleries ); $retval = $retval->save(); } return $retval; } /** * Sets the post thumbnail for a post to a NextGEN Gallery image * * @param $args (blog_id, username, password, post_id, image_id) * @return \IXR_Error|int attachment id */ public function set_post_thumbnail( $args ) { $retval = new \IXR_Error( 403, 'Invalid username or password' ); $blog_id = intval( $args[0] ); $username = strval( $args[1] ); $password = strval( $args[2] ); $post_ID = intval( $args[3] ); $image_id = intval( $args[4] ); // Authenticate the user. if ( $this->_login( $username, $password, $blog_id ) ) { if ( current_user_can( 'edit_post', $post_ID ) ) { $retval = StorageManager::get_instance()->set_post_thumbnail( $post_ID, $image_id ); } else { $retval = new \IXR_Error( 403, 'Sorry but you need permission to do this' ); } } return $retval; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XMLRPC/Manager.php����������������������������������������������������������������������������������0000644�����������������00000003644�15021223045�0007635 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * XMLRPC Manager * * @since 3.5.0 * * @package Nextgen Gallery */ namespace Imagely\NGG\XMLRPC; /** * Manager Class * * @since 3.5.0 */ class Manager { /** * Controller object * * @since 3.5.0 * * @var object */ protected static $nextgen_api_xmlrpc = null; /** * Add Methods * * @since 3.5.0 * * @param array $methods Holds Methods. * * @return array */ public static function add_methods( $methods ) { self::$nextgen_api_xmlrpc = new Controller(); $methods['ngg.installed'] = [ self::$nextgen_api_xmlrpc, 'get_version' ]; $methods['ngg.setPostThumbnail'] = [ self::$nextgen_api_xmlrpc, 'set_post_thumbnail' ]; // Image methods. $methods['ngg.getImage'] = [ self::$nextgen_api_xmlrpc, 'get_image' ]; $methods['ngg.getImages'] = [ self::$nextgen_api_xmlrpc, 'get_images' ]; $methods['ngg.uploadImage'] = [ self::$nextgen_api_xmlrpc, 'upload_image' ]; $methods['ngg.editImage'] = [ self::$nextgen_api_xmlrpc, 'edit_image' ]; $methods['ngg.deleteImage'] = [ self::$nextgen_api_xmlrpc, 'delete_image' ]; // Gallery methods. $methods['ngg.getGallery'] = [ self::$nextgen_api_xmlrpc, 'get_gallery' ]; $methods['ngg.getGalleries'] = [ self::$nextgen_api_xmlrpc, 'get_galleries' ]; $methods['ngg.newGallery'] = [ self::$nextgen_api_xmlrpc, 'create_gallery' ]; $methods['ngg.editGallery'] = [ self::$nextgen_api_xmlrpc, 'edit_gallery' ]; $methods['ngg.deleteGallery'] = [ self::$nextgen_api_xmlrpc, 'delete_gallery' ]; // Album methods. $methods['ngg.getAlbum'] = [ self::$nextgen_api_xmlrpc, 'get_album' ]; $methods['ngg.getAlbums'] = [ self::$nextgen_api_xmlrpc, 'get_albums' ]; $methods['ngg.newAlbum'] = [ self::$nextgen_api_xmlrpc, 'create_album' ]; $methods['ngg.editAlbum'] = [ self::$nextgen_api_xmlrpc, 'edit_album' ]; $methods['ngg.deleteAlbum'] = [ self::$nextgen_api_xmlrpc, 'delete_album' ]; return $methods; } } ��������������������������������������������������������������������������������������������Lightroom/Controller.php����������������������������������������������������������������������������0000644�����������������00000135546�15021223045�0011354 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Lightroom; use Imagely\NGG\DataMappers\Album as AlbumMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\Util\{Filesystem, Security}; class Controller { protected $nextgen_api = null; protected $nextgen_api_locked = false; protected $shutdown_registered = false; // Nonce verification not possible: the Lightroom client never requests or sends back a nonce. All actions are // authenticated. // // phpcs:disable WordPress.Security.NonceVerification.Missing // phpcs:disable WordPress.Security.NonceVerification.Recommended public static function run() { define( 'DOING_AJAX', true ); ob_start(); $self = new Controller(); $action = $self->param( 'action' ) . '_action'; $response = []; // The following could be dynamic but is written this way to prevent warnings that the methods aren't in use. if ( 'enqueue_nextgen_api_task_list_action' === $action ) { $response = $self->enqueue_nextgen_api_task_list_action(); } elseif ( 'execute_nextgen_api_task_list_action' === $action ) { $response = $self->execute_nextgen_api_task_list_action(); } elseif ( 'get_nextgen_api_path_list_action' === $action ) { $response = $self->get_nextgen_api_path_list_action(); } elseif ( 'get_nextgen_api_token_action' === $action ) { $response = $self->get_nextgen_api_token_action(); } // Flush the buffer. $buffer_limit = 0; $zlib = ini_get( 'zlib.output_compression' ); if ( ! is_numeric( $zlib ) && $zlib == 'On' ) { $buffer_limit = 1; } elseif ( is_numeric( $zlib ) && $zlib > 0 ) { $buffer_limit = 1; } while ( ob_get_level() != $buffer_limit ) { ob_end_clean(); } wp_send_json( $response ); } public function param( $key ) { if ( isset( $_REQUEST[ $key ] ) ) { return $this->recursive_stripslashes( $_REQUEST[ $key ] ); } } /** * Recursively calls stripslashes() on strings, arrays, and objects * * Copied here from RoutingApp to maintain compatibility with Lightroom * * @TODO Move this to a better place or find a better solution * @param string|array|\stdClass $value Value to be processed * @return string|array|\stdClass Resulting value */ public function recursive_stripslashes( $value ) { if ( is_string( $value ) ) { $value = stripslashes( $value ); } elseif ( is_array( $value ) ) { foreach ( $value as &$tmp ) { $tmp = $this->recursive_stripslashes( $tmp ); } } elseif ( is_object( $value ) ) { foreach ( get_object_vars( $value ) as $key => $data ) { $value->{$key} = $this->recursive_stripslashes( $data ); } } return $value; } public function enqueue_nextgen_api_task_list_action() { $api = $this->get_nextgen_api(); $user_obj = $this->authenticate_user(); $response = []; if ( $user_obj != null && ! is_a( $user_obj, 'WP_Error' ) ) { wp_set_current_user( $user_obj->ID ); $app_config = $this->param( 'app_config' ); $task_list = $this->param( 'task_list' ); $extra_data = $this->param( 'extra_data' ); if ( is_string( $app_config ) ) { $app_config = json_decode( $app_config, true ); } if ( is_string( $task_list ) ) { $task_list = json_decode( $task_list, true ); } if ( is_string( $extra_data ) ) { $extra_data = json_decode( $extra_data, true ); } foreach ( $_FILES as $key => $file ) { if ( substr( $key, 0, strlen( 'file_data_' ) ) == 'file_data_' ) { $extra_data[ substr( $key, strlen( 'file_data_' ) ) ] = $file; } } if ( $task_list != null ) { $task_count = count( $task_list ); $auth_count = 0; foreach ( $task_list as &$task_item ) { $task_name = isset( $task_item['name'] ) ? $task_item['name'] : null; $task_type = isset( $task_item['type'] ) ? $task_item['type'] : null; $task_query = isset( $task_item['query'] ) ? $task_item['query'] : null; $task_auth = false; switch ( $task_type ) { case 'gallery_add': { $task_auth = Security::is_allowed( 'nextgen_edit_gallery' ); break; } case 'gallery_remove': case 'gallery_edit': { $query_id = $api->get_query_id( $task_query['id'], $task_list ); $gallery = null; // The old NextGEN XMLRPC API had this logic so replicating it here for safety. if ( $query_id ) { $gallery_mapper = GalleryMapper::get_instance(); $gallery = $gallery_mapper->find( $query_id ); } if ( $gallery != null ) { $task_auth = ( wp_get_current_user()->ID == $gallery->author || Security::is_allowed( 'nextgen_edit_gallery_unowned' ) ); } else { $task_auth = Security::is_allowed( 'nextgen_edit_gallery' ); } break; } case 'album_remove': case 'album_edit': case 'album_add': { $task_auth = Security::is_allowed( 'nextgen_edit_album' ); break; } case 'image_list_move': { break; } } if ( $task_auth ) { ++$auth_count; } $task_item['auth'] = $task_auth ? 'allow' : 'forbid'; } if ( $task_count == $auth_count ) { $job_id = $api->add_job( [ 'user' => $user_obj->ID, 'clientid' => $this->param( 'clientid' ), ], $app_config, $task_list ); if ( $job_id != null ) { $post_back = $api->get_job_post_back( $job_id ); $handler_delay = defined( 'NGG_API_JOB_HANDLER_DELAY' ) ? intval( NGG_API_JOB_HANDLER_DELAY ) : 0; $handler_delay = $handler_delay > 0 ? $handler_delay : 30; /* in seconds */ $handler_maxsize = defined( 'NGG_API_JOB_HANDLER_MAXSIZE' ) ? intval( NGG_API_JOB_HANDLER_MAXSIZE ) : 0; $handler_maxsize = $handler_maxsize > 0 ? $handler_maxsize : $this->get_max_upload_size(); /* in bytes */ $handler_maxfiles = $this->get_max_upload_files(); $response['result'] = 'ok'; $response['result_object'] = [ 'job_id' => $job_id, 'job_post_back' => $post_back, 'job_handler_url' => home_url( '?photocrati_ajax=1&action=execute_nextgen_api_task_list' ), 'job_handler_delay' => $handler_delay, 'job_handler_maxsize' => $handler_maxsize, 'job_handler_maxfiles' => $handler_maxfiles, ]; if ( ! defined( 'NGG_API_SUPPRESS_QUICK_EXECUTE' ) || NGG_API_SUPPRESS_QUICK_EXECUTE == false ) { if ( ! $api->is_execution_locked() ) { $this->start_locked_execute(); try { $result = $api->handle_job( $job_id, $api->get_job_data( $job_id ), $app_config, $api->get_job_task_list( $job_id ), $extra_data ); $response['result_object']['job_result'] = $api->get_job_task_list( $job_id ); if ( $result ) { // everything was finished, remove job. $api->remove_job( $job_id ); } } catch ( \Exception $e ) { } $this->stop_locked_execute(); } } } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_JOB_NOT_ADDED, 'message' => __( 'Job could not be added.', 'nggallery' ), ]; } } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_NOT_AUTHORIZED, 'message' => __( 'Authorization Failed.', 'nggallery' ), ]; } } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_NO_TASK_LIST, 'message' => __( 'No task list was specified.', 'nggallery' ), ]; } } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_NOT_AUTHENTICATED, 'message' => __( 'Authentication Failed.', 'nggallery' ), ]; } return $response; } public function execute_nextgen_api_task_list_action() { $api = $this->get_nextgen_api(); $job_list = $api->get_job_list(); $response = []; if ( $api->is_execution_locked() ) { $response['result'] = 'ok'; $response['info'] = [ 'code' => API::INFO_EXECUTION_LOCKED, 'message' => __( 'Job execution is locked.', 'nggallery' ), ]; } elseif ( $job_list != null ) { $this->start_locked_execute(); try { $extra_data = $this->param( 'extra_data' ); $job_count = count( $job_list ); $done_count = 0; $client_result = []; if ( is_string( $extra_data ) ) { $extra_data = json_decode( $extra_data, true ); } foreach ( $_FILES as $key => $file ) { if ( substr( $key, 0, strlen( 'file_data_' ) ) == 'file_data_' ) { $extra_data[ substr( $key, strlen( 'file_data_' ) ) ] = $file; } } foreach ( $job_list as $job ) { $job_id = $job['id']; $job_data = $job['data']; $result = $api->handle_job( $job_id, $job_data, $job['app_config'], $job['task_list'], $extra_data ); if ( isset( $job_data['clientid'] ) && $job_data['clientid'] == $this->param( 'clientid' ) ) { $client_result[ $job_id ] = $api->get_job_task_list( $job_id ); } if ( $result ) { ++$done_count; // everything was finished, remove job. $api->remove_job( $job_id ); } if ( $api->should_stop_execution() ) { break; } } } catch ( \Exception $e ) { } $this->stop_locked_execute(); if ( $done_count == $job_count ) { $response['result'] = 'ok'; $response['info'] = [ 'code' => API::INFO_JOB_LIST_FINISHED, 'message' => __( 'Job list is finished.', 'nggallery' ), ]; } else { $response['result'] = 'ok'; $response['info'] = [ 'code' => API::INFO_JOB_LIST_UNFINISHED, 'message' => __( 'Job list is unfinished.', 'nggallery' ), ]; } if ( ! defined( 'NGG_API_SUPPRESS_QUICK_SUMMARY' ) || NGG_API_SUPPRESS_QUICK_SUMMARY == false ) { $response['result_object'] = $client_result; } } else { $response['result'] = 'ok'; $response['info'] = [ 'code' => API::INFO_NO_JOB_LIST, 'message' => __( 'Job list is empty.', 'nggallery' ), ]; } return $response; } public function get_nextgen_api_path_list_action() { $api = $this->get_nextgen_api(); $app_config = $this->param( 'app_config' ); $user_obj = $this->authenticate_user(); $response = []; if ( $user_obj != null && ! is_a( $user_obj, 'WP_Error' ) ) { wp_set_current_user( $user_obj->ID ); $ftp_method = isset( $app_config['ftp_method'] ) ? $app_config['ftp_method'] : 'ftp'; $creds = [ 'connection_type' => $ftp_method == 'sftp' ? 'ssh' : 'ftp', 'hostname' => $app_config['ftp_host'], 'port' => $app_config['ftp_port'], 'username' => $app_config['ftp_user'], 'password' => $app_config['ftp_pass'], ]; require_once ABSPATH . 'wp-admin/includes/file.php'; $wp_filesystem = $api->create_filesystem_access( $creds ); $root_path = null; $base_path = null; $plugin_path = null; if ( $wp_filesystem ) { $root_path = $wp_filesystem->wp_content_dir(); $base_path = $wp_filesystem->abspath(); $plugin_path = $wp_filesystem->wp_plugins_dir(); } else { // fallbacks when unable to connect, try to see if we know the path already. $root_path = get_option( 'ngg_ftp_root_path' ); if ( defined( 'FTP_BASE' ) ) { $base_path = FTP_BASE; } if ( $root_path == null && defined( 'FTP_CONTENT_DIR' ) ) { $root_path = FTP_CONTENT_DIR; } if ( defined( 'FTP_PLUGIN_DIR' ) ) { $plugin_path = FTP_PLUGIN_DIR; } if ( $base_path == null && $root_path != null ) { $base_path = dirname( $root_path ); } if ( $root_path == null && $base_path != null ) { $root_path = rtrim( $base_path, '/\\' ) . '/wp-content/'; } if ( $plugin_path == null && $base_path != null ) { $plugin_path = rtrim( $base_path, '/\\' ) . '/wp-content/plugins/'; } } if ( $root_path != null ) { $response['result'] = 'ok'; $response['result_object'] = [ 'root_path' => $root_path, 'wp_content_path' => $root_path, 'wp_base_path' => $base_path, 'wp_plugin_path' => $plugin_path, ]; } elseif ( $wp_filesystem != null ) { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_FTP_NO_PATH, 'message' => __( 'Could not determine FTP path.', 'nggallery' ), ]; } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_FTP_NOT_CONNECTED, 'message' => __( 'Could not connect to FTP to determine path.', 'nggallery' ), ]; } } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_NOT_AUTHENTICATED, 'message' => __( 'Authentication Failed.', 'nggallery' ), ]; } return $response; } public function get_nextgen_api_token_action() { $regen = $this->param( 'regenerate_token' ) ? true : false; $user_obj = $this->authenticate_user( $regen ); $response = []; if ( $user_obj != null ) { $response['result'] = 'ok'; $response['result_object'] = [ 'token' => get_user_meta( $user_obj->ID, 'nextgen_api_token', true ), ]; } else { $response['result'] = 'error'; $response['error'] = [ 'code' => API::ERR_NOT_AUTHENTICATED, 'message' => __( 'Authentication Failed.', 'nggallery' ), ]; } return $response; } protected function get_nextgen_api() { if ( is_null( $this->nextgen_api ) ) { $this->nextgen_api = API::get_instance(); } return $this->nextgen_api; } protected function authenticate_user( $regenerate_token = false ) { $api = $this->get_nextgen_api(); $username = $this->param( 'q' ); $password = $this->param( 'z' ); $token = $this->param( 'tok' ); return $api->authenticate_user( $username, $password, $token, $regenerate_token ); } protected function get_max_upload_size() { static $max_size = -1; if ( $max_size < 0 ) { $post_max_size = $this->parse_size( ini_get( 'post_max_size' ) ); if ( $post_max_size > 0 ) { $max_size = $post_max_size; } $upload_max = $this->parse_size( ini_get( 'upload_max_filesize' ) ); if ( $upload_max > 0 && $upload_max < $max_size ) { $max_size = $upload_max; } } return $max_size; } protected function parse_size( $size ) { $unit = preg_replace( '/[^bkmgtpezy]/i', '', $size ); $size = preg_replace( '/[^0-9\.]/', '', $size ); if ( $unit ) { return round( $size * pow( 1024, stripos( 'bkmgtpezy', $unit[0] ) ) ); } else { return round( $size ); } } protected function get_max_upload_files() { return intval( ini_get( 'max_file_uploads' ) ); } public function do_shutdown() { if ( $this->nextgen_api_locked ) { $this->get_nextgen_api()->set_execution_locked( false ); } } protected function start_locked_execute() { if ( ! $this->shutdown_registered ) { \register_shutdown_function( [ $this, 'do_shutdown' ] ); $this->shutdown_registered = true; } $this->get_nextgen_api()->set_execution_locked( true ); $this->nextgen_api_locked = true; } protected function stop_locked_execute() { $this->get_nextgen_api()->set_execution_locked( false ); $this->nextgen_api_locked = false; } } class API { // NOTE: these constants' numeric values MUST remain the same, do NOT change the values. const ERR_NO_TASK_LIST = 1001; const ERR_NOT_AUTHENTICATED = 1002; const ERR_NOT_AUTHORIZED = 1003; const ERR_JOB_NOT_ADDED = 1004; const ERR_FTP_NOT_AUTHENTICATED = 1101; const ERR_FTP_NOT_CONNECTED = 1102; const ERR_FTP_NO_PATH = 1103; const INFO_NO_JOB_LIST = 6001; const INFO_JOB_LIST_FINISHED = 6002; const INFO_JOB_LIST_UNFINISHED = 6003; const INFO_EXECUTION_LOCKED = 6004; public static $_instances = []; public $_start_time; /** * @param bool|string $context * @return API */ public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new API( $context ); } return self::$_instances[ $context ]; } public function __construct( $context ) { $this->_start_time = time(); } public function should_stop_execution() { $timeout = defined( 'NGG_API_JOB_HANDLER_TIMEOUT' ) ? intval( NGG_API_JOB_HANDLER_TIMEOUT ) : ( intval( ini_get( 'max_execution_time' ) ) - 3 ); $timeout = $timeout > 0 ? $timeout : 27; /* most hosts have a limit of 30 seconds execution time, so 27 should be a safe default */ return ( time() - $this->_start_time >= $timeout ); } public function is_execution_locked() { $lock_time = get_option( 'ngg_api_execution_lock', 0 ); if ( $lock_time == 0 ) { return false; } $lock_max = defined( 'NGG_API_EXECUTION_LOCK_MAX' ) ? intval( NGG_API_EXECUTION_LOCK_MAX ) : 0; $lock_max = $lock_max > 0 ? $lock_max : 60 * 5; /* if the lock is 5 minutes old assume something went wrong and the lock couldn't be unset */ $time_diff = time() - $lock_time; if ( $time_diff > $lock_max ) { return false; } return true; } public function set_execution_locked( $locked ) { if ( $locked ) { update_option( 'ngg_api_execution_lock', time(), false ); } else { update_option( 'ngg_api_execution_lock', 0, false ); } } public function get_job_list() { return get_option( 'ngg_api_job_list' ); } public function add_job( $job_data, $app_config, $task_list ) { $job_list = $this->get_job_list(); $job_id = uniqid(); while ( isset( $job_list[ $job_id ] ) ) { $job_id = uniqid(); } $job = [ 'id' => $job_id, 'post_back' => [ 'token' => md5( $job_id ), ], 'data' => $job_data, 'app_config' => $app_config, 'task_list' => $task_list, ]; $job_list[ $job_id ] = $job; update_option( 'ngg_api_job_list', $job_list, false ); return $job_id; } public function _update_job( $job_id, $job ) { $job_list = $this->get_job_list(); if ( isset( $job_list[ $job_id ] ) ) { $job_list[ $job_id ] = $job; update_option( 'ngg_api_job_list', $job_list, false ); } } public function remove_job( $job_id ) { $job_list = $this->get_job_list(); if ( isset( $job_list[ $job_id ] ) ) { unset( $job_list[ $job_id ] ); update_option( 'ngg_api_job_list', $job_list, false ); } } public function get_job( $job_id ) { $job_list = $this->get_job_list(); if ( isset( $job_list[ $job_id ] ) ) { return $job_list[ $job_id ]; } return null; } public function get_job_data( $job_id ) { $job = $this->get_job( $job_id ); if ( $job != null ) { return $job['data']; } return null; } public function get_job_task_list( $job_id ) { $job = $this->get_job( $job_id ); if ( $job != null ) { return $job['task_list']; } return null; } public function set_job_task_list( $job_id, $task_list ) { $job = $this->get_job( $job_id ); if ( $job != null ) { $job['task_list'] = $task_list; $this->_update_job( $job_id, $job ); return true; } return false; } public function get_job_post_back( $job_id ) { $job = $this->get_job( $job_id ); if ( $job != null ) { return $job['post_back']; } return null; } public function authenticate_user( $username, $password, $token, $regenerate_token = false ) { $user_obj = null; if ( $token != null ) { $users = get_users( [ 'meta_key' => 'nextgen_api_token', 'meta_value' => $token, ] ); if ( $users != null && count( $users ) > 0 ) { $user_obj = $users[0]; } } if ( $user_obj == null ) { if ( $username != null && $password != null ) { $user_obj = wp_authenticate( $username, $password ); $token = get_user_meta( $user_obj->ID, 'nextgen_api_token', true ); if ( $token == null ) { $regenerate_token = true; } } } if ( is_a( $user_obj, 'WP_Error' ) ) { $user_obj = null; } if ( $regenerate_token ) { if ( $user_obj != null ) { $token = ''; if ( function_exists( 'random_bytes' ) ) { $token = bin2hex( random_bytes( 16 ) ); } elseif ( function_exists( 'openssl_random_pseudo_bytes' ) ) { $token = bin2hex( openssl_random_pseudo_bytes( 16 ) ); } else { for ( $i = 0; $i < 16; $i++ ) { $token .= bin2hex( mt_rand( 0, 15 ) ); } } update_user_meta( $user_obj->ID, 'nextgen_api_token', $token ); } } return $user_obj; } public function create_filesystem_access( $args, $method = null ) { // taken from wp-admin/includes/file.php but with modifications. if ( ! $method && isset( $args['connection_type'] ) && 'ssh' == $args['connection_type'] && extension_loaded( 'ssh2' ) && function_exists( 'stream_get_contents' ) ) { $method = 'ssh2'; } if ( ! $method && extension_loaded( 'ftp' ) ) { $method = 'ftpext'; } if ( ! $method && ( extension_loaded( 'sockets' ) || function_exists( 'fsockopen' ) ) ) { $method = 'ftpsockets'; // Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread. } if ( ! $method ) { return false; } require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php'; if ( ! class_exists( "WP_Filesystem_$method" ) ) { /** * Filter the path for a specific filesystem method class file. * * @since 2.6.0 * * @see get_filesystem_method() * * @param string $path Path to the specific filesystem method class file. * @param string $method The filesystem method to use. */ $abstraction_file = apply_filters( 'filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method ); if ( ! file_exists( $abstraction_file ) ) { return false; } require_once $abstraction_file; } $method_class = "WP_Filesystem_$method"; $wp_filesystem = new $method_class( $args ); // Define the timeouts for the connections. Only available after the construct is called to allow for per-transport overriding of the default. if ( ! defined( 'FS_CONNECT_TIMEOUT' ) ) { define( 'FS_CONNECT_TIMEOUT', 30 ); } if ( ! defined( 'FS_TIMEOUT' ) ) { define( 'FS_TIMEOUT', 30 ); } if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) { return false; } if ( ! $wp_filesystem->connect() ) { if ( $method == 'ftpext' ) { // attempt connecting with alternative method. return $this->create_filesystem_access( $args, 'ftpsockets' ); } return false; // There was an error connecting to the server. } // Set the permission constants if not already set. if ( ! defined( 'FS_CHMOD_DIR' ) ) { define( 'FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) ); } if ( ! defined( 'FS_CHMOD_FILE' ) ) { define( 'FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) ); } return $wp_filesystem; } // returns an actual scalar ID based on parametric ID (e.g. a parametric ID could represent the query ID from another task). public function get_query_id( $id, &$task_list ) { $task_id = $id; if ( is_object( $task_id ) || is_array( $task_id ) ) { $id = null; // it was specified that the query ID is referencing the query ID from another task. if ( isset( $task_id['target'] ) && $task_id['target'] == 'task' ) { if ( isset( $task_id['id'] ) && isset( $task_list[ $task_id['id'] ] ) ) { $target_task = $task_list[ $task_id['id'] ]; if ( isset( $target_task['query']['id'] ) ) { $id = $target_task['query']['id']; } } } } return $id; } // returns an actual scalar ID based on parametric ID (e.g. a parametric ID could represent the resulting object ID from another task). public function get_object_id( $id, &$result_list ) { $task_id = $id; if ( is_object( $task_id ) || is_array( $task_id ) ) { $id = null; // it was specified that the query ID is referencing the result from another task. if ( isset( $task_id['target'] ) && $task_id['target'] == 'task' ) { if ( isset( $task_id['id'] ) && isset( $result_list[ $task_id['id'] ] ) ) { $target_result = $result_list[ $task_id['id'] ]; if ( isset( $target_result['object_id'] ) ) { $id = $target_result['object_id']; } } } } return $id; } public function _array_find_by_entry( array $array_target, $entry_key, $entry_value ) { foreach ( $array_target as $key => $value ) { $item = $value; if ( isset( $item[ $entry_key ] ) && $item[ $entry_key ] == $entry_value ) { return $key; } } return null; } public function _array_filter_by_entry( array $array_target, array $array_source, $entry_key ) { foreach ( $array_source as $key => $value ) { $item = $value; if ( isset( $item[ $entry_key ] ) ) { $find_key = $this->_array_find_by_entry( $array_target, $entry_key, $item[ $entry_key ] ); if ( $find_key !== null ) { unset( $array_target[ $find_key ] ); } } } return $array_target; } public function is_valid_filename( string $filename ): bool { $fs = Filesystem::get_instance(); $root = $fs->get_document_root( 'galleries' ); $tmp = ini_get( 'upload_tmp_dir' ) ?: sys_get_temp_dir(); $filename = str_replace( '\\', '/', $filename ); // Do not allow phar:// streams, and block ".phar" filenames as well. if ( false !== strpos( $filename, '.phar' ) || false !== strpos( $filename, 'phar://' ) ) { return false; } // Also block all streams for good measure. if ( false !== strpos( $filename, '://' ) ) { return false; } // And prevent all "../". if ( false !== strpos( $filename, '../' ) ) { return false; } // Bitnami stores files in /opt/bitnami, but PHP's ReflectionClass->getFileName() can report /bitnami // which causes this method to reject files for being outside the server document root. if ( 0 === strpos( $filename, '/bitnami', 0 ) ) { $filename = '/opt' . $filename; } if ( '/tmp' === $tmp || '/tmp/' === $tmp ) { $filename = strstr( $filename, '/tmp' ); } if ( 0 === strpos( $filename, '/' ) && ( strncmp( $filename, $root, strlen( $root ) ) !== 0 && strncmp( $filename, $tmp, strlen( $tmp ) ) !== 0 ) ) { return false; } return true; } // Note: handle_job only worries about processing the job, it does NOT remove finished jobs anymore, the responsibility is on the caller to remove the job when handle_job returns true, this is to allow calling get_job_*() methods after handle_job has been called. public function handle_job( $job_id, $job_data, $app_config, $task_list, $extra_data = null ) { $job_user = $job_data['user']; $task_count = count( $task_list ); $done_count = 0; $skip_count = 0; $task_list_result = []; wp_set_current_user( $job_user ); // Prevent PHP warnings about accessing undefined array keys. $app_config['ftp_path'] = isset( $app_config['ftp_path'] ) ? $app_config['ftp_path'] : ''; $app_config['full_path'] = isset( $app_config['full_path'] ) ? $app_config['full_path'] : ''; /* This block does all of the filesystem magic: * - determines web paths based on FTP paths * - initializes the WP_Filesystem mechanism in case this host doesn't support direct file access * (this might not be 100% reliable right now due to NG core not making use of WP_Filesystem) */ // $ftp_path is assumed to be WP_CONTENT_DIR as accessed through the FTP mount point. $ftp_path = rtrim( $app_config['ftp_path'], '/\\' ); $full_path = rtrim( $app_config['full_path'], '/\\' ); $root_path = rtrim( WP_CONTENT_DIR, '/\\' ); $creds = true; // WP_Filesystem(true) requests direct filesystem access. $fs_sep = DIRECTORY_SEPARATOR; $wp_fs = null; require_once ABSPATH . 'wp-admin/includes/file.php'; if ( get_filesystem_method() !== 'direct' ) { $fs_sep = '/'; $ftp_method = isset( $app_config['ftp_method'] ) ? $app_config['ftp_method'] : 'ftp'; $creds = [ 'connection_type' => $ftp_method == 'sftp' ? 'ssh' : 'ftp', 'hostname' => $app_config['ftp_host'], 'port' => $app_config['ftp_port'], 'username' => $app_config['ftp_user'], 'password' => $app_config['ftp_pass'], ]; } if ( WP_Filesystem( $creds ) ) { $wp_fs = $GLOBALS['wp_filesystem']; $path_prefix = $full_path; if ( $wp_fs->method === 'direct' ) { if ( trim( $ftp_path, " \t\n\r\x0B\\" ) == '' ) { // Note: if ftp_path is empty, we assume the FTP account home dir is on wp-content. $path_prefix = $root_path . $full_path; } else { $path_prefix = str_replace( $ftp_path, $root_path, $full_path ); } } } else { include_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php'; if ( ! $wp_fs ) { $wp_fs = new \WP_Filesystem_Direct( $creds ); } } foreach ( $task_list as &$task_item ) { $task_id = isset( $task_item['id'] ) ? $task_item['id'] : null; $task_name = isset( $task_item['name'] ) ? $task_item['name'] : null; $task_type = isset( $task_item['type'] ) ? $task_item['type'] : null; $task_auth = isset( $task_item['auth'] ) ? $task_item['auth'] : null; $task_query = isset( $task_item['query'] ) ? $task_item['query'] : null; $task_object = isset( $task_item['object'] ) ? $task_item['object'] : null; $task_status = isset( $task_item['status'] ) ? $task_item['status'] : null; $task_result = isset( $task_item['result'] ) ? $task_item['result'] : null; // make sure we don't repeat execution of already finished tasks. if ( $task_status == 'done' ) { ++$done_count; // for previously finished tasks, store the result as it may be needed by future tasks. if ( $task_id != null && $task_result != null ) { $task_list_result[ $task_id ] = $task_result; } continue; } // make sure only valid and authorized tasks are executed. if ( $task_status == 'error' || $task_auth != 'allow' ) { ++$skip_count; continue; } // the task query ID can be a simple (integer) ID or more complex ID that gets converted to a simple ID, for instance to point to an object that is the result of a previously finished task. if ( isset( $task_query['id'] ) ) { $task_query['id'] = $this->get_object_id( $task_query['id'], $task_list_result ); } $task_error = null; switch ( $task_type ) { case 'gallery_add': { $mapper = GalleryMapper::get_instance(); $gallery = null; $gal_errors = ''; if ( isset( $task_query['id'] ) ) { $gallery = $mapper->find( $task_query['id'], true ); } if ( $gallery == null ) { $title = isset( $task_object['title'] ) ? $task_object['title'] : ''; $gallery = $mapper->create( [ 'title' => $title ] ); if ( ! $gallery || ! $gallery->save() ) { if ( $gallery != null ) { $gal_errors = $gallery->validation(); if ( is_array( $gal_errors ) ) { $gal_errors = ' [' . json_encode( $gal_errors ) . ']'; } } $gallery = null; } } if ( $gallery != null ) { $task_status = 'done'; $task_result['object_id'] = $gallery->id(); } else { $task_status = 'error'; $task_error = [ 'level' => 'fatal', 'message' => sprintf( __( 'Gallery creation failed for "%1$s"%2$s.', 'nggallery' ), $title, $gal_errors ), ]; } break; } case 'gallery_remove': case 'gallery_edit': { if ( isset( $task_query['id'] ) ) { $mapper = GalleryMapper::get_instance(); $gallery = $mapper->find( $task_query['id'], true ); $error = null; if ( $gallery != null ) { if ( $task_type == 'gallery_remove' ) { /** * @var GalleryMapper $mapper. */ if ( ! $mapper->destroy( $gallery, true ) ) { $error = __( 'Failed to remove gallery (%1$s).', 'nggallery' ); } } elseif ( $task_type == 'gallery_edit' ) { if ( isset( $task_object['name'] ) ) { $gallery->name = $task_object['name']; } if ( isset( $task_object['title'] ) ) { $gallery->title = $task_object['title']; } if ( isset( $task_object['description'] ) ) { $gallery->galdesc = $task_object['description']; } if ( isset( $task_object['preview_image'] ) ) { $gallery->previewpic = $task_object['preview_image']; } if ( isset( $task_object['property_list'] ) ) { $properties = $task_object['property_list']; foreach ( $properties as $key => $value ) { $gallery->$key = $value; } } // this is used to determine whether the task is complete. $image_list_unfinished = false; if ( isset( $task_object['image_list'] ) && $wp_fs != null ) { $storage_path = isset( $task_object['storage_path'] ) ? $task_object['storage_path'] : null; $storage_path = trim( $storage_path, '/\\' ); $storage = StorageManager::get_instance(); $image_mapper = ImageMapper::get_instance(); $creds = true; $images_folder = $path_prefix . $fs_sep . $storage_path . $fs_sep; $images_folder = str_replace( [ '\\', '/' ], $fs_sep, $images_folder ); $images = $task_object['image_list']; $result_images = isset( $task_result['image_list'] ) ? $task_result['image_list'] : []; $images_todo = array_values( $this->_array_filter_by_entry( $images, $result_images, 'localId' ) ); $image_count = count( $images ); $result_image_count = count( $result_images ); foreach ( $images_todo as $image_index => $image ) { $image_id = isset( $image['id'] ) ? $image['id'] : null; $image_filename = isset( $image['filename'] ) ? $image['filename'] : null; $image_path = isset( $image['path'] ) ? $image['path'] : null; $image_data_key = isset( $image['data_key'] ) ? $image['data_key'] : null; $image_action = isset( $image['action'] ) ? $image['action'] : null; $image_status = isset( $image['status'] ) ? $image['status'] : 'skip'; if ( $image_filename == null ) { $image_filename = basename( $image_path ); } $ngg_image = $image_mapper->find( $image_id, true ); // ensure that we don't transpose the image from one gallery to another in case a remoteId is passed in for the image but the gallery associated to the collection cannot be found. if ( $ngg_image && $ngg_image->galleryid != $gallery->id() ) { $ngg_image = null; $image_id = null; } $image_error = null; if ( $image_action == 'delete' ) { // image was deleted. if ( $ngg_image != null ) { $settings = \Imagely\NGG\Settings\Settings::get_instance(); $delete_fine = true; if ( $settings->get( 'deleteImg' ) ) { if ( ! $storage->delete_image( $ngg_image ) ) { $image_error = __( 'Could not delete image file(s) from disk (%1$s).', 'nggallery' ); } } elseif ( ! $image_mapper->destroy( $ngg_image ) ) { $image_error = __( 'Could not remove image from gallery (%1$s).', 'nggallery' ); } if ( $image_error == null ) { do_action( 'ngg_delete_picture', $ngg_image->{$ngg_image->id_field}, $ngg_image ); $image_status = 'done'; } } else { $image_error = __( 'Could not remove image because image was not found (%1$s).', 'nggallery' ); } } else { // image was added or edited and needs updating. $image_data = null; if ( $image_data_key != null ) { if ( ! isset( $extra_data['__queuedImages'][ $image_data_key ] ) ) { if ( isset( $extra_data[ $image_data_key ] ) ) { $image_data_arr = $extra_data[ $image_data_key ]; if ( $this->is_valid_filename( $image_data_arr['tmp_name'] ) ) { $image_data = file_get_contents( $image_data_arr['tmp_name'] ); } } if ( $image_data == null ) { $image_error = __( 'Could not obtain data for image (%1$s).', 'nggallery' ); } } else { $image_status = 'queued'; } } else { $image_path = $images_folder . $image_path; if ( $image_path !== null && $this->is_valid_filename( $image_path ) && $wp_fs->exists( $image_path ) ) { $image_data = $wp_fs->get_contents( $image_path ); // delete temporary image. $wp_fs->delete( $image_path ); } elseif ( is_multisite() ) { $image_error = __( 'Could not find image file for image (%1$s). Using FTP Upload Method in Multisite is not recommended.', 'nggallery' ); } else { $image_error = __( 'Could not find image file for image (%1$s).', 'nggallery' ); } } if ( $image_data != null ) { try { $ngg_image = $storage->upload_base64_image( $gallery, $image_data, $image_filename, $image_id, true ); $image_mapper->reimport_metadata( $ngg_image ); if ( $ngg_image != null ) { $image_status = 'done'; $image_id = is_int( $ngg_image ) ? $ngg_image : $ngg_image->{$ngg_image->id_field}; } } catch ( \E_NoSpaceAvailableException $e ) { $image_error = __( 'No space available for image (%1$s).', 'nggallery' ); } catch ( \E_UploadException $e ) { $image_error = $e->getMessage . __( ' (%1$s).', 'nggallery' ); } catch ( \E_No_Image_Library_Exception $e ) { $image_error = __( 'No image library present, image uploads will fail (%1$s).', 'nggallery' ); // no point in continuing if the image library is not present but we don't break here to ensure that all images are processed (otherwise they'd be processed in further fruitless handle_job calls). } catch ( \E_InsufficientWriteAccessException $e ) { $image_error = __( 'Inadequate system permissions to write image (%1$s).', 'nggallery' ); } catch ( \E_InvalidEntityException $e ) { $image_error = __( 'Requested image with id (%2$s) doesn\'t exist (%1$s).', 'nggallery' ); } catch ( \E_EntityNotFoundException $e ) { // gallery doesn't exist - already checked above so this should never happen. } } } if ( $image_error != null ) { $image_status = 'error'; $image['error'] = [ 'level' => 'fatal', 'message' => sprintf( $image_error, $image_filename, $image_id ), ]; } if ( $image_id ) { $image['id'] = $image_id; } if ( $image_status ) { $image['status'] = $image_status; } if ( $image_status != 'queued' ) { // append processed image to result image_list array. $result_images[] = $image; } if ( $this->should_stop_execution() ) { break; } } $task_result['image_list'] = $result_images; $image_list_unfinished = count( $result_images ) < $image_count; // if images have finished processing, remove the folder used to store the temporary images (the folder should be empty due to delete() calls above). if ( ! $image_list_unfinished && $storage_path != null && $storage_path != $fs_sep && $path_prefix != null && $path_prefix != $fs_sep ) { $wp_fs->rmdir( $images_folder ); } } elseif ( $wp_fs == null ) { $error = __( 'Could not access file system for gallery (%1$s).', 'nggallery' ); } if ( ! $gallery->save() ) { if ( $error == null ) { $gal_errors = '[' . json_encode( $gallery->validation() ) . ']'; $error = __( 'Failed to save modified gallery (%1$s). ' . $gal_errors, 'nggallery' ); } } } } else { $error = __( 'Could not find gallery (%1$s).', 'nggallery' ); } // XXX workaround for $gallery->save() returning false even if successful. if ( isset( $task_result['image_list'] ) && $gallery != null ) { $task_result['object_id'] = $gallery->id(); } if ( $error == null ) { $task_status = 'done'; $task_result['object_id'] = $gallery->id(); } else { $task_status = 'error'; $task_error = [ 'level' => 'fatal', 'message' => sprintf( $error, (string) $task_query['id'] ), ]; } if ( $image_list_unfinished ) { // we override the status of the task when the image list has not finished processing. $task_status = 'unfinished'; } } else { $task_status = 'error'; $task_error = [ 'level' => 'fatal', 'message' => __( 'No gallery was specified to edit.', 'nggallery' ), ]; } break; } case 'album_add': { $mapper = AlbumMapper::get_instance(); $name = isset( $task_object['name'] ) ? $task_object['name'] : ''; $desc = isset( $task_object['description'] ) ? $task_object['description'] : ''; $previewpic = isset( $task_object['preview_image'] ) ? $task_object['preview_image'] : 0; $sortorder = isset( $task_object['sort_order'] ) ? $task_object['sort_order'] : ''; $page_id = isset( $task_object['page_id'] ) ? $task_object['page_id'] : 0; $album = null; if ( isset( $task_query['id'] ) ) { $album = $mapper->find( $task_query['id'], true ); } if ( $album == null ) { $album = $mapper->create( [ 'name' => $name, 'previewpic' => $previewpic, 'albumdesc' => $desc, 'sortorder' => $sortorder, 'pageid' => $page_id, ] ); if ( ! $album || ! $album->save() ) { $album = null; } } if ( $album != null ) { $task_status = 'done'; $task_result['object_id'] = $album->id(); } else { $task_status = 'error'; $task_error = [ 'level' => 'fatal', 'message' => __( 'Album creation failed.', 'nggallery' ), ]; } break; } case 'album_remove': case 'album_edit': { if ( isset( $task_query['id'] ) ) { $mapper = AlbumMapper::get_instance(); $album = $mapper->find( $task_query['id'], true ); $error = null; if ( $album ) { if ( $task_type == 'album_remove' ) { if ( ! $mapper->destroy( $album ) ) { $error = __( 'Failed to remove album (%1$s).', 'nggallery' ); } } elseif ( $task_type == 'album_edit' ) { if ( isset( $task_object['name'] ) ) { $album->name = $task_object['name']; } if ( isset( $task_object['description'] ) ) { $album->albumdesc = $task_object['description']; } if ( isset( $task_object['preview_image'] ) ) { $album->previewpic = $task_object['preview_image']; } if ( isset( $task_object['property_list'] ) ) { $properties = $task_object['property_list']; foreach ( $properties as $key => $value ) { $album->$key = $value; } } if ( isset( $task_object['item_list'] ) ) { $item_list = $task_object['item_list']; $sortorder = $album->sortorder; $count = count( $sortorder ); $album_items = []; for ( $index = 0; $index < $count; $index++ ) { $album_items[ $sortorder[ $index ] ] = $index; } foreach ( $item_list as $item_info ) { $item_id = isset( $item_info['id'] ) ? $item_info['id'] : null; $item_type = isset( $item_info['type'] ) ? $item_info['type'] : null; $item_index = isset( $item_info['index'] ) ? $item_info['index'] : null; // translate ID in case this gallery has been created as part of this job. $item_id = $this->get_object_id( $item_id, $task_list_result ); if ( $item_id != null ) { if ( $item_type == 'album' ) { $item_id = 'a' . $item_id; } $album_items[ $item_id ] = $count + $item_index; } } asort( $album_items ); $album->sortorder = array_keys( $album_items ); } if ( ! $mapper->save( $album ) ) { $error = __( 'Failed to save modified album (%1$s).', 'nggallery' ); } } } else { $error = __( 'Could not find album (%1$s).', 'nggallery' ); } if ( $error == null ) { $task_status = 'done'; $task_result['object_id'] = $album->id(); } else { $task_status = 'error'; $task_error = [ 'level' => 'fatal', 'message' => sprintf( $error, (string) $task_query['id'] ), ]; } } else { $task_status = 'error'; $task_error = [ 'level' => 'fatal', 'message' => __( 'No album was specified to edit.', 'nggallery' ), ]; } break; } case 'gallery_list_get': { $mapper = GalleryMapper::get_instance(); $gallery_list = $mapper->find_all(); $result_list = []; foreach ( $gallery_list as $gallery ) { $gallery_result = [ 'id' => $gallery->id(), 'name' => $gallery->name, 'title' => $gallery->title, 'description' => $gallery->galdesc, 'preview_image' => $gallery->previewpic, ]; $result_list[] = $gallery_result; } $task_status = 'done'; $task_result['gallery_list'] = $result_list; break; } case 'image_list_move': { break; } } $task_item['result'] = $task_result; $task_item['status'] = $task_status; $task_item['error'] = $task_error; // for previously finished tasks, store the result as it may be needed by future tasks. if ( $task_id != null && $task_result != null ) { $task_list_result[ $task_id ] = $task_result; } // if the task has finished, either successfully or unsuccessfully, increase count for done tasks. if ( 'unfinished' != $task_status ) { ++$done_count; } if ( $this->should_stop_execution() ) { break; } } $this->set_job_task_list( $job_id, $task_list ); if ( $task_count > $done_count + $skip_count ) { // unfinished tasks, return false. return false; } else { $upload_method = isset( $app_config['upload_method'] ) ? $app_config['upload_method'] : 'ftp'; if ( 'ftp' == $upload_method ) { // everything was finished, write status file. $status_file = '_ngg_job_status_' . strval( $job_id ) . '.txt'; $status_content = json_encode( $task_list ); if ( null != $wp_fs ) { $status_path = $path_prefix . $fs_sep . $status_file; $status_path = str_replace( [ '\\', '/' ], $fs_sep, $status_path ); $wp_fs->put_contents( $status_path, $status_content ); } else { // if WP_Filesystem failed try one last desperate attempt at direct file writing. $status_path = str_replace( $ftp_path, $root_path, $full_path ) . DIRECTORY_SEPARATOR . $status_file; $status_path = str_replace( [ '\\', '/' ], DIRECTORY_SEPARATOR, $status_path ); file_put_contents( $status_path, $status_content ); } } return true; } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/Image.php���������������������������������������������������������������������������������0000644�����������������00000003703�15021223045�0010172 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMapper\Model; use Imagely\NGG\DataMappers\Image as Mapper; use Imagely\NGG\DataStorage\Sanitizer; class Image extends Model { public $alttext; public $description; public $exclude; public $extras_post_id; public $filename; public $galleryid; public $id_field = 'pid'; public $image_slug; public $imagedate; public $meta_data = []; public $pid; public $post_id; public $sortorder; public $tags; public $updated_at; // TODO: remove this when get_pro_compat_level() >= 1. public $items = []; public $pricelist_id; public $title; public function get_primary_key_column() { return 'pid'; } public function get_mapper() { return Mapper::get_instance(); } /** * Returns the model representing the gallery associated with this image. * * @param object|false $model (optional) * @return Gallery */ public function get_gallery( $model = false ) { return \Imagely\NGG\DataMappers\Gallery::get_instance()->find( $this->galleryid, $model ); } public function validation() { if ( isset( $this->description ) ) { $this->description = Sanitizer::strip_html( $this->description, true ); } if ( isset( $this->alttext ) ) { $this->alttext = Sanitizer::strip_html( $this->alttext, true ); } $errors = array_merge( [], $this->validates_presence_of( 'galleryid' ), $this->validates_presence_of( 'filename' ), $this->validates_presence_of( 'alttext' ), $this->validates_presence_of( 'exclude' ), $this->validates_presence_of( 'sortorder' ), $this->validates_presence_of( 'imagedate' ), $this->validates_numericality_of( 'galleryid' ), $this->validates_numericality_of( 'pid' ), $this->validates_numericality_of( 'sortorder' ), $this->validates_length_of( 'filename', 185, '<=', __( 'Image filenames may not be longer than 185 characters in length', 'nextgen-gallery' ) ) ); return empty( $errors ) ? true : $errors; } } �������������������������������������������������������������DataTypes/Lightbox.php������������������������������������������������������������������������������0000644�����������������00000001370�15021223045�0010726 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; class Lightbox { public $id = ''; public $name = ''; public $title = ''; public $code = ''; public $values = []; public $scripts = []; public $styles = []; public $albums_supported = false; public function __construct( $id = '' ) { $this->id = $id; } /** * Returns whether the lightbox supports displaying entities from the displayed gallery object. * Most lightbox do not support displaying albums. * * @param DisplayedGallery $displayed_gallery * @return bool */ public function is_supported( $displayed_gallery ) { return ! in_array( $displayed_gallery->source, [ 'album', 'albums' ] ) || isset( $displayed_gallery->display_settings['open_gallery_in_lightbox'] ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/LegacyThumbnail.php�����������������������������������������������������������������������0000644�����������������00000105225�15021223045�0012222 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; /** * PHP class for dynamically resizing, cropping, and rotating images for thumbnail purposes and either displaying them on-the-fly or saving them. */ class LegacyThumbnail { /** * Error message to display, if any * * @var string */ public $errmsg; /** * Whether or not there is an error * * @var boolean */ public $error; /** * Format of the image file * * @var string */ public $format; /** * File name and path of the image file * * @var string */ public $fileName; /** * Current dimensions of working image * * @var array */ public $currentDimensions; /** * New dimensions of working image * * @var array */ public $newDimensions; /** * Image resource for newly manipulated image * * @var resource * @access private */ public $newImage; /** * Image resource for image before previous manipulation * * @var resource * @access private */ public $oldImage; /** * Image resource for image being currently manipulated * * @var resource * @access private */ public $workingImage; /** * Percentage to resize image by * * @var int * @access private */ public $percent; /** * Maximum width of image during resize * * @var int * @access private */ public $maxWidth; /** * Maximum height of image during resize * * @var int * @access private */ public $maxHeight; /** * Image for Watermark * * @var string */ public $watermarkImgPath; /** * Text for Watermark * * @var string */ public $watermarkText; public $newWidth; public $newHeight; /** * Image Resource ID for Watermark * * @var string */ public function __construct( $fileName, $no_ErrorImage = false ) { // make sure the GD library is installed. if ( ! function_exists( 'gd_info' ) ) { echo 'You do not have the GD Library installed. This class requires the GD library to function properly.' . "\n"; echo 'visit http://us2.php.net/manual/en/ref.image.php for more information'; throw new \E_No_Image_Library_Exception(); } // initialize variables. $this->errmsg = ''; $this->error = false; $this->currentDimensions = []; $this->newDimensions = []; $this->fileName = $fileName; $this->percent = 100; $this->maxWidth = 0; $this->maxHeight = 0; $this->watermarkImgPath = ''; $this->watermarkText = ''; // check to see if file exists. if ( ! @file_exists( $this->fileName ) ) { $this->errmsg = 'File not found'; $this->error = true; } // check to see if file is readable. elseif ( ! is_readable( $this->fileName ) ) { $this->errmsg = 'File is not readable'; $this->error = true; } $image_size = null; // if there are no errors, determine the file format. if ( $this->error == false ) { @ini_set( 'memory_limit', -1 ); $image_size = @getimagesize( $this->fileName ); if ( isset( $image_size ) && is_array( $image_size ) ) { $extensions = [ IMAGETYPE_GIF => 'GIF', IMAGETYPE_JPEG => 'JPG', IMAGETYPE_PNG => 'PNG', IMAGETYPE_WEBP => 'WEBP', ]; $extension = array_key_exists( $image_size[2], $extensions ) ? $extensions[ $image_size[2] ] : ''; if ( $extension ) { $this->format = $extension; } else { $this->errmsg = 'Unknown file format'; $this->error = true; } } else { $this->errmsg = 'File is not an image'; $this->error = true; } } // increase memory-limit if possible, GD needs this for large images. if ( ! extension_loaded( 'suhosin' ) ) { @ini_set( 'memory_limit', '512M' ); } if ( $this->error == false ) { // Check memory consumption if file exists. $this->checkMemoryForImage( $this->fileName ); } // initialize resources if no errors. if ( $this->error == false ) { $img_err = null; switch ( $this->format ) { case 'GIF': if ( function_exists( 'ImageCreateFromGif' ) ) { $this->oldImage = @ImageCreateFromGif( $this->fileName ); } else { $img_err = __( 'Support for GIF format is missing.', 'nggallery' ); } break; case 'JPG': if ( function_exists( 'ImageCreateFromJpeg' ) ) { $this->oldImage = @ImageCreateFromJpeg( $this->fileName ); } else { $img_err = __( 'Support for JPEG format is missing.', 'nggallery' ); } break; case 'PNG': if ( function_exists( 'ImageCreateFromPng' ) ) { $this->oldImage = @ImageCreateFromPng( $this->fileName ); } else { $img_err = __( 'Support for PNG format is missing.', 'nggallery' ); } break; case 'WEBP': if ( function_exists( 'imagecreatefromwebp' ) ) { $this->oldImage = @imagecreatefromwebp( $this->fileName ); } else { $img_err = __( 'Support for WEBP format is missing.', 'nggallery' ); } break; } if ( ! $this->oldImage ) { if ( $img_err == null ) { $img_err = __( 'Check memory limit', 'nggallery' ); } $this->errmsg = sprintf( __( 'Create Image failed. %1$s', 'nggallery' ), $img_err ); $this->error = true; } else { $this->currentDimensions = [ 'width' => $image_size[0], 'height' => $image_size[1], ]; $this->newImage = $this->oldImage; } } if ( $this->error == true ) { if ( ! $no_ErrorImage ) { $this->showErrorImage(); } return; } } /** * Calculate the memory limit * * @param string $filename */ public function checkMemoryForImage( $filename ) { $imageInfo = getimagesize( $filename ); switch ( $this->format ) { case 'GIF': // measured factor 1 is better. $CHANNEL = 1; break; case 'JPG': $CHANNEL = $imageInfo['channels']; break; case 'PNG': // didn't get the channel for png. $CHANNEL = 3; break; case 'WEBP': $CHANNEL = $imageInfo['bits']; break; } $bits = ( ! empty( $imageInfo['bits'] ) ? $imageInfo['bits'] : 32 ); // imgInfo[bits] is not always available. return $this->checkMemoryForData( $imageInfo[0], $imageInfo[1], $CHANNEL, $bits ); } public function checkMemoryForData( $width, $height, $channels = null, $bits = null ) { $imageInfo = getimagesize( $this->fileName ); if ( $channels == null ) { switch ( $this->format ) { case 'GIF': // measured factor 1 is better. $channels = 1; break; case 'JPG': $channels = $imageInfo['channels']; break; case 'PNG': // didn't get the channel for png. $channels = 3; break; case 'WEBP': $channels = $imageInfo['bits']; break; } } if ( $bits == null ) { $bits = ( ! empty( $imageInfo['bits'] ) ? $imageInfo['bits'] : 32 ); // imgInfo[bits] is not always available. } if ( ( function_exists( 'memory_get_usage' ) ) && ( ini_get( 'memory_limit' ) ) ) { $MB = 1048576; // number of bytes in 1M. $K64 = 65536; // number of bytes in 64K. $TWEAKFACTOR = 1.68; // Or whatever works for you. $memoryNeeded = round( ( doubleval( $width * $height * $bits * $channels ) / 8 + $K64 ) * $TWEAKFACTOR ); $memoryNeeded = memory_get_usage() + $memoryNeeded; // get memory limit. $memory_limit = ini_get( 'memory_limit' ); // PHP docs : Note that to have no memory limit, set this directive to -1. if ( $memory_limit == -1 ) { return true; } // Just check megabyte limits, not higher. if ( strtolower( substr( $memory_limit, -1 ) ) == 'm' ) { if ( $memory_limit != '' ) { $memory_limit = intval( substr( $memory_limit, 0, -1 ) ) * 1024 * 1024; } if ( $memoryNeeded > $memory_limit ) { $memoryNeeded = round( $memoryNeeded / 1024 / 1024, 2 ); $this->errmsg = 'Exceed Memory limit. Require : ' . $memoryNeeded . ' MByte'; $this->error = true; return false; } } } return true; } public function __destruct() { $this->destruct(); } /** * Must be called to free up allocated memory after all manipulations are done */ public function destruct() { if ( is_resource( $this->newImage ) || $this->newImage instanceof \GdImage ) { @imagedestroy( $this->newImage ); } if ( is_resource( $this->oldImage ) || $this->oldImage instanceof \GdImage ) { @imagedestroy( $this->oldImage ); } if ( is_resource( $this->workingImage ) || $this->workingImage instanceof \GdImage ) { @imagedestroy( $this->workingImage ); } } /** * Returns the current width of the image * * @return int */ public function getCurrentWidth() { return $this->currentDimensions['width']; } /** * Returns the current height of the image * * @return int */ public function getCurrentHeight() { return $this->currentDimensions['height']; } /** * Calculates new image width * * @param int $width * @param int $height * @return array */ public function calcWidth( $width, $height ) { $newWp = ( 100 * $this->maxWidth ) / $width; $newHeight = ( $height * $newWp ) / 100; if ( intval( $newHeight ) == $this->maxHeight - 1 ) { $newHeight = $this->maxHeight; } return [ 'newWidth' => intval( $this->maxWidth ), 'newHeight' => intval( $newHeight ), ]; } /** * Calculates new image height * * @param int $width * @param int $height * @return array */ public function calcHeight( $width, $height ) { $newHp = ( 100 * $this->maxHeight ) / $height; $newWidth = ( $width * $newHp ) / 100; if ( intval( $newWidth ) == $this->maxWidth - 1 ) { $newWidth = $this->maxWidth; } return [ 'newWidth' => intval( $newWidth ), 'newHeight' => intval( $this->maxHeight ), ]; } /** * Calculates new image size based on percentage * * @param int $width * @param int $height * @return array */ public function calcPercent( $width, $height, $percent = -1 ) { if ( $percent == -1 ) { $percent = $this->percent; } $newWidth = ( $width * $percent ) / 100; $newHeight = ( $height * $percent ) / 100; return [ 'newWidth' => intval( $newWidth ), 'newHeight' => intval( $newHeight ), ]; } /** * Calculates new image size based on width and height, while constraining to maxWidth and maxHeight * * @param int $width * @param int $height */ public function calcImageSize( $width, $height ) { // $width and $height are the CURRENT image resolutions $ratio_w = $this->maxWidth / $width; $ratio_h = $this->maxHeight / $height; if ( $ratio_w >= $ratio_h ) { $width = $this->maxWidth; $height = (int) round( $height * $ratio_h, 0 ); } else { $height = $this->maxHeight; $width = (int) round( $width * $ratio_w, 0 ); } $this->newDimensions = [ 'newWidth' => $width, 'newHeight' => $height, ]; } /** * Calculates new image size based percentage * * @param int $width * @param int $height */ public function calcImageSizePercent( $width, $height ) { if ( $this->percent > 0 ) { $this->newDimensions = $this->calcPercent( $width, $height ); } } /** * Displays error image */ public function showErrorImage() { header( 'Content-type: image/png' ); $errImg = ImageCreate( 220, 25 ); $bgColor = imagecolorallocate( $errImg, 0, 0, 0 ); $fgColor1 = imagecolorallocate( $errImg, 255, 255, 255 ); $fgColor2 = imagecolorallocate( $errImg, 255, 0, 0 ); imagestring( $errImg, 3, 6, 6, 'Error:', $fgColor2 ); imagestring( $errImg, 3, 55, 6, $this->errmsg, $fgColor1 ); imagepng( $errImg ); imagedestroy( $errImg ); } /** * Resizes image to fixed Width x Height * * @param int $Width * @param int $Height * @param int $deprecated Unused */ public function resizeFix( $Width = 0, $Height = 0, $deprecated = 3 ) { if ( ! $this->checkMemoryForData( $Width, $Height ) ) { return; } $this->newWidth = $Width; $this->newHeight = $Height; if ( function_exists( 'ImageCreateTrueColor' ) ) { $this->workingImage = ImageCreateTrueColor( $this->newWidth, $this->newHeight ); } else { $this->workingImage = ImageCreate( $this->newWidth, $this->newHeight ); } // ImageCopyResampled(. $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $this->newWidth; $this->currentDimensions['height'] = $this->newHeight; } /** * Resizes image to maxWidth x maxHeight * * @param int $maxWidth * @param int $maxHeight * @param int $deprecated Unused */ public function resize( $maxWidth = 0, $maxHeight = 0, $deprecated = 3 ) { if ( ! $this->checkMemoryForData( $maxWidth, $maxHeight ) ) { return; } $this->maxWidth = $maxWidth; $this->maxHeight = $maxHeight; $this->calcImageSize( $this->currentDimensions['width'], $this->currentDimensions['height'] ); if ( $this->workingImage != null && $this->workingImage != $this->oldImage ) { ImageDestroy( $this->workingImage ); $this->workingImage = null; } if ( function_exists( 'ImageCreateTrueColor' ) ) { $this->workingImage = ImageCreateTrueColor( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } else { $this->workingImage = ImageCreate( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height'] ); ImageDestroy( $this->oldImage ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $this->newDimensions['newWidth']; $this->currentDimensions['height'] = $this->newDimensions['newHeight']; } /** * Resizes the image by $percent percent * * @param int $percent */ public function resizePercent( $percent = 0 ) { $dims = $this->calcPercent( $this->currentDimensions['width'], $this->currentDimensions['height'], $percent ); if ( ! $this->checkMemoryForData( $dims['newWidth'], $dims['newHeight'] ) ) { return; } $this->percent = $percent; $this->calcImageSizePercent( $this->currentDimensions['width'], $this->currentDimensions['height'] ); if ( function_exists( 'ImageCreateTrueColor' ) ) { $this->workingImage = ImageCreateTrueColor( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } else { $this->workingImage = ImageCreate( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } $this->ImageCopyResampled( $this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $this->newDimensions['newWidth']; $this->currentDimensions['height'] = $this->newDimensions['newHeight']; } /** * Crops the image from calculated center in a square of $cropSize pixels * * @param int $cropSize */ public function cropFromCenter( $cropSize ) { if ( $cropSize > $this->currentDimensions['width'] ) { $cropSize = $this->currentDimensions['width']; } if ( $cropSize > $this->currentDimensions['height'] ) { $cropSize = $this->currentDimensions['height']; } $cropX = intval( ( $this->currentDimensions['width'] - $cropSize ) / 2 ); $cropY = intval( ( $this->currentDimensions['height'] - $cropSize ) / 2 ); if ( $this->workingImage != null && $this->workingImage != $this->oldImage ) { ImageDestroy( $this->workingImage ); $this->workingImage = null; } if ( function_exists( 'ImageCreateTrueColor' ) ) { $this->workingImage = ImageCreateTrueColor( $cropSize, $cropSize ); } else { $this->workingImage = ImageCreate( $cropSize, $cropSize ); } $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, $cropX, $cropY, $cropSize, $cropSize, $cropSize, $cropSize ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $cropSize; $this->currentDimensions['height'] = $cropSize; } /** * Advanced cropping function that crops an image using $startX and $startY as the upper-left hand corner. * * @param int $startX * @param int $startY * @param int $width * @param int $height */ public function crop( $startX, $startY, $width, $height ) { if ( ! $this->checkMemoryForData( $width, $height ) ) { return; } // make sure the cropped area is not greater than the size of the image. if ( $width > $this->currentDimensions['width'] ) { $width = $this->currentDimensions['width']; } if ( $height > $this->currentDimensions['height'] ) { $height = $this->currentDimensions['height']; } // make sure not starting outside the image. if ( ( $startX + $width ) > $this->currentDimensions['width'] ) { $startX = ( $this->currentDimensions['width'] - $width ); } if ( ( $startY + $height ) > $this->currentDimensions['height'] ) { $startY = ( $this->currentDimensions['height'] - $height ); } if ( $startX < 0 ) { $startX = 0; } if ( $startY < 0 ) { $startY = 0; } if ( $this->workingImage != null && $this->workingImage != $this->oldImage ) { ImageDestroy( $this->workingImage ); $this->workingImage = null; } if ( function_exists( 'ImageCreateTrueColor' ) ) { $this->workingImage = ImageCreateTrueColor( $width, $height ); } else { $this->workingImage = ImageCreate( $width, $height ); } $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, $startX, $startY, $width, $height, $width, $height ); ImageDestroy( $this->oldImage ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $width; $this->currentDimensions['height'] = $height; } /** * Outputs the image to the screen, or saves to $name if supplied. Quality of JPEG images can be controlled with the $quality variable * * @param int $quality * @param string $name */ public function show( $quality = 100, $name = '' ) { switch ( $this->format ) { case 'GIF': if ( $name != '' ) { @ImageGif( $this->newImage, $name ) or $this->error = true; } else { header( 'Content-type: image/gif' ); ImageGif( $this->newImage ); } break; case 'JPG': if ( $name != '' ) { @ImageJpeg( $this->newImage, $name, $quality ) or $this->error = true; } else { header( 'Content-type: image/jpeg' ); ImageJpeg( $this->newImage, null, $quality ); } break; case 'PNG': if ( $name != '' ) { @ImagePng( $this->newImage, $name ) or $this->error = true; } else { header( 'Content-type: image/png' ); ImagePng( $this->newImage ); } break; case 'WEBP': if ( $name != '' ) { $this->error = ! @imagewebp( $this->newImage, $name ); } else { header( 'Content-type: image/webp' ); imagewebp( $this->newImage ); } break; } } /** * Saves image as $name (can include file path), with quality of # percent if file is a jpeg * * @param string $name * @param int $quality * @return bool errorstate */ public function save( $name, $quality = 100 ) { $this->show( $quality, $name ); if ( $this->error == true ) { $this->errmsg = 'Create Image failed. Check safe mode settings'; return false; } if ( function_exists( 'do_action' ) ) { do_action( 'ngg_ajax_image_save', $name ); } return true; } /** * Creates Apple-style reflection under image, optionally adding a border to main image * * @param int $percent * @param int $reflection * @param int $white * @param bool $border * @param string $borderColor */ public function createReflection( $percent, $reflection, $white, $border = true, $borderColor = '#a4a4a4' ) { $width = $this->currentDimensions['width']; $height = $this->currentDimensions['height']; $reflectionHeight = intval( $height * ( $reflection / 100 ) ); $newHeight = $height + $reflectionHeight; $reflectedPart = $height * ( $percent / 100 ); $this->workingImage = ImageCreateTrueColor( $width, $newHeight ); ImageAlphaBlending( $this->workingImage, true ); $colorToPaint = ImageColorAllocateAlpha( $this->workingImage, 255, 255, 255, 0 ); ImageFilledRectangle( $this->workingImage, 0, 0, $width, $newHeight, $colorToPaint ); imagecopyresampled( $this->workingImage, $this->newImage, 0, 0, 0, $reflectedPart, $width, $reflectionHeight, $width, ( $height - $reflectedPart ) ); $this->imageFlipVertical(); imagecopy( $this->workingImage, $this->newImage, 0, 0, 0, 0, $width, $height ); imagealphablending( $this->workingImage, true ); for ( $i = 0;$i < $reflectionHeight;$i++ ) { $colorToPaint = imagecolorallocatealpha( $this->workingImage, 255, 255, 255, ( $i / $reflectionHeight * -1 + 1 ) * $white ); imagefilledrectangle( $this->workingImage, 0, $height + $i, $width, $height + $i, $colorToPaint ); } if ( $border == true ) { $rgb = $this->hex2rgb( $borderColor, false ); $colorToPaint = imagecolorallocate( $this->workingImage, $rgb[0], $rgb[1], $rgb[2] ); imageline( $this->workingImage, 0, 0, $width, 0, $colorToPaint ); // top line. imageline( $this->workingImage, 0, $height, $width, $height, $colorToPaint ); // bottom line. imageline( $this->workingImage, 0, 0, 0, $height, $colorToPaint ); // left line. imageline( $this->workingImage, $width - 1, 0, $width - 1, $height, $colorToPaint ); // right line. } $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $width; $this->currentDimensions['height'] = $newHeight; } /** * Flip an image. * * @param bool $horz flip the image in horizontal mode * @param bool $vert flip the image in vertical mode * @return true */ public function flipImage( $horz = false, $vert = false ) { $sx = $vert ? ( $this->currentDimensions['width'] - 1 ) : 0; $sy = $horz ? ( $this->currentDimensions['height'] - 1 ) : 0; $sw = $vert ? -$this->currentDimensions['width'] : $this->currentDimensions['width']; $sh = $horz ? -$this->currentDimensions['height'] : $this->currentDimensions['height']; $this->workingImage = imagecreatetruecolor( $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, $sx, $sy, $this->currentDimensions['width'], $this->currentDimensions['height'], $sw, $sh ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; return true; } /** * Rotate an image clockwise or counter clockwise * * @param string $dir Either CW or CCW * @return bool */ public function rotateImage( $dir = 'CW' ) { $angle = ( $dir == 'CW' ) ? 90 : -90; return $this->rotateImageAngle( $angle ); } /** * Rotate an image clockwise or counter clockwise * * @param int $angle Degrees to rotate the target image * @return bool */ public function rotateImageAngle( $angle = 90 ) { if ( function_exists( 'imagerotate' ) ) { $this->currentDimensions['width'] = imagesx( $this->workingImage ); $this->currentDimensions['height'] = imagesy( $this->workingImage ); $this->oldImage = $this->workingImage; // imagerotate() rotates CCW ;. // See for help: https://evertpot.com/115/. $this->newImage = imagerotate( $this->oldImage, 360 - $angle, 0 ); return true; } $this->workingImage = imagecreatetruecolor( $this->currentDimensions['height'], $this->currentDimensions['width'] ); imagealphablending( $this->workingImage, false ); imagesavealpha( $this->workingImage, true ); switch ( $angle ) { case 90: for ( $x = 0; $x < $this->currentDimensions['width']; $x++ ) { for ( $y = 0; $y < $this->currentDimensions['height']; $y++ ) { if ( ! imagecopy( $this->workingImage, $this->oldImage, $this->currentDimensions['height'] - $y - 1, $x, $x, $y, 1, 1 ) ) { return false; } } } break; case -90: for ( $x = 0; $x < $this->currentDimensions['width']; $x++ ) { for ( $y = 0; $y < $this->currentDimensions['height']; $y++ ) { if ( ! imagecopy( $this->workingImage, $this->oldImage, $y, $this->currentDimensions['width'] - $x - 1, $x, $y, 1, 1 ) ) { return false; } } } break; default: return false; } $this->currentDimensions['width'] = imagesx( $this->workingImage ); $this->currentDimensions['height'] = imagesy( $this->workingImage ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; return true; } /** * Inverts working image, used by reflection function * * @access private */ public function imageFlipVertical() { $x_i = imagesx( $this->workingImage ); $y_i = imagesy( $this->workingImage ); for ( $x = 0; $x < $x_i; $x++ ) { for ( $y = 0; $y < $y_i; $y++ ) { imagecopy( $this->workingImage, $this->workingImage, $x, $y_i - $y - 1, $x, $y, 1, 1 ); } } } /** * Converts hexidecimal color value to rgb values and returns as array/string * * @param string $hex * @param bool $asString * @return array|string */ public function hex2rgb( $hex, $asString = false ) { // strip off any leading #. if ( 0 === strpos( $hex, '#' ) ) { $hex = substr( $hex, 1 ); } elseif ( 0 === strpos( $hex, '&H' ) ) { $hex = substr( $hex, 2 ); } // break into hex 3-tuple. $cutpoint = ceil( strlen( $hex ) / 2 ) - 1; $rgb = explode( ':', wordwrap( $hex, $cutpoint, ':', $cutpoint ), 3 ); // convert each tuple to decimal. $rgb[0] = ( isset( $rgb[0] ) ? hexdec( $rgb[0] ) : 0 ); $rgb[1] = ( isset( $rgb[1] ) ? hexdec( $rgb[1] ) : 0 ); $rgb[2] = ( isset( $rgb[2] ) ? hexdec( $rgb[2] ) : 0 ); return ( $asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb ); } /** * Based on the Watermark function by Marek Malcherek * http://www.malcherek.de * * @param string $color * @param string $wmFont * @param int $wmSize * @param int $wmOpaque */ public function watermarkCreateText( $color, $wmFont, $wmSize = 10, $wmOpaque = 90 ) { if ( empty( $this->watermarkText ) ) { return; } if ( ! $color ) { $color = '000000'; } // set font path. $wmFontPath = NGGALLERY_ABSPATH . 'fonts/' . $wmFont; if ( ! is_readable( $wmFontPath ) ) { return; } // This function requires both the GD library and the FreeType library. if ( ! function_exists( 'ImageTTFBBox' ) ) { return; } $words = preg_split( '/ /', $this->watermarkText ); $lines = []; $line = ''; $watermark_image_width = 0; // attempt adding a new word until the width is too large; then start a new line and start again. foreach ( $words as $word ) { // sanitize the text being input; imagettftext() can be sensitive. $TextSize = $this->ImageTTFBBoxDimensions( $wmSize, 0, $this->correct_gd_unc_path( $wmFontPath ), $line . preg_replace( '~^(&([a-zA-Z0-9]);)~', htmlentities( '${1}' ), htmlspecialchars_decode( htmlentities( $word, ENT_QUOTES, 'UTF-8' ) ) ) ); if ( $watermark_image_width == 0 ) { $watermark_image_width = $TextSize['width']; } if ( $TextSize['width'] > $this->newDimensions['newWidth'] ) { $lines[] = trim( $line ); $line = ''; } elseif ( $TextSize['width'] > $watermark_image_width ) { $watermark_image_width = $TextSize['width']; } $line .= $word . ' '; } $lines[] = trim( $line ); // use this string to determine our largest possible line height. $line_dimensions = $this->ImageTTFBBoxDimensions( $wmSize, 0, $this->correct_gd_unc_path( $wmFontPath ), 'MXQJALYmxqjabdfghjklpqry019`@$^&*(,!132' ); $line_height = (float) $line_dimensions['height'] * 1.05; // Create an image to apply our text to. $this->workingImage = ImageCreateTrueColor( $watermark_image_width, (int) ( count( $lines ) * $line_height ) ); ImageSaveAlpha( $this->workingImage, true ); ImageAlphaBlending( $this->workingImage, false ); $bgText = imagecolorallocatealpha( $this->workingImage, 255, 255, 255, 127 ); imagefill( $this->workingImage, 0, 0, $bgText ); $wmTransp = 127 - ( (int) $wmOpaque * 1.27 ); $rgb = $this->hex2rgb( $color, false ); $TextColor = imagecolorallocatealpha( $this->workingImage, (int) $rgb[0], (int) $rgb[1], (int) $rgb[2], (int) $wmTransp ); // Put text on the image, line-by-line. $y_pos = $wmSize; foreach ( $lines as $line ) { imagettftext( $this->workingImage, $wmSize, 0, 0, $y_pos, $TextColor, $this->correct_gd_unc_path( $wmFontPath ), $line ); $y_pos += $line_height; } $this->watermarkImgPath = $this->workingImage; return; } /** * Returns a path that can be used with imagettftext() and ImageTTFBBox() * * imagettftext() and ImageTTFBBox() cannot load resources from Windows UNC paths * and require they be mangled to be like //server\filename instead of \\server\filename * * @param string $path Absolute file path * @return string $path Mangled absolute file path */ public function correct_gd_unc_path( $path ) { if ( strtoupper( substr( PHP_OS, 0, 3 ) ) == 'WIN' && substr( $path, 0, 2 ) === '\\\\' ) { $path = ltrim( $path, '\\\\' ); $path = '//' . $path; } return $path; } /** * Calculates the width & height dimensions of ImageTTFBBox(). * * Note: ImageTTFBBox() is unreliable with large font sizes * * @param $wmSize * @param $fontAngle * @param $wmFontPath * @param $text * @return array */ public function ImageTTFBBoxDimensions( $wmSize, $fontAngle, $wmFontPath, $text ) { $box = @ImageTTFBBox( $wmSize, $fontAngle, $this->correct_gd_unc_path( $wmFontPath ), $text ); $max_x = max( [ $box[0], $box[2], $box[4], $box[6] ] ); $max_y = max( [ $box[1], $box[3], $box[5], $box[7] ] ); $min_x = min( [ $box[0], $box[2], $box[4], $box[6] ] ); $min_y = min( [ $box[1], $box[3], $box[5], $box[7] ] ); return [ 'width' => ( $max_x - $min_x ), 'height' => ( $max_y - $min_y ), ]; } public function applyFilter( $filterType ) { $args = func_get_args(); array_unshift( $args, $this->newImage ); return call_user_func_array( 'imagefilter', $args ); } /** * Modfied Watermark function by Steve Peart * http://parasitehosting.com/ * * @param string $relPOS * @param int $xPOS * @param int $yPOS */ public function watermarkImage( $relPOS = 'botRight', $xPOS = 0, $yPOS = 0 ) { // if it's a resource ID take it as watermark text image. if ( is_resource( $this->watermarkImgPath ) || $this->watermarkImgPath instanceof \GdImage ) { $this->workingImage = $this->watermarkImgPath; } else { // (possibly) search for the file from the document root. if ( ! is_file( $this->watermarkImgPath ) ) { $fs = \Imagely\NGG\Util\Filesystem::get_instance(); if ( is_file( $fs->join_paths( $fs->get_document_root( 'content' ), $this->watermarkImgPath ) ) ) { $this->watermarkImgPath = $fs->get_document_root( 'content' ) . $this->watermarkImgPath; } } if ( empty( $this->watermarkImgPath ) ) { return; } // Would you really want to use anything other than a png? $this->workingImage = @imagecreatefrompng( $this->watermarkImgPath ); // if it's not a valid file die... if ( empty( $this->workingImage ) or ( ! $this->workingImage ) ) { return; } } imagealphablending( $this->workingImage, false ); imagesavealpha( $this->workingImage, true ); $sourcefile_width = imageSX( $this->oldImage ); $sourcefile_height = imageSY( $this->oldImage ); $watermarkfile_width = imageSX( $this->workingImage ); $watermarkfile_height = imageSY( $this->workingImage ); switch ( substr( $relPOS, 0, 3 ) ) { case 'top': $dest_y = 0 + $yPOS; break; case 'mid': $dest_y = ( $sourcefile_height / 2 ) - ( $watermarkfile_height / 2 ); break; case 'bot': $dest_y = $sourcefile_height - $watermarkfile_height - $yPOS; break; default: $dest_y = 0; break; } switch ( substr( $relPOS, 3 ) ) { case 'Left': $dest_x = 0 + $xPOS; break; case 'Center': $dest_x = ( $sourcefile_width / 2 ) - ( $watermarkfile_width / 2 ); break; case 'Right': $dest_x = $sourcefile_width - $watermarkfile_width - $xPOS; break; default: $dest_x = 0; break; } // if a gif, we have to upsample it to a truecolor image. if ( $this->format == 'GIF' ) { $tempimage = imagecreatetruecolor( $sourcefile_width, $sourcefile_height ); imagecopy( $tempimage, $this->oldImage, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height ); $this->newImage = $tempimage; } $this->imagecopymerge_alpha( $this->newImage, $this->workingImage, $dest_x, $dest_y, 0, 0, $watermarkfile_width, $watermarkfile_height, 100 ); } /** * Wrapper to imagecopymerge() that allows PNG transparency */ public function imagecopymerge_alpha( $destination_image, $source_image, $destination_x, $destination_y, $source_x, $source_y, $source_w, $source_h, $pct ) { $cut = imagecreatetruecolor( $source_w, $source_h ); imagecopy( $cut, $destination_image, 0, 0, (int) $destination_x, (int) $destination_y, (int) $source_w, (int) $source_h ); imagecopy( $cut, $source_image, 0, 0, $source_x, $source_y, $source_w, $source_h ); imagecopymerge( $destination_image, $cut, (int) $destination_x, (int) $destination_y, 0, 0, (int) $source_w, (int) $source_h, (int) $pct ); } /** * Modfied imagecopyresampled function to save transparent images * See : http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/ * * @since 1.9.0 * * @param resource $dst_image * @param resource $src_image * @param int $dst_x * @param int $dst_y * @param int $src_x * @param int $src_y * @param int $dst_w * @param int $dst_h * @param int $src_w * @param int $src_h * @return bool */ public function imagecopyresampled( &$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) { // Check if this image is PNG or GIF, then set if Transparent. if ( $this->format == 'GIF' || $this->format == 'PNG' ) { imagealphablending( $dst_image, false ); imagesavealpha( $dst_image, true ); $transparent = imagecolorallocatealpha( $dst_image, 255, 255, 255, 127 ); imagefilledrectangle( $dst_image, 0, 0, $dst_w, $dst_h, $transparent ); } imagecopyresampled( $dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); return true; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/DisplayedGallery.php����������������������������������������������������������������������0000644�����������������00000102410�15021223045�0012401 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMapper\Model; use Imagely\NGG\DataMappers\Album as AlbumMapper; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\DataMappers\DisplayedGallery as Mapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\Display\I18N; use Imagely\NGG\DisplayedGallery\SourceManager; use Imagely\NGG\DisplayType\ControllerFactory; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Transient; class DisplayedGallery extends Model { public $ID; public $album_ids; public $container_ids; public $display; public $display_settings; public $display_type; public $effect_code; public $entity_ids; public $excluded_container_ids; public $exclusions; public $gallery_ids; public $id; public $ids; public $image_ids; public $images_list_count; public $inner_content; public $is_album_gallery; public $maximum_entity_count; public $order_by; public $order_direction; public $returns; public $skip_excluding_globally_excluded_images; public $slug; public $sortorder; public $source; public $src; public $tag_ids; public $tagcloud; public $transient_id; // The "alternative" approach to using "ORDER BY RAND()" works by finding X image PID in a kind of shotgun-blast // like scattering in a second query made via $wpdb that is then fed into the query built by _get_image_entities(). // This variable is used to cache the results of that inner quasi-random PID retrieval so that multiple calls // to $displayed_gallery->get_entities() don't return different results for each invocation. This is important // for NextGen Pro's galleria module in order to 'localize' the results of get_entities() to JSON. protected static $_random_image_ids_cache = []; public function __construct( \stdClass $object = null ) { parent::__construct( $object ); // Apply the default display type settings. if ( isset( $this->display_type ) ) { // Settings are stored in posts and must be found by their ID while shortcodes are likely using an alias. if ( ControllerFactory::has_controller( $this->display_type ) ) { $this->display_type = ControllerFactory::get_display_type_id( $this->display_type ); } $mapper = DisplayTypeMapper::get_instance(); $display_type = $mapper->find_by_name( $this->display_type ); if ( $display_type ) { $this->display_settings = array_merge( $display_type->settings, $this->display_settings ); $this->display_type = $display_type->name; } } // Only some sources should have their own maximum_entity_count. if ( ! empty( $this->display_settings['maximum_entity_count'] ) && in_array( $this->source, [ 'tag', 'tags', 'random_images', 'recent_images', 'random', 'recent' ] ) ) { $this->maximum_entity_count = $this->display_settings['maximum_entity_count']; } // If no maximum_entity_count has been given, then set a maximum. if ( ! isset( $this->maximum_entity_count ) ) { $settings = Settings::get_instance(); $this->maximum_entity_count = $settings->get( 'maximum_entity_count', 500 ); } \do_action( 'ngg_displayed_gallery_construct', $this ); } public function get_mapper() { return Mapper::get_instance(); } /** * @param int $limit Limit * @param int $offset Offset * @param bool $id_only ID Only * @param string $returns Included/Excluded * @return array */ public function get_entities( $limit = false, $offset = false, $id_only = false, $returns = 'included' ) { $retval = []; $source_obj = $this->get_source(); $max = $this->get_maximum_entity_count(); if ( ! $limit || ( is_numeric( $limit ) && $limit > $max ) ) { $limit = $max; } // Ensure that all parameters have values that are expected. if ( $this->_parse_parameters() ) { // Is this an image query? if ( in_array( 'image', $source_obj->returns ) ) { $retval = $this->_get_image_entities( $source_obj, $limit, $offset, $id_only, $returns ); } // Is this a gallery/album query? elseif ( in_array( 'gallery', $source_obj->returns ) ) { $retval = $this->_get_album_and_gallery_entities( $source_obj, $limit, $offset, $id_only, $returns ); } } return $retval; } /** * Gets all images in the displayed gallery * * @param \stdClass $source_obj * @param int $limit * @param int $offset * @param boolean $id_only * @param string $returns */ public function _get_image_entities( $source_obj, $limit, $offset, $id_only, $returns ) { global $wpdb; $settings = Settings::get_instance(); $mapper = ImageMapper::get_instance(); $image_key = $mapper->get_primary_key_column(); $select = $id_only ? $image_key : $mapper->get_table_name() . '.*'; if ( strtoupper( $this->order_direction ) == 'DSC' ) { $this->order_direction = 'DESC'; } $sort_direction = in_array( strtoupper( $this->order_direction ), [ 'ASC', 'DESC' ] ) ? $this->order_direction : $settings->get( 'galSortDir' ); $sort_by = in_array( strtolower( $this->order_by ), array_merge( ImageMapper::get_instance()->get_column_names(), [ 'rand()' ] ) ) ? $this->order_by : $settings->get( 'galSort' ); $this->container_ids = $this->container_ids ? array_map( [ $wpdb, '_escape' ], $this->container_ids ) : []; $this->entity_ids = $this->entity_ids ? array_map( [ $wpdb, '_escape' ], $this->entity_ids ) : []; $this->exclusions = $this->exclusions ? array_map( [ $wpdb, '_escape' ], $this->exclusions ) : []; // Here's what this method is doing: // 1) Determines what results need returned // 2) Determines from what container ids the results should come from // 3) Applies ORDER BY clause // 4) Applies LIMIT/OFFSET clause // 5) Executes the query and returns the result. // We start with the most difficult query. When returns is "both", we need to return a list of both included // and excluded entity ids, and mark specifically which entities are excluded. if ( $returns == 'both' ) { // We need to add two dynamic columns, one called "sortorder" and the other called "exclude". $if_true = 1; $if_false = 0; $excluded_set = $this->entity_ids; if ( ! $excluded_set ) { $if_true = 0; $if_false = 1; $excluded_set = $this->exclusions; } $sortorder_set = $this->sortorder ?: $excluded_set; // Add sortorder column. if ( $sortorder_set ) { $select = $this->_add_find_in_set_column( $select, $image_key, $sortorder_set, 'new_sortorder', true ); // A user might want to sort the results by the order of images that they specified to be included. // For that we need some trickery by reversing the order direction. $sort_direction = $this->order_direction == 'ASC' ? 'DESC' : 'ASC'; $sort_by = 'new_sortorder'; } // Add exclude column. if ( $excluded_set ) { $select = $this->_add_find_in_set_column( $select, $image_key, $excluded_set, 'exclude' ); $select .= ", IF (exclude = 0 AND @exclude = 0, $if_true, $if_false) AS 'exclude'"; } // Select what we want. $mapper->select( $select ); } // When returns is "included", the query is relatively simple. We just provide a where clause to limit how many // images we're returning based on the entity_ids, exclusions, and container_ids parameters. if ( $returns == 'included' ) { // If the sortorder property is available, then we need to override the sortorder. if ( $this->sortorder ) { $select = $this->_add_find_in_set_column( $select, $image_key, $this->sortorder, 'new_sortorder', true ); $sort_direction = $this->order_direction == 'ASC' ? 'DESC' : 'ASC'; $sort_by = 'new_sortorder'; } $mapper->select( $select ); // Filter based on entity_ids selection. if ( $this->entity_ids ) { $mapper->where( [ "{$image_key} IN %s", $this->entity_ids ] ); } // Filter based on exclusions selection. if ( $this->exclusions ) { $mapper->where( [ "{$image_key} NOT IN %s", $this->exclusions ] ); } // Ensure that no images marked as excluded at the gallery level are returned. if ( empty( $this->skip_excluding_globally_excluded_images ) ) { $mapper->where( [ 'exclude = %d', 0 ] ); } } elseif ( $returns == 'excluded' ) { // When returns is "excluded", it's a little more complicated as the query is the negated form of the // "included". entity_ids become the list of exclusions, and exclusions become the list of entity_ids to // return. All results we return must be marked as excluded. // If the sortorder property is available, then we need to override the sortorder. if ( $this->sortorder ) { $select = $this->_add_find_in_set_column( $select, $image_key, $this->sortorder, 'new_sortorder', true ); $sort_direction = $this->order_direction == 'ASC' ? 'DESC' : 'ASC'; $sort_by = 'new_sortorder'; } // Mark each result as excluded. $select .= ', 1 AS exclude'; $mapper->select( $select ); // Is this case, entity_ids become the exclusions. $exclusions = $this->entity_ids; // Remove the exclusions always takes precedence over entity_ids, so we adjust the list of ids. if ( $this->exclusions ) { foreach ( $this->exclusions as $excluded_entity_id ) { if ( ( $index = array_search( $excluded_entity_id, $exclusions ) ) !== false ) { unset( $exclusions[ $index ] ); } } } // Filter based on exclusions selection. if ( $exclusions ) { $mapper->where( [ "{$image_key} NOT IN %s", $exclusions ] ); } // Filter based on selected exclusions. elseif ( $this->exclusions ) { $mapper->where( [ "{$image_key} IN %s", $this->exclusions ] ); } // Ensure that images marked as excluded are returned as well. $mapper->where( [ 'exclude = 1' ] ); } // Filter based on containers_ids. Container ids is a little more complicated as it can contain gallery ids or tags. if ( $this->container_ids ) { // Container ids are tags. if ( $source_obj->name == 'tags' ) { $term_ids = $this->get_term_ids_for_tags( $this->container_ids ); $mapper->where( [ "{$image_key} IN %s", get_objects_in_term( $term_ids, 'ngg_tag' ) ] ); } else { // Container ids are gallery ids. $mapper->where( [ 'galleryid IN %s', $this->container_ids ] ); } } // Filter based on excluded container ids. if ( $this->excluded_container_ids ) { // Container ids are tags. if ( $source_obj->name == 'tags' ) { $term_ids = $this->get_term_ids_for_tags( $this->excluded_container_ids ); $mapper->where( [ "{$image_key} NOT IN %s", get_objects_in_term( $term_ids, 'ngg_tag' ) ] ); } else { // Container ids are gallery ids. $mapper->where( [ 'galleryid NOT IN %s', $this->excluded_container_ids ] ); } } // Adjust the query more based on what source was selected. if ( in_array( $this->source, [ 'recent', 'recent_images' ] ) ) { $sort_direction = 'DESC'; $sort_by = apply_filters( 'ngg_recent_images_sort_by_column', 'imagedate' ); } elseif ( $this->source == 'random_images' && empty( $this->entity_ids ) ) { // A gallery with source=random and a non-empty entity_ids is treated as source=images & image_ids=(entity_ids) // In this case however source is random but no image ID are pre-filled. // // Here we must transform our query from "SELECT * FROM ngg_pictures WHERE gallery_id = X" into something // like "SELECT * FROM ngg_pictures WHERE pid IN (SELECT pid FROM ngg_pictures WHERE gallery_id = X ORDER BY RAND())". $table_name = $mapper->get_table_name(); $where_clauses = []; $old_where_sql = ''; // $this->get_entities_count() works by calling count(get_entities()) which means that for random galleries // there will be no limit passed to this method -- adjust the $limit now based on the maximum_entity_count. $max = $this->get_maximum_entity_count(); if ( ! $limit || ( is_numeric( $limit ) && $limit > $max ) ) { $limit = $max; } foreach ( $mapper->where_clauses as $where ) { $where_clauses[] = '(' . $where . ')'; } if ( $where_clauses ) { $old_where_sql = 'WHERE ' . implode( ' AND ', $where_clauses ); } $noExtras = '/*NGG_NO_EXTRAS_TABLE*/'; if ( Settings::get_instance()->get( 'use_alternate_random_method' ) ) { // Check if the random image PID have been cached and use them (again) if already found. $id = $this->ID(); if ( ! empty( self::$_random_image_ids_cache[ $id ] ) ) { $image_ids = self::$_random_image_ids_cache[ $id ]; } else { global $wpdb; // Prevent infinite loops: retrieve the image count and if needed just pull in every image available. // PHP-CS flags this but it is a false positive, the $old_where_sql is an already prepared SQL string. // // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $total = $wpdb->get_var( "SELECT COUNT(`pid`) FROM {$wpdb->nggpictures} {$old_where_sql}" ); $image_ids = []; if ( $total <= $limit ) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $image_ids = $wpdb->get_col( "SELECT `pictures`.`pid` FROM {$wpdb->nggpictures} `pictures` {$old_where_sql} LIMIT {$total}" ); } else { // Start retrieving random ID from the DB and hope they exist; continue looping until our count is full. $segments = ceil( $limit / 4 ); while ( count( $image_ids ) < $limit ) { $newID = $this->_query_random_ids_for_cache( $segments, $old_where_sql ); $image_ids = array_merge( array_unique( $image_ids ), $newID ); } } // Prevent overflow. if ( count( $image_ids ) > $limit ) { array_splice( $image_ids, $limit ); } // Give things an extra shake. shuffle( $image_ids ); // Cache these ID in memory so that any attempts to call get_entities() more than once will result // in the same images being retrieved for the duration of that page execution. self::$_random_image_ids_cache[ $id ] = $image_ids; } $image_ids = implode( ',', $image_ids ); // Replace the existing WHERE clause with one where aready retrieved "random" PID are included. $mapper->where_clauses = [ " {$noExtras} `{$image_key}` IN ({$image_ids}) {$noExtras}" ]; } else { // Replace the existing WHERE clause with one that selects from a sub-query that is randomly ordered. $sub_where = "SELECT `{$image_key}` FROM `{$table_name}` i {$old_where_sql} ORDER BY RAND() LIMIT {$limit}"; $mapper->where_clauses = [ " {$noExtras} `{$image_key}` IN (SELECT `{$image_key}` FROM ({$sub_where}) o) {$noExtras}" ]; } } // Apply a sorting order. if ( $sort_by ) { $mapper->order_by( $sort_by, $sort_direction ); } // Apply a limit. if ( $limit ) { if ( $offset ) { $mapper->limit( $limit, $offset ); } else { $mapper->limit( $limit ); } } $results = $mapper->run_query(); if ( ! is_admin() && in_array( 'image', $source_obj->returns ) ) { foreach ( $results as $entity ) { if ( ! empty( $entity->description ) ) { $entity->description = I18N::translate( $entity->description, 'pic_' . $entity->pid . '_description' ); } if ( ! empty( $entity->alttext ) ) { $entity->alttext = I18N::translate( $entity->alttext, 'pic_' . $entity->pid . '_alttext' ); } } } return $results; } /** * @param int $limit * @param string $where_sql Must be the full "WHERE x=y" string * @return int[] */ public function _query_random_ids_for_cache( $limit = 10, $where_sql = '' ) { global $wpdb; $mod = rand( 3, 9 ); if ( empty( $where_sql ) ) { $where_sql = 'WHERE 1=1'; } // The following query uses $where_sql which is an already prepared clause generated by the DataMapper // // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared return $wpdb->get_col( "SELECT `pictures`.`pid` from {$wpdb->nggpictures} `pictures` JOIN (SELECT CEIL(MAX(`pid`) * RAND()) AS `pid` FROM {$wpdb->nggpictures}) AS `x` ON `pictures`.`pid` >= `x`.`pid` {$where_sql} AND `pictures`.`pid` MOD {$mod} = 0 LIMIT {$limit}" ); // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared } /** * Gets all gallery and album entities from albums specified, if any * * @param \stdClass $source_obj * @param int $limit * @param int $offset * @param boolean $id_only * @param array $returns */ public function _get_album_and_gallery_entities( $source_obj, $limit = false, $offset = false, $id_only = false, $returns = 'included' ) { // Album queries are difficult and inefficient to perform due to the database schema. To complicate things, // we're returning two different types of entities - galleries, and sub-albums. The user prefixes entity_id's // with an 'a' to distinguish album ids from gallery ids. E.g. entity_ids=[1, "a2", 3]. $album_mapper = AlbumMapper::get_instance(); $gallery_mapper = GalleryMapper::get_instance(); $album_key = $album_mapper->get_primary_key_column(); $gallery_key = $gallery_mapper->get_primary_key_column(); $select = $id_only ? $album_key . ', sortorder' : $album_mapper->get_table_name() . '.*'; $retval = []; // If no exclusions are specified, are entity_ids are specified, and we're to return is "included", then we // have a relatively easy query to perform - we just fetch each entity listed in the entity_ids field. if ( $returns == 'included' && $this->entity_ids && empty( $this->exclusions ) ) { $retval = $this->_entities_to_galleries_and_albums( $this->entity_ids, $id_only, [], $limit, $offset ); } else { // It's not going to be easy. We'll start by fetching the albums and retrieving each of their entities. $album_mapper->select( $select ); // Fetch the albums, and find the entity ids of the sub-albums and galleries. $entity_ids = []; $excluded_ids = []; // Filter by container ids. If container_ids === '0' we retrieve all existing gallery_ids and use them as // the available entity_ids for comparability with 1.9x. $container_ids = $this->container_ids; if ( $container_ids ) { if ( $container_ids !== [ '0' ] && $container_ids !== [ '' ] ) { $container_ids = array_map( 'intval', $container_ids ); $album_mapper->where( [ "{$album_key} IN %s", $container_ids ] ); // This order_by is necessary for albums to be ordered correctly given the WHERE .. IN() above. $order_string = implode( ',', $container_ids ); $album_mapper->order_by( "FIELD('id', {$order_string})" ); foreach ( $album_mapper->run_query() as $album ) { $entity_ids = array_merge( $entity_ids, (array) $album->sortorder ); } } elseif ( $container_ids === [ '0' ] || $container_ids === [ '' ] ) { foreach ( $gallery_mapper->select( $gallery_key )->run_query() as $gallery ) { $entity_ids[] = $gallery->$gallery_key; } } } // Break the list of entities into two groups, included entities and excluded entity ids // If a specific list of entity ids have been specified, then we know what entity ids are meant to be // included. We can compute the intersection and also determine what entity ids are to be excluded. if ( $this->entity_ids ) { // Determine the real list of included entity ids. Exclusions always take precedence. $included_ids = $this->entity_ids; foreach ( $this->exclusions as $excluded_id ) { if ( ( $index = array_search( $excluded_id, $included_ids ) ) !== false ) { unset( $included_ids[ $index ] ); } } $excluded_ids = array_diff( $entity_ids, $included_ids ); } elseif ( $this->exclusions ) { // We only have a list of exclusions. $included_ids = array_diff( $entity_ids, $this->exclusions ); $excluded_ids = array_diff( $entity_ids, $included_ids ); } else { // We have no entity ids and no exclusions. $included_ids = $entity_ids; } // We've built our two groups. Let's determine how we'll focus on them. We're interested in only the included ids. if ( $returns == 'included' ) { $retval = $this->_entities_to_galleries_and_albums( $included_ids, $id_only, [], $limit, $offset ); } // We're interested in only the excluded ids. elseif ( $returns == 'excluded' ) { $retval = $this->_entities_to_galleries_and_albums( $excluded_ids, $id_only, $excluded_ids, $limit, $offset ); } // We're interested in both groups. else { $retval = $this->_entities_to_galleries_and_albums( $entity_ids, $id_only, $excluded_ids, $limit, $offset ); } } return $retval; } /** * Takes a list of entities, and returns the mapped galleries and sub-albums * * @param array $entity_ids * @param bool $id_only * @param array $exclusions * @param int $limit * @param int $offset * @return array */ public function _entities_to_galleries_and_albums( $entity_ids, $id_only = false, $exclusions = [], $limit = false, $offset = false ) { $retval = []; $gallery_ids = []; $album_ids = []; $album_mapper = AlbumMapper::get_instance(); $gallery_mapper = GalleryMapper::get_instance(); $image_mapper = ImageMapper::get_instance(); $album_key = $album_mapper->get_primary_key_column(); $gallery_key = $gallery_mapper->get_primary_key_column(); $album_select = ( $id_only ? $album_key : $album_mapper->get_table_name() . '.*' ) . ', 1 AS is_album, 0 AS is_gallery, name AS title, albumdesc AS galdesc'; $gallery_select = ( $id_only ? $gallery_key : $gallery_mapper->get_table_name() . '.*' ) . ', 1 AS is_gallery, 0 AS is_album'; // Modify the sort order of the entities. if ( $this->sortorder ) { $sortorder = array_intersect( $this->sortorder, $entity_ids ); $entity_ids = array_merge( $sortorder, array_diff( $entity_ids, $sortorder ) ); } // Segment entity ids into two groups - galleries and albums. foreach ( $entity_ids as $entity_id ) { if ( substr( $entity_id, 0, 1 ) == 'a' ) { $album_ids[] = intval( substr( $entity_id, 1 ) ); } else { $gallery_ids[] = intval( $entity_id ); } } // Adjust query to include an exclude property. if ( $exclusions ) { $album_select = $this->_add_find_in_set_column( $album_select, $album_key, $this->exclusions, 'exclude' ); $album_select = $this->_add_if_column( $album_select, 'exclude', 0, 1 ); $gallery_select = $this->_add_find_in_set_column( $gallery_select, $gallery_key, $this->exclusions, 'exclude' ); $gallery_select = $this->_add_if_column( $gallery_select, 'exclude', 0, 1 ); } // Add sorting parameter to the gallery and album queries. if ( $gallery_ids ) { $gallery_select = $this->_add_find_in_set_column( $gallery_select, $gallery_key, $gallery_ids, 'ordered_by', true ); } else { $gallery_select .= ', 0 AS ordered_by'; } if ( $album_ids ) { $album_select = $this->_add_find_in_set_column( $album_select, $album_key, $album_ids, 'ordered_by', true ); } else { $album_select .= ', 0 AS ordered_by'; } // Fetch entities. $galleries = $gallery_mapper ->select( $gallery_select ) ->where( [ "{$gallery_key} IN %s", $gallery_ids ] ) ->order_by( 'ordered_by', 'DESC' ) ->run_query(); $counts = $image_mapper ->select( 'galleryid, COUNT(*) as counter' ) ->where( [ [ 'galleryid IN %s', $gallery_ids ], [ 'exclude = %d', 0 ] ] ) ->group_by( 'galleryid' ) ->run_query( false, false, true ); $albums = $album_mapper ->select( $album_select ) ->where( [ "{$album_key} IN %s", $album_ids ] ) ->order_by( 'ordered_by', 'DESC' ) ->run_query(); // Reorder entities according to order specified in entity_ids. foreach ( $entity_ids as $entity_id ) { if ( substr( $entity_id, 0, 1 ) == 'a' ) { $album = array_shift( $albums ); if ( $album ) { $retval[] = $album; } } else { $gallery = array_shift( $galleries ); if ( $gallery ) { foreach ( $counts as $id => $gal_count ) { if ( $gal_count->galleryid == $gallery->gid ) { $gallery->counter = intval( $gal_count->counter ); unset( $counts[ $id ] ); } } $retval[] = $gallery; } } } // Sort the entities. if ( $this->order_by && $this->order_by != 'sortorder' ) { usort( $retval, [ &$this, '_sort_album_result' ] ); } if ( $this->order_direction == 'DESC' ) { $retval = array_reverse( $retval ); } // Limit the entities. if ( $limit ) { $retval = array_slice( $retval, $offset, $limit ); } return $retval; } /** * Returns the total number of entities in this displayed gallery * * @param string $returns * @return int */ public function get_entity_count( $returns = 'included' ) { $retval = 0; // Is this an image query? $source_obj = $this->get_source(); if ( in_array( 'image', $source_obj->returns ) ) { $retval = count( $this->_get_image_entities( $source_obj, false, false, true, $returns ) ); } // Is this a gallery/album query? elseif ( in_array( 'gallery', $source_obj->returns ) ) { $retval = count( $this->_get_album_and_gallery_entities( $source_obj, false, false, true, $returns ) ); } $max = $this->get_maximum_entity_count(); if ( $retval > $max ) { $retval = $max; } return $retval; } /** * Honor the gallery 'maximum_entity_count' setting ONLY when dealing with random & recent galleries. All others * will always obey the *global* 'maximum_entity_count' setting. */ public function get_maximum_entity_count() { $max = intval( Settings::get_instance()->get( 'maximum_entity_count', 500 ) ); $sources = SourceManager::get_instance(); $source_obj = $this->get_source(); if ( in_array( $source_obj, [ $sources->get( 'random' ), $sources->get( 'random_images' ), $sources->get( 'recent' ), $sources->get( 'recent_images' ) ] ) ) { $max = intval( $this->maximum_entity_count ); } return $max; } /** * Returns all included entities for the displayed gallery * * @param int $limit * @param int $offset * @param boolean $id_only * @return array */ public function get_included_entities( $limit = false, $offset = false, $id_only = false ) { return $this->get_entities( $limit, $offset, $id_only, 'included' ); } /** * Adds a FIND_IN_SET call to the select portion of the query, and optionally defines a dynamic column * * @param string $select * @param string $key * @param array $array * @param string $alias * @param boolean $add_column * @return string */ public function _add_find_in_set_column( $select, $key, $array, $alias, $add_column = false ) { $array = array_map( 'intval', $array ); $set = implode( ',', array_reverse( $array ) ); if ( ! $select ) { $select = '1'; } $select .= ", @{$alias} := FIND_IN_SET({$key}, '{$set}')"; if ( $add_column ) { $select .= " AS {$alias}"; } return $select; } public function _add_if_column( $select, $alias, $true = 1, $false = 0 ) { if ( ! $select ) { $select = '1'; } $select .= ", IF(@{$alias} = 0, {$true}, {$false}) AS {$alias}"; return $select; } /** * Parses the list of parameters provided in the displayed gallery, and ensures everything meets expectations * * @return boolean */ public function _parse_parameters() { $valid = false; // Ensure that the source is valid. if ( SourceManager::get_instance()->get( $this->source ) ) { $valid = true; } // Ensure that exclusions, entity_ids, and sortorder have valid elements. IE likes to send empty array as an // array with a single element that has no value. if ( $this->exclusions && ! $this->exclusions[0] ) { $this->exclusions = []; } if ( $this->entity_ids && ! $this->entity_ids[0] ) { $this->entity_ids = []; } if ( $this->sortorder && ! $this->sortorder[0] ) { $this->sortorder = []; } return $valid; } /** * Returns a list of term ids for the list of tags * * @global \wpdb $wpdb * @param array $tags * @return array */ public function get_term_ids_for_tags( $tags = false ) { global $wpdb; // If no tags were provided, get them from the container_ids. if ( ! $tags || ! is_array( $tags ) ) { $tags = $this->container_ids; } // Convert container ids to a string suitable for WHERE IN. $container_ids = []; if ( is_array( $tags ) && ! in_array( 'all', array_map( 'strtolower', $tags ) ) ) { foreach ( $tags as $ndx => $container ) { $container = esc_sql( str_replace( '%', '%%', $container ) ); $container_ids[] = "'{$container}'"; } $container_ids = implode( ',', $container_ids ); } // Construct query. $query = "SELECT {$wpdb->term_taxonomy}.term_id FROM {$wpdb->term_taxonomy} INNER JOIN {$wpdb->terms} ON {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id WHERE {$wpdb->term_taxonomy}.term_id = {$wpdb->terms}.term_id AND {$wpdb->term_taxonomy}.taxonomy = %s"; if ( ! empty( $container_ids ) ) { $query .= " AND ({$wpdb->terms}.slug IN ({$container_ids}) OR {$wpdb->terms}.name IN ({$container_ids}))"; } $query .= " ORDER BY {$wpdb->terms}.term_id"; // This is a false positive // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $query = $wpdb->prepare( $query, 'ngg_tag' ); // Get all term_ids for each image tag slug. $term_ids = []; // This is a false positive // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $results = $wpdb->get_results( $query ); if ( is_array( $results ) && ! empty( $results ) ) { foreach ( $results as $row ) { $term_ids[] = $row->term_id; } } return $term_ids; } /** * Sorts the results of an album query * * @param \stdClass $a * @param \stdClass $b * @return int */ public function _sort_album_result( $a, $b ) { $key = $this->order_by; if ( ! isset( $a->$key ) || ! isset( $b->$key ) ) { return 0; } return strcmp( $a->$key, $b->$key ); } /** * Gets the display type object used in this displayed gallery * * @return null|\Imagely\NGG\DataTypes\DisplayType */ public function get_display_type() { return DisplayTypeMapper::get_instance()->find_by_name( $this->display_type ); } /** * Gets albums queried in this displayed gallery * * @return array */ public function get_albums() { $retval = []; if ( ( $source = $this->get_source() ) ) { if ( in_array( 'album', $source->returns ) ) { $mapper = AlbumMapper::get_instance(); $album_key = $mapper->get_primary_key_column(); if ( $this->container_ids ) { $mapper->select()->where( [ "{$album_key} IN %s", $this->container_ids ] ); } $retval = $mapper->run_query(); } } return $retval; } /** * Ensures the 'id' attribute is copied to 'ID' as both are used frequently * * @param $value * @return mixed */ public function id( $value = null ) { $retval = parent::id( $value ); $this->ID = $this->id; return $retval; } /** * Returns a transient for the displayed gallery * * @return string */ public function to_transient() { $params = $this->get_entity(); unset( $params->transient_id ); $key = Transient::create_key( 'displayed_galleries', $params ); if ( is_null( Transient::fetch( $key, null ) ) ) { Transient::update( $key, $params, NGG_DISPLAYED_GALLERY_CACHE_TTL ); } $this->transient_id = $key; if ( ! $this->id() ) { $this->id( $key ); } return $key; } public function validation() { $retval = []; $display_type = $this->get_display_type(); if ( ! $display_type ) { $retval['display_type'][] = 'Invalid display type'; } // Is the display type compatible with the source? E.g., if we're using a display type that expects images, // we can't be feeding it galleries and albums. $source_manager = SourceManager::get_instance(); if ( ! $source_manager->is_compatible( $this->get_source(), $display_type ) ) { $retval['display_type'][] = __( 'Source not compatible with selected display type', 'nggallery' ); } $retval = array_merge( $retval, $this->validates_presence_of( 'source' ), $this->validates_presence_of( 'display_type' ) ); return empty( $retval ) ? true : $retval; } /** * In case we are dealing with a legacy displayed gallery that was a post under a custom post type registry */ public function get_entity() { $entity = $this; unset( $entity->comment_count ); unset( $entity->comment_status ); unset( $entity->filter ); unset( $entity->guid ); unset( $entity->ping_status ); unset( $entity->pinged ); unset( $entity->post_author ); unset( $entity->post_content_filtered ); unset( $entity->post_date ); unset( $entity->post_date_gmt ); unset( $entity->post_excerpt ); unset( $entity->post_mime_type ); unset( $entity->post_modified ); unset( $entity->post_modified_gmt ); unset( $entity->post_name ); unset( $entity->post_parent ); unset( $entity->post_status ); unset( $entity->post_title ); unset( $entity->post_type ); unset( $entity->to_ping ); return $entity; } /** * Gets the corresponding source instance * * @return \stdClass */ public function get_source() { return SourceManager::get_instance()->get( $this->source ); } /** * Returns the galleries queries in this displayed gallery * * @return array */ public function get_galleries() { $retval = []; if ( ( $source = $this->get_source() ) ) { if ( in_array( 'image', $source->returns ) ) { $mapper = GalleryMapper::get_instance(); $gallery_key = $mapper->get_primary_key_column(); $mapper->select(); if ( $this->container_ids ) { $mapper->where( [ "{$gallery_key} IN %s", $this->container_ids ] ); } $retval = $mapper->run_query(); } } return $retval; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/DisplayType.php���������������������������������������������������������������������������0000644�����������������00000002016�15021223045�0011413 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMapper\WPModel; use Imagely\NGG\DataMappers\DisplayType as Mapper; class DisplayType extends WPModel { public $aliases = []; public $default_source = ''; public $entity_types; public $extras_post_id; public $filter; public $hidden_from_igw; public $hidden_from_ui; public $id_field; public $installed_at_version; public $meta_id; public $meta_key; public $meta_value; public $module_id; public $name = ''; public $preview_image_relpath = ''; public $preview_image_url; public $settings = []; public $title = ''; public $view_order; public function get_mapper() { return Mapper::get_instance(); } public function get_order() { return NGG_DISPLAY_PRIORITY_BASE; } public function validation() { $errors = array_merge( [], $this->validates_presence_of( 'entity_types' ), $this->validates_presence_of( 'name' ), $this->validates_presence_of( 'title' ) ); return empty( $errors ) ? true : $errors; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/Album.php���������������������������������������������������������������������������������0000644�����������������00000002163�15021223045�0010207 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMapper\Model; use Imagely\NGG\DataMappers\Album as Mapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; class Album extends Model { public $albumdesc; public $exclude; public $extras_post_id; public $id; public $id_field = 'id'; public $name; public $pageid; public $previewpic; public $slug; public $sortorder = []; public function get_primary_key_column() { return 'id'; } public function get_mapper() { return Mapper::get_instance(); } /** * @param bool $models Unused * @return array * @TODO Remove $models attribute when Pro has reached the first stage of POPE removal compatibility */ public function get_galleries( $models = false ) { $mapper = GalleryMapper::get_instance(); $gallery_key = $mapper->get_primary_key_column(); return $mapper->find_all( [ "{$gallery_key} IN %s", $this->sortorder ] ); } public function validation() { $errors = array_merge( [], $this->validates_presence_of( 'name' ), $this->validates_numericality_of( 'previewpic' ) ); return empty( $errors ) ? true : $errors; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/DataMapperExtraFields.php�����������������������������������������������������������������0000644�����������������00000000337�15021223045�0013321 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMapper\{WPModel, WPPostDriver}; class DataMapperExtraFields extends WPModel { public function get_mapper() { return new WPPostDriver( 'extra_fields' ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/Gallery.php�������������������������������������������������������������������������������0000644�����������������00000012314�15021223045�0010545 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMappers\Gallery as Mapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DataMapper\Model; use Imagely\NGG\DataStorage\Sanitizer; use Imagely\NGG\Util\Filesystem; class Gallery extends Model { public $author; public $extras_post_id; public $galdesc; public $gid; public $id_field = 'gid'; public $name; public $pageid; public $path; public $previewpic; public $slug; public $title; // TODO: remove this when get_pro_compat_level() >= 1. public $pricelist_id; public $closedpostboxesnonce; public $parent_id; public $post_paged; public $bulkaction; public $images = []; public $updatepictures; public $attach_to_post; public function get_primary_key_column() { return 'gid'; } public function get_mapper() { return Mapper::get_instance(); } public function get_images() { return ImageMapper::get_instance() ->select() ->where( [ 'galleryid = %d', $this->gid ] ) ->order_by( 'sortorder' ) ->run_query(); } public function validation() { $retval = []; // If a title is present, we can automatically populate some other properties. if ( ( $this->title ) ) { // Strip html. $this->title = Sanitizer::strip_html( $this->title, true ); $sanitized_title = str_replace( ' ', '-', $this->title ); if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) { $sanitized_title = \remove_accents( $sanitized_title ); } // If no name is present, use the title to generate one. if ( ! ( $this->name ) ) { $this->name = \apply_filters( 'ngg_gallery_name', \sanitize_file_name( $sanitized_title ) ); } // Assign a slug; possibly updating the current slug if it was conceived by a method other than sanitize_title() // NextGen 3.2.19 and older used a method adopted from esc_url() which would convert ampersands to "&" // and allow slashes in gallery slugs which breaks their ability to be linked to as children of albums. $sanitized_slug = \sanitize_title( $sanitized_title ); if ( empty( $this->slug ) || $this->slug !== $sanitized_slug ) { $this->slug = $sanitized_slug; $this->slug = \nggdb::get_unique_slug( $this->slug, 'gallery' ); } } // Set what will be the path to the gallery. $storage = StorageManager::get_instance(); if ( ! ( $this->path ) ) { $this->path = $storage->get_gallery_relpath( $this ); } // Ensure that the gallery path is restricted to $fs->get_document_root('galleries'). $fs = Filesystem::get_instance(); $root = $fs->get_document_root( 'galleries' ); $storage->flush_gallery_path_cache( $this ); $gallery_abspath = $storage->get_gallery_abspath( $this ); if ( strpos( $gallery_abspath, $root ) === false ) { $retval['gallerypath'][] = sprintf( __( 'Gallery path must be located in %s', 'nggallery' ), $root ); $this->path = $storage->get_upload_relpath( $this ); } $this->path = trailingslashit( $this->path ); // Check for '..' in the path. $sections = explode( DIRECTORY_SEPARATOR, trim( $this->path, '/\\' ) ); if ( in_array( '..', $sections, true ) ) { $retval['gallerypath'][] = __( "Gallery paths may not use '..' to access parent directories)", 'nggallery' ); } // Establish some rules on where galleries can go. $abspath = $storage->get_gallery_abspath( $this ); // Galleries should at least be a sub-folder, not directly in WP_CONTENT. $not_directly_in = [ 'content' => \wp_normalize_path( WP_CONTENT_DIR ), 'wordpress root' => $fs->get_document_root(), ]; if ( ! empty( $_SERVER['DOCUMENT_ROOT'] ) ) { $not_directly_in['document root'] = $_SERVER['DOCUMENT_ROOT']; } foreach ( $not_directly_in as $label => $dir ) { if ( $abspath == $dir ) { $retval['gallerypath'][] = sprintf( __( 'Gallery path must be a sub-directory under the %s directory', 'nggallery' ), $label ); } } $ABSPATH = \wp_normalize_path( ABSPATH ); // Disallow galleries from being under these directories at all. $not_ever_in = [ 'plugins' => \wp_normalize_path( WP_PLUGIN_DIR ), 'must use plugins' => \wp_normalize_path( WPMU_PLUGIN_DIR ), 'wp-admin' => $fs->join_paths( $ABSPATH, 'wp-admin' ), 'wp-includes' => $fs->join_paths( $ABSPATH, 'wp-includes' ), 'themes' => \get_theme_root(), ]; foreach ( $not_ever_in as $label => $dir ) { if ( strpos( $abspath, $dir ) === 0 ) { $retval['gallerypath'][] = sprintf( __( 'Gallery path cannot be under %s directory', 'nggallery' ), $label ); } } // Regardless of where they are just don't let the path end in any of these. $never_named = [ 'wp-admin', 'wp-includes', 'wp-content', ]; foreach ( $never_named as $name ) { if ( $name === end( $sections ) ) { $retval['gallerypath'][] = sprintf( __( 'Gallery path cannot end with a directory named %s', 'nggallery' ), $name ); } } unset( $storage ); $retval = array_merge( $retval, $this->validates_presence_of( 'title' ), $this->validates_presence_of( 'name' ), $this->validates_uniqueness_of( 'slug' ), $this->validates_numericality_of( 'author' ) ); return empty( $retval ) ? true : $retval; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataTypes/LegacyImageCollection.php�����������������������������������������������������������������0000644�����������������00000002650�15021223045�0013333 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; class LegacyImageCollection implements \ArrayAccess { public $container = []; public $galleries = []; /** * @param $offset * @return bool */ #[\ReturnTypeWillChange] public function offsetExists( $offset ) { return isset( $this->container[ $offset ] ); } /** * @param $offset * @return mixed|null */ #[\ReturnTypeWillChange] public function offsetGet( $offset ) { return isset( $this->container[ $offset ] ) ? $this->container[ $offset ] : null; } /** * @param $offset * @param $value */ #[\ReturnTypeWillChange] public function offsetSet( $offset, $value ) { if ( is_object( $value ) ) { $value->container = $this; } if ( is_null( $offset ) ) { $this->container[] = $value; } else { $this->container[ $offset ] = $value; } } /** * @param $offset * @return void */ #[\ReturnTypeWillChange] public function offsetUnset( $offset ) { unset( $this->container[ $offset ] ); } /** * Retrieves and caches a gallery mapper instance for this gallery id * * @param int $gallery_id Gallery ID * @return mixed */ public function get_gallery( $gallery_id ) { if ( ! isset( $this->galleries[ $gallery_id ] ) || is_null( $this->galleries[ $gallery_id ] ) ) { $this->galleries[ $gallery_id ] = GalleryMapper::get_instance(); } return $this->galleries[ $gallery_id ]; } } ����������������������������������������������������������������������������������������DataTypes/LegacyImage.php���������������������������������������������������������������������������0000644�����������������00000040410�15021223045�0011313 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataTypes; use Imagely\NGG\DisplayType\Controller; /** * This class provides a lazy-loading wrapper to the legacy "nggImage" class for use in legacy style templates */ class LegacyImage { public $_cache; // cache of retrieved values. public $_settings; // I_Settings_Manager cache. public $_storage; // I_Gallery_Storage cache. public $_galleries; // cache of Imagely\NGG\DataTypes\Mapper (plural). public $_orig_image; // original provided image. public $_orig_image_id; // original image ID. public $_cache_overrides; // allow for forcing variable values. public $_legacy = false; public $_displayed_gallery; // cached object. /** * Constructor. Converts the image class into an array and fills from defaults any missing values * * @param object $image Individual result from displayed_gallery->get_entities() * @param object $displayed_gallery Displayed gallery -- MAY BE NULL * @param bool $legacy Whether the image source is from NextGen Legacy or NextGen * @return void */ public function __construct( $image, $displayed_gallery = null, $legacy = false ) { // for clarity. if ( $displayed_gallery && isset( $displayed_gallery->display_settings['number_of_columns'] ) ) { $columns = $displayed_gallery->display_settings['number_of_columns']; } else { $columns = 0; } // Public variables. $defaults = [ 'errmsg' => '', // Error message to display, if any. 'error' => false, // Error state. 'imageURL' => '', // URL Path to the image. 'thumbURL' => '', // URL Path to the thumbnail. 'imagePath' => '', // Server Path to the image. 'thumbPath' => '', // Server Path to the thumbnail. 'href' => '', // A href link code. // Mostly constant. 'thumbPrefix' => 'thumbs_', // FolderPrefix to the thumbnail. 'thumbFolder' => '/thumbs/', // Foldername to the thumbnail. // Image Data. 'galleryid' => 0, // Gallery ID. 'pid' => 0, // Image ID. 'filename' => '', // Image filename. 'description' => '', // Image description. 'alttext' => '', // Image alttext. 'imagedate' => '', // Image date/time. 'exclude' => '', // Image exclude. 'thumbcode' => '', // Image effect code. // Gallery Data. 'name' => '', // Gallery name. 'path' => '', // Gallery path. 'title' => '', // Gallery title. 'pageid' => 0, // Gallery page ID. 'previewpic' => 0, // Gallery preview pic. 'style' => ( $columns > 0 ) ? 'style="width:' . floor( 100 / $columns ) . '%;"' : '', 'hidden' => false, 'permalink' => '', 'tags' => '', ]; // convert the image to an array and apply the defaults. $this->_orig_image = $image; $image = (array) $image; foreach ( $defaults as $key => $val ) { if ( ! isset( $image[ $key ] ) ) { $image[ $key ] = $val; } } // cache the results. ksort( $image ); $id_field = ( ! empty( $image['id_field'] ) ? $image['id_field'] : 'pid' ); $this->_cache = (array) apply_filters( 'ngg_image_object', (object) $image, $image[ $id_field ] ); $this->_orig_image_id = $image[ $id_field ]; $this->_legacy = $legacy; $this->_displayed_gallery = $displayed_gallery; } public function __set( $name, $value ) { $this->_cache[ $name ] = $value; } public function __isset( $name ) { return isset( $this->_cache[ $name ] ); } public function __unset( $name ) { unset( $this->_cache[ $name ] ); } /** * Lazy-loader for image variables. * * @param string $name Parameter name. * @return mixed */ public function __get( $name ) { if ( isset( $this->_cache_overrides[ $name ] ) ) { return $this->_cache_overrides[ $name ]; } // at the bottom we default to returning $this->_cache[$name]. switch ( $name ) { case 'alttext': $this->_cache['alttext'] = ( empty( $this->_cache['alttext'] ) ) ? ' ' : \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $this->_cache['alttext'] ); return $this->_cache['alttext']; case 'author': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['author'] = $gallery->name; return $this->_cache['author']; case 'caption': $caption = \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $this->__get( 'description' ) ); if ( empty( $caption ) ) { $caption = ' '; } $this->_cache['caption'] = $caption; return $this->_cache['caption']; case 'description': $this->_cache['description'] = ( empty( $this->_cache['description'] ) ) ? ' ' : \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $this->_cache['description'] ); return $this->_cache['description']; case 'galdesc': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['galdesc'] = $gallery->name; return $this->_cache['galdesc']; case 'gid': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['gid'] = $gallery->{$gallery->id_field}; return $this->_cache['gid']; case 'href': return $this->__get( 'imageHTML' ); case 'id': return $this->_orig_image_id; case 'imageHTML': $tmp = '<a href="' . $this->__get( 'imageURL' ) . '" title="' . esc_attr( $this->__get( 'description' ) ) . '" ' . $this->get_thumbcode( $this->__get( 'name' ) ) . '>' . '<img alt="' . esc_attr( $this->__get( 'alttext' ) ) . '" src="' . $this->__get( 'imageURL' ) . '"/>' . '</a>'; $this->_cache['href'] = $tmp; $this->_cache['imageHTML'] = $tmp; return $this->_cache['imageHTML']; case 'imagePath': $storage = $this->get_storage(); $this->_cache['imagePath'] = $storage->get_image_abspath( $this->_orig_image, 'full' ); return $this->_cache['imagePath']; case 'imageURL': $storage = $this->get_storage(); $this->_cache['imageURL'] = $storage->get_image_url( $this->_orig_image, 'full' ); return $this->_cache['imageURL']; case 'linktitle': $this->_cache['linktitle'] = htmlspecialchars( stripslashes( $this->__get( 'description' ) ) ); return $this->_cache['linktitle']; case 'name': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['name'] = $gallery->name; return $this->_cache['name']; case 'pageid': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['pageid'] = $gallery->name; return $this->_cache['pageid']; case 'path': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['path'] = $gallery->name; return $this->_cache['path']; case 'permalink': $this->_cache['permalink'] = $this->__get( 'imageURL' ); return $this->_cache['permalink']; case 'pid': return $this->_orig_image_id; case 'id_field': $this->_cache['id_field'] = ( ! empty( $this->_orig_image->id_field ) ? $this->_orig_image->id_field : 'pid' ); return $this->_cache['id_field']; case 'pidlink': $application = \Imagely\NGG\Util\Router::get_instance()->get_routed_app(); $this->_cache['pidlink'] = $application->set_parameter_value( 'pid', $this->__get( 'image_slug' ), null, false, $application->get_routed_url( true ) ); return $this->_cache['pidlink']; case 'previewpic': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['previewpic'] = $gallery->name; return $this->_cache['previewpic']; case 'size': $w = 0; $h = 0; if ( $this->_displayed_gallery && isset( $this->_displayed_gallery->display_settings ) ) { $ds = $this->_displayed_gallery->display_settings; if ( isset( $ds['override_thumbnail_settings'] ) && $ds['override_thumbnail_settings'] ) { $w = $ds['thumbnail_width']; $h = $ds['thumbnail_height']; } } if ( ! $w || ! $h ) { if ( is_string( $this->_orig_image->meta_data ) ) { $this->_orig_image = \Imagely\NGG\Util\Serializable::unserialize( $this->_orig_image->meta_data ); } if ( ! isset( $this->_orig_image->meta_data['thumbnail'] ) ) { $storage = $this->get_storage(); $storage->generate_thumbnail( $this->_orig_image ); } $w = $this->_orig_image->meta_data['thumbnail']['width']; $h = $this->_orig_image->meta_data['thumbnail']['height']; } return "width='{$w}' height='{$h}'"; case 'slug': $gallery = $this->get_legacy_gallery( $this->__get( 'galleryid' ) ); $this->_cache['slug'] = $gallery->name; return $this->_cache['slug']; case 'tags': $this->_cache['tags'] = wp_get_object_terms( $this->__get( 'id' ), 'ngg_tag', 'fields=all' ); return $this->_cache['tags']; case 'thumbHTML': $tmp = '<a href="' . $this->__get( 'imageURL' ) . '" title="' . htmlspecialchars( stripslashes( $this->__get( 'description' ) ) ) . '" ' . $this->get_thumbcode( $this->__get( 'name' ) ) . '>' . '<img alt="' . $this->__get( 'alttext' ) . '" src="' . $this->thumbURL . '"/>' . '</a>'; $this->_cache['href'] = $tmp; $this->_cache['thumbHTML'] = $tmp; return $this->_cache['thumbHTML']; case 'thumbPath': $storage = $this->get_storage(); $this->_cache['thumbPath'] = $storage->get_image_abspath( $this->_orig_image, 'thumbnail' ); return $this->_cache['thumbPath']; case 'thumbnailURL': $storage = $this->get_storage(); $thumbnail_size_name = 'thumbnail'; if ( $this->_displayed_gallery && isset( $this->_displayed_gallery->display_settings ) ) { $ds = $this->_displayed_gallery->display_settings; if ( isset( $ds['override_thumbnail_settings'] ) && $ds['override_thumbnail_settings'] ) { $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); $dyn_params = [ 'width' => $ds['thumbnail_width'], 'height' => $ds['thumbnail_height'], ]; if ( $ds['thumbnail_quality'] ) { $dyn_params['quality'] = $ds['thumbnail_quality']; } if ( $ds['thumbnail_crop'] ) { $dyn_params['crop'] = true; } if ( $ds['thumbnail_watermark'] ) { $dyn_params['watermark'] = true; } $thumbnail_size_name = $dynthumbs->get_size_name( $dyn_params ); } } $this->_cache['thumbnailURL'] = $storage->get_image_url( $this->_orig_image, $thumbnail_size_name ); return $this->_cache['thumbnailURL']; case 'thumbcode': if ( $this->_displayed_gallery && isset( $this->_displayed_gallery->display_settings ) && isset( $this->_displayed_gallery->display_settings['use_imagebrowser_effect'] ) && $this->_displayed_gallery->display_settings['use_imagebrowser_effect'] && ! empty( $this->_orig_image->thumbcode ) ) { $this->_cache['thumbcode'] = $this->_orig_image->thumbcode; } else { $this->_cache['thumbcode'] = $this->get_thumbcode( $this->__get( 'name' ) ); } return $this->_cache['thumbcode']; case 'thumbURL': return $this->__get( 'thumbnailURL' ); case 'title': $this->_cache['title'] = stripslashes( $this->__get( 'name' ) ); return $this->_cache['title']; case 'url': $storage = $this->get_storage(); $this->_cache['url'] = $storage->get_image_url( $this->_orig_image, 'full' ); return $this->_cache['url']; default: return $this->_cache[ $name ]; } } // called on initial nggLegacy image at construction. not sure what to do with it now. public function construct_ngg_Image( $gallery ) { do_action_ref_array( 'ngg_get_image', [ &$this ] ); unset( $this->tags ); } /** * Retrieves and caches an I_Settings_Manager instance * * @return mixed */ public function get_settings() { if ( is_null( $this->_settings ) ) { $this->_settings = \Imagely\NGG\Settings\Settings::get_instance(); } return $this->_settings; } /** * Retrieves and caches an I_Gallery_Storage instance * * @return mixed */ public function get_storage() { if ( is_null( $this->_storage ) ) { $this->_storage = \Imagely\NGG\DataStorage\Manager::get_instance(); } return $this->_storage; } /** * Retrieves gallery mapper instance * * @param int $gallery_id Gallery ID * @return Imagely\NGG\DataTypes\Gallery|null */ public function get_gallery( $gallery_id ) { if ( isset( $this->container ) && method_exists( $this->container, 'get_gallery' ) ) { return $this->container->get_gallery( $gallery_id ); } return \Imagely\NGG\DataMappers\Gallery::get_instance()->find( $gallery_id ); } /** * Retrieves gallery mapper instance * * @param int $gallery_id Gallery ID * @return Imagely\NGG\DataTypes\Gallery|null */ public function get_legacy_gallery( $gallery_id ) { return \Imagely\NGG\DataMappers\Gallery::get_instance()->find( $gallery_id ); } /** * Get the thumbnail code (to add effects on thumbnail click) * * Applies the filter 'ngg_get_thumbcode' * * @param string $gallery_name (optional) Default = '' * @return string */ public function get_thumbcode( $gallery_name = '' ) { if ( empty( $this->_displayed_gallery ) ) { $effect_code = \Imagely\NGG\Settings\Settings::get_instance()->thumbCode; $effect_code = str_replace( '%GALLERY_ID%', $gallery_name, $effect_code ); $effect_code = str_replace( '%GALLERY_NAME%', $gallery_name, $effect_code ); $retval = $effect_code; } else { $controller = new Controller(); $retval = $controller->get_effect_code( $this->_displayed_gallery ); // This setting requires that we disable the effect code. $ds = $this->_displayed_gallery->display_settings; if ( isset( $ds['use_imagebrowser_effect'] ) && $ds['use_imagebrowser_effect'] ) { $retval = ''; } } $retval = apply_filters( 'ngg_get_thumbcode', $retval, $this ); // ensure some additional data- fields are added; provides Pro-Lightbox compatibility. $retval .= ' data-image-id="' . $this->__get( 'id' ) . '"'; $retval .= ' data-src="' . $this->__get( 'imageURL' ) . '"'; $retval .= ' data-thumbnail="' . $this->__get( 'thumbnailURL' ) . '"'; $retval .= ' data-title="' . \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $this->__get( 'alttext' ) ) . '"'; $retval .= ' data-description="' . \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $this->__get( 'description' ) ) . '"'; $this->_cache['thumbcode'] = $retval; return $retval; } /** * For compatibility support * * @return mixed */ public function get_href_link() { return $this->__get( 'imageHTML' ); } /** * For compatibility support * * @return mixed */ public function get_href_thumb_link() { return $this->__get( 'thumbHTML' ); } /** * Function exists for legacy support but has been gutted to not do anything * * @param string|int $width (optional) Default = '' * @param string|int $height (optional) Default = '' * @param string $mode could be watermark | web20 | crop * @return bool|string The url for the image or false if failed */ public function cached_singlepic_file( $width = '', $height = '', $mode = '' ) { $dynthumbs = \Imagely\NGG\DynamicThumbnails\Manager::get_instance(); $storage = $this->get_storage(); // determine what to do with 'mode'. $display_reflection = false; $display_watermark = false; if ( ! is_array( $mode ) ) { $mode = explode( ',', $mode ); } if ( in_array( 'web20', $mode ) ) { $display_reflection = true; } if ( in_array( 'watermark', $mode ) ) { $display_watermark = true; } // and go for it. $params = [ 'width' => $width, 'height' => $height, 'watermark' => $display_watermark, 'reflection' => $display_reflection, ]; return $storage->get_image_url( (object) $this->_cache, $dynthumbs->get_size_name( $params ) ); } /** * Get the tags associated to this image */ public function get_tags() { return $this->__get( 'tags' ); } /** * Get the permalink to the image * * TODO: Get a permalink to a page presenting the image */ public function get_permalink() { return $this->__get( 'permalink' ); } /** * Returns the _cache array; used by nggImage * * @return array */ public function _get_image() { return $this->_cache; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Functions/compat.php��������������������������������������������������������������������������������0000644�����������������00000000646�15021223045�0010510 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Compat Function * * @since 3.5.1 * * @package NextGEN Gallery */ if ( ! function_exists( 'str_contains' ) ) { /** * Polyfill for str_contains * * @since 3.5.1 * * @param array $haystack Array to search. * @param string $needle What to find. * * @return bool */ function str_contains( $haystack, $needle ) { return '' !== $needle && false !== mb_strpos( $haystack, $needle ); } } ������������������������������������������������������������������������������������������Functions/deprecated.php����������������������������������������������������������������������������0000644�����������������00000010061�15021223045�0011315 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Remove once get_pro_api_version() is > 4.0 * * @deprecated */ function nextgen_esc_url( $url, $protocols = null, $context = 'display' ) { return \Imagely\NGG\Util\Router::esc_url( $url, $protocols, $context ); } /** * @depecated */ function nggShowRelatedGallery( $taglist, $maxImages = 0 ) { return \Imagely\NGG\Display\DisplayManager::_render_related_string( $taglist, $maxImages, $type = null ); } /** * @depecated */ function nggShowRelatedImages( $type = null, $maxImages = 0 ) { return \Imagely\NGG\Display\DisplayManager::_render_related_string( null, $maxImages, $type ); } /** * @deprecated */ function the_related_images( $type = 'tags', $maxNumbers = 7 ) { return \Imagely\NGG\Display\DisplayManager::_render_related_string( null, $maxNumbers, $type ); } /** * @depecated */ function nggShowImageBrowser( $galleryID, $template = '' ) { $renderer = \Imagely\NGG\DisplayedGallery\Renderer::get_instance(); $retval = $renderer->display_images( [ 'gallery_ids' => [ $galleryID ], 'display_type' => NGG_BASIC_IMAGEBROWSER, 'template' => $template, ] ); return apply_filters( 'ngg_show_imagebrowser_content', $retval, $galleryID ); } /** * @deprecated */ function nggCreateImageBrowser( $picturelist, $template = '' ) { $renderer = \Imagely\NGG\DisplayedGallery\Renderer::get_instance(); $image_ids = []; foreach ( $picturelist as $image ) { $image_ids[] = $image->pid; } return $renderer->display_images( [ 'image_ids' => $image_ids, 'display_type' => NGG_BASIC_IMAGEBROWSER, 'template' => $template, ] ); } /** * @deprecated */ function nggShowSlideshow( $galleryID, $width, $height ) { $args = [ 'source' => 'galleries', 'container_ids' => $galleryID, 'gallery_width' => $width, 'gallery_height' => $height, 'display_type' => NGG_BASIC_SLIDESHOW, ]; echo \Imagely\NGG\DisplayedGallery\Renderer::get_instance()->display_images( $args ); } /** * @deprecated */ function nggShowGallery( $galleryID, $template = '', $images_per_page = false ) { $args = [ 'source' => 'galleries', 'container_ids' => $galleryID, ]; if ( apply_filters( 'ngg_show_imagebrowser_first', false, $galleryID ) ) { $args['display_type'] = NGG_BASIC_IMAGEBROWSER; } else { $args['display_type'] = NGG_BASIC_THUMBNAILS; } if ( ! empty( $template ) ) { $args['template'] = $template; } if ( ! empty( $images_per_page ) ) { $args['images_per_page'] = $images_per_page; } echo \Imagely\NGG\DisplayedGallery\Renderer::get_instance()->display_images( $args ); } /** * @deprecated */ function nggShowAlbum( $albumID, $template = 'extend', $gallery_template = '' ) { $renderer = \Imagely\NGG\DisplayedGallery\Renderer::get_instance(); $retval = $renderer->display_images( [ 'album_ids' => [ $albumID ], 'display_type' => 'photocrati-nextgen_basic_extended_album', 'template' => $template, 'gallery_display_template' => $gallery_template, ] ); return apply_filters( 'ngg_show_album_content', $retval, $albumID ); } /** * This class is used by some 3rd party plugins. For compatibility this class exists to accept the stdClass passed to * the register() method and cast it to a NGG Lightbox data type before registration. * * @depecated */ class C_Lightbox_Library_Manager { public static $instance = null; public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new C_Lightbox_Library_Manager(); } return self::$instance; } public function __call( $method, $args ) { $manager = \Imagely\NGG\Display\LightboxManager::get_instance(); return $manager->$method( ...$args ); } public function register( string $name, $lightbox ) { $manager = \Imagely\NGG\Display\LightboxManager::get_instance(); // Clone a new Lightbox class using the attributes in a regular stdClass. $new_lightbox = new \Imagely\NGG\DataTypes\Lightbox( $name ); foreach ( get_object_vars( $lightbox ) as $key => $value ) { $new_lightbox->$key = $value; } $manager->register( $name, $new_lightbox ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Functions/admin.php���������������������������������������������������������������������������������0000644�����������������00000002272�15021223045�0010312 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Admin Functions * * @since 3.5.0 * * @package NextGen Gallery */ /** * Helper Method to load admin Partials * * @since 3.5.0 * * @param string $template Template to load. * * @return bool */ function nextgen_load_admin_partial( $template ) { $dir = trailingslashit( trailingslashit( NGG_PLUGIN_DIR ) . 'src/Admin/Views' ); if ( file_exists( $dir . $template . '.php' ) ) { require_once $dir . $template . '.php'; return true; } return false; } /** * Helper method to check if starter, plus or pro is active. * * @since 3.5.0 * * @return bool */ function nextgen_is_plus_or_pro_enabled() { return defined( 'NGG_PRO_PLUGIN_BASENAME' ) || defined( 'NGG_PLUS_PLUGIN_BASENAME' ) || defined( 'NGG_STARTER_PLUGIN_BASENAME' ) || is_multisite(); } /** * Helper Method to Detect NGG Admin Page * * @since 3.5.0 * * @return bool */ function is_nextgen_admin_page() { global $current_screen; if ( ! is_admin() ) { return false; } $keys = [ 'ngg', 'nggallery', 'nextgen-gallery', 'nextgen' ]; foreach ( $keys as $key ) { $is_modern_page = str_contains( $current_screen->id, $key ); if ( $is_modern_page ) { return true; } } return false; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Display/ViewElement.php�����������������������������������������������������������������������������0000644�����������������00000003211�15021223045�0011075 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; class ViewElement { protected $id; protected $type; protected $list; protected $context; public function __construct( $id, $type = null ) { $this->id = $id; $this->type = $type; $this->list = []; $this->context = []; } public function get_id() { return $this->id; } public function append( $child ) { $this->list[] = $child; } public function insert( $child, $position = 0 ) { array_splice( $this->list, $position, 0, $child ); } public function delete( $child ) { $index = array_search( $child, $this->list ); if ( $index !== false ) { array_splice( $this->list, $index, 1 ); } } public function find( $id, $recurse = false ) { $list = []; $this->_find( $list, $id, $recurse ); return $list; } public function _find( array &$list, $id, $recurse = false ) { foreach ( $this->list as $index => $element ) { if ( $element instanceof ViewElement ) { if ( $element->get_id() == $id ) { $list[] = $element; } if ( $recurse ) { $element->_find( $list, $id, $recurse ); } } } } public function get_context( $name ) { if ( isset( $this->context[ $name ] ) ) { return $this->context[ $name ]; } return null; } public function set_context( $name, $value ) { $this->context[ $name ] = $value; } public function get_object() { return $this->get_context( 'object' ); } public function rasterize() { $ret = null; foreach ( $this->list as $index => $element ) { if ( $element instanceof ViewElement ) { $ret .= $element->rasterize(); } else { $ret .= (string) $element; } } return $ret; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Display/I18N.php������������������������������������������������������������������������������������0000644�����������������00000034225�15021223045�0007341 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\DataMappers\DisplayedGallery as DisplayedGalleryMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\Util\URL; class I18N { protected static $instance = null; /** * @return I18N */ static function get_instance() { if ( is_null( self::$instance ) ) { self::$instance = new I18N(); } return self::$instance; } public function register_hooks() { add_action( 'init', [ $this, 'register_translation_hooks' ], 2 ); } public function register_translation_hooks() { $dir = \str_replace( \wp_normalize_path( WP_PLUGIN_DIR ), '', \wp_normalize_path( NGG_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'static' . DIRECTORY_SEPARATOR . 'I18N' ) ); // Load text domain. \load_plugin_textdomain( 'nggallery', false, $dir ); // Hooks to register image, gallery, and album name & description with WPML. \add_action( 'ngg_image_updated', [ $this, 'register_image_strings' ] ); \add_action( 'ngg_album_updated', [ $this, 'register_album_strings' ] ); \add_action( 'ngg_created_new_gallery', [ $this, 'register_gallery_strings' ] ); // do not let WPML translate posts we use as a document store. \add_filter( 'get_translatable_documents', [ $this, 'wpml_translatable_documents' ] ); if ( \class_exists( 'SitePress' ) ) { // Copy AttachToPost entries when duplicating posts to another language. \add_action( 'icl_make_duplicate', [ $this, 'wpml_adjust_gallery_id' ], 10, 4 ); \add_action( 'save_post', [ $this, 'wpml_set_gallery_language_on_save_post' ], 101, 1 ); } // see function comments. \add_filter( 'ngg_displayed_gallery_cache_params', [ $this, 'set_qtranslate_cache_parameters' ] ); \add_filter( 'ngg_displayed_gallery_cache_params', [ $this, 'set_wpml_cache_parameters' ] ); } /** * When QTranslate is active we must add its language & url-mode settings as display parameters * so as to generate a unique cache for each language. * * @param array $arr * @return array */ public function set_qtranslate_cache_parameters( $arr ) { if ( empty( $GLOBALS['q_config'] ) || ! \defined( 'QTRANS_INIT' ) ) { return $arr; } global $q_config; $arr['qtranslate_language'] = $q_config['language']; $arr['qtranslate_url_mode'] = $q_config['url_mode']; return $arr; } /** * See notes on set_qtranslate_cache_paramters() * * @param array $arr * @return array */ public function set_wpml_cache_parameters( $arr ) { if ( empty( $GLOBALS['sitepress'] ) || ! \defined( 'WPML_ST_VERSION' ) ) { return $arr; } global $sitepress; $settings = $sitepress->get_settings(); $arr['wpml_language'] = ICL_LANGUAGE_CODE; $arr['wpml_url_mode'] = $settings['language_negotiation_type']; return $arr; } /** * Registers gallery strings with WPML * * @param int|object $gallery_id Gallery object or ID */ public function register_gallery_strings( $gallery_id ) { if ( \function_exists( 'icl_register_string' ) ) { $gallery = GalleryMapper::get_instance()->find( $gallery_id ); if ( $gallery ) { if ( isset( $gallery->title ) && ! empty( $gallery->title ) ) { \icl_register_string( 'plugin_ngg', 'gallery_' . $gallery->{$gallery->id_field} . '_name', $gallery->title, true ); } if ( isset( $gallery->galdesc ) && ! empty( $gallery->galdesc ) ) { \icl_register_string( 'plugin_ngg', 'gallery_' . $gallery->{$gallery->id_field} . '_description', $gallery->galdesc, true ); } } } } /** * Registers image strings with WPML * * @param object $image */ public function register_image_strings( $image ) { if ( \function_exists( 'icl_register_string' ) ) { if ( isset( $image->description ) && ! empty( $image->description ) ) { \icl_register_string( 'plugin_ngg', 'pic_' . $image->{$image->id_field} . '_description', $image->description, true ); } if ( isset( $image->alttext ) && ! empty( $image->alttext ) ) { \icl_register_string( 'plugin_ngg', 'pic_' . $image->{$image->id_field} . '_alttext', $image->alttext, true ); } } } /** * Registers album strings with WPML * * @param object $album */ public function register_album_strings( $album ) { if ( \function_exists( 'icl_register_string' ) ) { if ( isset( $album->name ) && ! empty( $album->name ) ) { \icl_register_string( 'plugin_ngg', 'album_' . $album->{$album->id_field} . '_name', $album->name, true ); } if ( isset( $album->albumdesc ) && ! empty( $album->albumdesc ) ) { \icl_register_string( 'plugin_ngg', 'album_' . $album->{$album->id_field} . '_description', $album->albumdesc, true ); } } } /** * NextGEN stores some data in custom posts that MUST NOT be automatically translated by WPML * * @param array $icl_post_types * @return array $icl_post_types without any NextGEN custom posts */ public function wpml_translatable_documents( $icl_post_types = [] ) { $nextgen_post_types = [ 'ngg_album', 'ngg_gallery', 'ngg_pictures', 'display_type', 'gal_display_source', 'lightbox_library', 'photocrati-comments', ]; foreach ( $icl_post_types as $ndx => $post_type ) { if ( \in_array( $post_type->name, $nextgen_post_types, true ) ) { unset( $icl_post_types[ $ndx ] ); } } return $icl_post_types; } public function wpml_adjust_gallery_id( $master_post_id, $lang, $post_array, $id ) { if ( ! isset( $post_array['post_type'] ) || $post_array['post_type'] == 'displayed_gallery' ) { return; } $re = '|preview/id--(\d+)|mi'; if ( \preg_match_all( $re, $post_array['post_content'], $gallery_ids ) ) { foreach ( $gallery_ids[1] as $index => $gallery_id ) { $translated_gallery_id = \apply_filters( 'wpml_object_id', (int) $gallery_id, 'displayed_gallery', true, $lang ); } $search[ $index ] = 'preview/id--' . $gallery_id; $replace[ $index ] = 'preview/id--' . $translated_gallery_id; $post_array['post_content'] = \str_replace( $search, $replace, $post_array['post_content'] ); $to_save = [ 'ID' => $id, 'post_content' => $post_array['post_content'], ]; \wp_update_post( $to_save ); } } public function wpml_set_gallery_language_on_save_post( $post_id ) { if ( \wp_is_post_revision( $post_id ) ) { return; } // Nonce verification is not necessary: we are inspecting the URL and ending execution if a URL paramater matches. // // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( isset( $_POST['icl_ajx_action'] ) && 'make_duplicates' === sanitize_text_field( wp_unslash( $_POST['icl_ajx_action'] ) ) ) { return; } $post = \get_post( $post_id ); if ( $post->post_type == 'displayed_gallery' ) { return; } if ( \preg_match_all( '#<img.*http(s)?://(.*)?' . NGG_ATTACH_TO_POST_SLUG . '(=|/)preview(/|&|&)id(=|--)(\\d+).*?>#mi', $post->post_content, $matches, PREG_SET_ORDER ) ) { $mapper = DisplayedGalleryMapper::get_instance(); foreach ( $matches as $match ) { // Find the displayed gallery. $displayed_gallery_id = $match[6]; \add_filter( 'wpml_suppress_filters', '__return_true', 10, 1 ); $displayed_gallery = $mapper->find( $displayed_gallery_id, true ); \add_filter( 'wpml_suppress_filters', '__return_false', 11, 1 ); if ( $displayed_gallery ) { $displayed_gallery_type = \apply_filters( 'wpml_element_type', 'displayed_gallery' ); // set language of this gallery. $displayed_gallery_lang = \apply_filters( 'wpml_post_language_details', null, $displayed_gallery->ID ); $post_language = \apply_filters( 'wpml_post_language_details', null, $post_id ); if ( ! $displayed_gallery_lang || $displayed_gallery_lang['language_code'] != $post_language['language_code'] ) { if ( $post_language ) { $args = [ 'element_id' => $displayed_gallery->ID, 'element_type' => $displayed_gallery_type, 'language_code' => $post_language['language_code'], ]; \do_action( 'wpml_set_element_language_details', $args ); } } // duplicate gallery to other languages. $is_translated = \apply_filters( 'wpml_element_has_translations', '', $displayed_gallery->ID, $displayed_gallery_type ); if ( ! $is_translated ) { \do_action( 'wpml_admin_make_post_duplicates', $displayed_gallery->ID ); } } } } } public static function translate( $in, $name = null ) { if ( \function_exists( 'langswitch_filter_langs_with_message' ) ) { $in = \langswitch_filter_langs_with_message( $in ); } if ( \function_exists( 'polyglot_filter' ) ) { $in = \polyglot_filter( $in ); } if ( \function_exists( 'qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage' ) ) { $in = \qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage( $in ); } if ( \is_string( $name ) && ! empty( $name ) && \function_exists( 'icl_translate' ) && \apply_filters( 'wpml_default_language', null ) != \apply_filters( 'wpml_current_language', null ) ) { $in = \icl_translate( 'plugin_ngg', $name, $in, true ); } $in = \apply_filters( 'localization', $in ); return $in; } public static function mb_pathinfo( $path, $options = null ) { $ret = [ 'dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '', ]; $pathinfo = []; if ( \preg_match( '%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo ) ) { if ( \array_key_exists( 1, $pathinfo ) ) { $ret['dirname'] = $pathinfo[1]; } if ( \array_key_exists( 2, $pathinfo ) ) { $ret['basename'] = $pathinfo[2]; } if ( \array_key_exists( 5, $pathinfo ) ) { $ret['extension'] = $pathinfo[5]; } if ( \array_key_exists( 3, $pathinfo ) ) { $ret['filename'] = $pathinfo[3]; } } switch ( $options ) { case PATHINFO_DIRNAME: case 'dirname': return $ret['dirname']; case PATHINFO_BASENAME: case 'basename': return $ret['basename']; case PATHINFO_EXTENSION: case 'extension': return $ret['extension']; case PATHINFO_FILENAME: case 'filename': return $ret['filename']; default: return $ret; } } public static function mb_basename( $path ) { $separator = ' qq '; $path = \preg_replace( '/[^ ]/u', $separator . '$0' . $separator, $path ); $base = \basename( $path ); return \str_replace( $separator, '', $base ); } public static function get_kses_allowed_html() { global $allowedtags; $our_keys = [ 'a' => [ 'href' => [], 'class' => [], 'title' => [], ], 'br' => [], 'em' => [], 'i' => [], 'strong' => [], 'b' => [], 'u' => [], 'p' => [ 'class' => [] ], 'div' => [ 'class' => [], 'id' => [], ], 'span' => [ 'class' => [], 'id' => [], ] ]; return \array_merge_recursive( $allowedtags, $our_keys ); } /** * Sanitize text for alt/title/desc field. * * @param string $content content. * @return string Sanitized content. */ public static function ngg_sanitize_text_alt_title_desc( $content ) { // Step 1: Decode HTML entities to get rid of HTML entity encoding (for example, < becomes <). $content = self::ngg_decode_html_entities( $content ); // Strip backslashes that may have been added by wp_kses or other functions. $content = stripslashes( $content ); $content = str_replace( '`', '', $content ); // Step 2: Remove specific dangerous patterns using regex. // Remove <script> tags and anything inside them. $content = preg_replace( '/<script\b[^>]*>(.*?)<\/script>/is', '', $content ); // Remove inline event handlers like onclick, onload, etc. $content = preg_replace( '/\bon\w+\s*=\s*["\'].*?["\']/i', '', $content ); // Remove dangerous JavaScript function calls (alert, prompt, confirm, etc.). $content = preg_replace( '/\b(alert|prompt|confirm)\s*\(\s*["\']?.*?["\']?\s*\)/i', '', $content ); // standard function calls. // Remove variations of alert(), prompt(), confirm(), including backticks and HTML entities. $content = preg_replace( '/\b(alert|prompt|confirm)\s*\(\s*`?[^`]*`?\s*\)/i', '', $content ); // with backticks. // Remove encoded JavaScript entities like <script>alert</script> and others. $content = preg_replace( '/(&#?x?([0-9a-f]+);?|&(?:[a-z0-9]+|#x?[0-9a-f]+);?)*alert/i', '', $content ); // HTML-encoded alert and script. $content = preg_replace( '/(&#?x?([0-9a-f]+);?|&(?:[a-z0-9]+|#x?[0-9a-f]+);?)*script/i', '', $content ); // HTML-encoded script. // Remove JavaScript URL protocols like "javascript:", "vbscript:", etc. $content = preg_replace( '/(javascript|vbscript|data|file):/i', '', $content ); // Remove dangerous JavaScript functions (eval, window.location, document.cookie, etc.). $content = preg_replace( '/(eval|window\.location|document\.cookie|document\.write)/i', '', $content ); // Remove HTML entities. $content = preg_replace('/\&[^;]*;/', '', $content); // Strip remaining unwanted HTML tags and attributes (you can customize this further). $allowed_tags = self::get_kses_allowed_html(); $content = wp_kses( $content, $allowed_tags ); // Clean up the content by re-encoding HTML entities, this ensures that no malicious code is stored in db. $content = htmlspecialchars( $content, ENT_QUOTES, 'UTF-8' ); return $content; } /** * Function to decode sanitized HTML content before render. * * @param mixed $content * @return void */ public static function ngg_decode_sanitized_html_content( $content ) { $content = self::ngg_sanitize_text_alt_title_desc( $content ); $content = htmlspecialchars_decode( $content, ENT_QUOTES ); return $content; } /** * Function to return plain text for alt or title attributes. * * @param mixed $text * @return void */ public static function ngg_plain_text_alt_title_attributes( $text ) { $text = esc_attr( strip_tags( html_entity_decode( $text, ENT_QUOTES, 'UTF-8' ) ) ); return $text; } /** * Function to decode HTML entities recursively. * * @param mixed $content * @return void */ public static function ngg_decode_html_entities( $content ) { $previous_content = ''; // Keep decoding until no changes occur (i.e., fully decoded). do { $previous_content = $content; $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8'); } while ($previous_content !== $content); return $content; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Display/Shortcodes.php������������������������������������������������������������������������������0000644�����������������00000024727�15021223045�0011005 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\DisplayedGallery\Renderer; /** * NGG registers its shortcodes using Shortcodes::add($tag, $callback) * * We do this for the following reason: * * NGG is used with a wide variety of third-party themes and plugins. Some of which, do things * a little unorthodox, and end up modifying the markup generated by the shortcode, which breaks * the display for our users. * * Rather than having to explain to our userbase, "you shouldn't use NGG with [plugin x]", we * decided to find a mechanism that would make our plugin immune from such manipulation from other * plugins, or at least reduce likelihood of such a thing happening. * * This is how the mechanism works: * * When you register a shortcode using Shortcodes::add(), we store a reference to * the callback internally, but add the shortcode will actually call one of the internal methods of * this class which outputs a placeholder (@see $_privateholder_text) instead of the markup generated * by the callback. It's just a simple string and something that a third-party plugin is unlikely to * manipulate in any way. * * We then register a filter for the_content, at high a priority of PHP_INT_MAX as an attempt to make * our hook be the last hook to be executed. This hook then substitutes the placeholders with the markup * generated by the shortcode's callback that was provided in \Imagely\NGG\Display\Shortcodes::add() */ class Shortcodes { private static $_instance = null; private $_shortcodes = []; private $_found = []; private $_placeholder_text = 'ngg_shortcode_%d_placeholder'; /** * @return Shortcodes */ static function get_instance() { if ( \is_null( self::$_instance ) ) { self::$_instance = new Shortcodes(); } return self::$_instance; } /** * Adds a shortcode * * @param $name * @param $callback * @param callable|null Parameters transformer */ static function add( $name, $callback, $transformer = null ) { $manager = self::get_instance(); $manager->add_shortcode( $name, $callback, $transformer ); } /** * @return string[] */ public function get_shortcodes() { return $this->_shortcodes; } public function is_disabled(): bool { return defined( 'NGG_DISABLE_SHORTCODE_MANAGER' ) && NGG_DISABLE_SHORTCODE_MANAGER; } /** * Removes a previously added shortcode * * @param $name */ static function remove( $name ) { $manager = self::get_instance(); $manager->remove_shortcode( $name ); } public function register_hooks() { if ( $this->is_disabled() ) { return; } // For theme & plugin compatibility and to prevent the output of our shortcodes from being // altered we substitute our shortcodes with placeholders at the start of the the_content() filter // queue and then at the end of the the_content() queue, we substitute the placeholders with our // actual markup. \add_filter( 'the_content', [ $this, 'fix_nested_shortcodes' ], -1 ); \add_filter( 'the_content', [ $this, 'parse_content' ], PHP_INT_MAX ); \add_filter( 'widget_text', [ $this, 'fix_nested_shortcodes' ], -1 ); } /** * We're parsing our own shortcodes because WP can't yet handle nested shortcodes [ngg param="[slideshow]"] * * @param string $content * @return string */ public function fix_nested_shortcodes( $content ) { // Try to find each registered shortcode in the content. foreach ( $this->_shortcodes as $tag => $tag_details ) { $shortcode_start_tag = "[{$tag}"; $offset = 0; // Find each occurrence of the shortcode. while ( ( $start_of_shortcode = \strpos( $content, $shortcode_start_tag, $offset ) ) !== false ) { $index = $start_of_shortcode + \strlen( $shortcode_start_tag ); $found_attribute_assignment = false; $current_attribute_enclosure = null; $last_found_char = ''; $content_length = \strlen( $content ) - 1; while ( true ) { // Parse out the shortcode, character-by-character. $char = $content[ $index ]; if ( $char == '"' || $char == "'" && $last_found_char == '=' ) { // Is this the closing quote for an already found attribute assignment? if ( $found_attribute_assignment && $current_attribute_enclosure == $char ) { $found_attribute_assignment = false; $current_attribute_enclosure = null; } else { $found_attribute_assignment = true; $current_attribute_enclosure = $char; } } elseif ( $char == ']' ) { // we've found a shortcode closing tag. But, we need to ensure // that this ] isn't within the value of a shortcode attribute. if ( ! $found_attribute_assignment ) { break; // exit loop - we've found the shortcode. } } $last_found_char = $char; // Prevent infinite loops in our while(TRUE). if ( $index == $content_length ) { break; } ++$index; } // Get the shortcode. $shortcode = \substr( $content, $start_of_shortcode + 1, --$index - $start_of_shortcode ); $shortcode_replacement = \str_replace( [ '[', ']' ], [ '[', ']' ], $shortcode ); // Replace the shortcode with one that doesn't have nested shortcodes. $content = \str_replace( $shortcode, $shortcode_replacement, $content ); // Calculate the offset for the next loop iteration. $offset = $index + 1 + \strlen( $shortcode_replacement ) - \strlen( $shortcode ); } } \reset( $this->_shortcodes ); return $content; } /** * Deactivates all shortcodes */ public function deactivate_all() { foreach ( \array_keys( $this->_shortcodes ) as $shortcode ) { $this->deactivate( $shortcode ); } } /** * Parses the content for shortcodes and returns the substituted content * * @param $content * @return string */ public function parse_content( $content ) { $regex = \str_replace( '%d', '(\d+)', $this->_placeholder_text ); if ( $this->is_rest_request() ) { // Return early if we're in the REST API and shortcodes are disabled. // Allows other plugins to disable shortcodes in the REST API. if ( \apply_filters( 'ngg_disable_shortcodes_in_request_api', true ) ) { return $content; } \ob_start(); } if ( \preg_match_all( "/{$regex}/m", $content, $matches, PREG_SET_ORDER ) ) { foreach ( $matches as $match ) { $placeholder = \array_shift( $match ); $id = \array_shift( $match ); $content = \str_replace( $placeholder, $this->execute_found_shortcode( $id ), $content ); } } if ( $this->is_rest_request() ) { // Pre-generating displayed gallery cache by executing shortcodes in the REST API can prevent users // from being able to add and save blocks with lots of images and no pagination (for example a very large // basic slideshow or pro masonry / mosaic / tile display). if ( \apply_filters( 'ngg_disable_shortcodes_in_request_api', false ) ) { return $content; } \ob_start(); } return $content; } public function render_legacy_shortcode( $params, $inner_content ) { return Renderer::get_instance()->display_images( $params, $inner_content ); } public function execute_found_shortcode( $found_id ) { return isset( $this->_found[ $found_id ] ) ? $this->render_shortcode( $this->_found[ $found_id ]['shortcode'], $this->_found[ $found_id ]['params'], $this->_found[ $found_id ]['inner_content'] ) : 'Invalid shortcode'; } /** * Adds a shortcode * * @param $name * @param $callback * @param callable|null $transformer */ public function add_shortcode( $name, $callback, $transformer = null ) { $this->_shortcodes[ $name ] = [ 'callback' => $callback, 'transformer' => $transformer, ]; if ( $this->is_disabled() ) { // Because render_shortcode() is a wrapper to several shortcodes it requires the $name parameter and can't be passed directly to add_shortcode() add_shortcode( $name, function ( $params, $inner_content ) use ( $name ) { return $this->render_shortcode( $name, $params, $inner_content ); } ); } else { \add_shortcode( $name, [ $this, $name . '____wrapper' ] ); } } /** * Removes a shortcode * * @param $name */ public function remove_shortcode( $name ) { unset( $this->_shortcodes[ $name ] ); $this->deactivate( $name ); } /** * De-activates a shortcode * * @param $shortcode */ public function deactivate( $shortcode ) { if ( isset( $this->_shortcodes[ $shortcode ] ) ) { \remove_shortcode( $shortcode ); } } public function is_rest_request() { return \defined( 'REST_REQUEST' ) || \strpos( $_SERVER['REQUEST_URI'], 'wp-json' ) !== false; } public function __call( $method, $args ) { $params = \array_shift( $args ); $inner_content = \array_shift( $args ); $parts = \explode( '____', $method ); $shortcode = \array_shift( $parts ); if ( \doing_filter( 'the_content' ) && ! \doing_filter( 'widget_text' ) ) { $retval = $this->replace_with_placeholder( $shortcode, $params, $inner_content ); } else { // Widgets don't use placeholders. return $this->render_shortcode( $shortcode, $params, $inner_content ); } return $retval; } public function render_shortcode( $shortcode, $params = [], $inner_content = '' ) { if ( isset( $this->_shortcodes[ $shortcode ] ) ) { $shortcode = $this->_shortcodes[ $shortcode ]; if ( \is_callable( $shortcode['transformer'] ) ) { $params = \call_user_func( $shortcode['transformer'], $params ); } $method = ( \is_null( $shortcode['callback'] ) && \is_callable( $shortcode['transformer'] ) ) ? [ $this, 'render_legacy_shortcode' ] : $shortcode['callback']; $retval = \call_user_func( $method, $params, $inner_content ); } else { $retval = 'Invalid shortcode'; } return $retval; } /** * Prevents wptexturize * * @param $shortcode * @param array $params * @param string $inner_content * @return mixed|void */ public function replace_with_placeholder( $shortcode, $params = [], $inner_content = '' ) { $id = \count( $this->_found ); $this->_found[ $id ] = [ 'shortcode' => $shortcode, 'params' => $params, 'inner_content' => $inner_content, ]; $placeholder = \sprintf( $this->_placeholder_text, $id ); return \apply_filters( 'ngg_shortcode_placeholder', $placeholder, $shortcode, $params, $inner_content ); } /** * @return string */ public function get_shortcode_regex() { $keys = \array_keys( $this->_shortcodes ); return '/' . \get_shortcode_regex( $keys ) . '/'; } } �����������������������������������������Display/StaticPopeAssets.php������������������������������������������������������������������������0000644�����������������00000006314�15021223045�0012116 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\DataMapper\WPModel; use Imagely\NGG\Settings\Settings; class StaticPopeAssets extends StaticAssets { /** * @param $filename * @param false|string $legacy_module_id * @return string */ public static function get_computed_abspath( $filename, $legacy_module_id = false ) { if ( strpos( $filename, '#' ) !== false ) { $parts = explode( '#', $filename ); if ( \count( $parts ) === 2 ) { $filename = $parts[1]; $legacy_module_id = $parts[0]; } else { $filename = $parts[0]; } } elseif ( strpos( $legacy_module_id, '#' ) !== false ) { $parts = explode( '#', $legacy_module_id ); if ( \count( $parts ) === 2 ) { $legacy_module_id = $parts[0]; } } $filename = self::trim_preceding_slash( $filename ); $static_dir = self::trim_preceding_slash( Settings::get_instance()->get( 'mvc_static_dir', '/static' ) ); $override_dir = \wp_normalize_path( self::get_override_dir( $legacy_module_id ) ); $override = \path_join( $override_dir, $filename ); if ( @\stream_resolve_include_path( $override ) ) { return $override; } // Find the POPE modules root. $module_dir = \C_NextGEN_Bootstrap::get_legacy_module_directory( $legacy_module_id ); if ( ! empty( $module_dir ) ) { // To avoid PHP deprecated warnings. $module_dir = \wp_normalize_path( $module_dir ); } // In case NextGen is in a symlink we make $mod_dir relative to the NGG parent root and then rebuild it // using WP_PLUGIN_DIR; without this NGG-in-symlink creates URL that reference the file abspath. if ( \is_link( \path_join( WP_PLUGIN_DIR, \basename( NGG_PLUGIN_DIR ) ) ) ) { $module_dir = \ltrim( \str_replace( \dirname( NGG_PLUGIN_DIR ), '', $module_dir ), DIRECTORY_SEPARATOR ); $module_dir = \path_join( WP_PLUGIN_DIR, $module_dir ); } if ( ! empty( $module_dir ) ) { // To avoid PHP deprecated warnings. $retval = \path_join( \path_join( $module_dir, $static_dir ), $filename ); } else { $retval = ''; } if ( ! is_null( $retval ) ) { // Adjust for windows paths. return \wp_normalize_path( $retval ); } else { return $retval; } } /** * @param string|null $module_id * @return string $dir */ public static function get_override_dir( $module_id = null ) { $root = \trailingslashit( \path_join( WP_CONTENT_DIR, 'ngg' ) ); if ( ! @\file_exists( $root ) && \is_writable( \trailingslashit( WP_CONTENT_DIR ) ) ) { \wp_mkdir_p( $root ); } $modules = \trailingslashit( \path_join( $root, 'modules' ) ); if ( ! @\file_exists( $modules ) && \is_writable( $root ) ) { \wp_mkdir_p( $modules ); } if ( $module_id ) { $module_dir = \trailingslashit( \path_join( $modules, $module_id ) ); if ( ! @\file_exists( $module_dir ) && \is_writable( $modules ) ) { \wp_mkdir_p( $module_dir ); } $static_dir = \trailingslashit( \path_join( $module_dir, 'static' ) ); if ( ! @\file_exists( $static_dir ) && \is_writable( $module_dir ) ) { \wp_mkdir_p( $static_dir ); } return $static_dir; } return $modules; } /** * @param string $str * @return string */ public static function trim_preceding_slash( $str ) { return \preg_replace( '#^/{1,2}#', '', $str, 1 ); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Display/ResourceManager.php�������������������������������������������������������������������������0000644�����������������00000022357�15021223045�0011747 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\Util\URL; class ResourceManager { static $instance = null; public $marker = '<!-- ngg_resource_manager_marker -->'; public $buffer = ''; public $styles = ''; public $scripts = ''; public $other_output = ''; public $wrote_footer = false; public $run_shutdown = false; public $valid_request = true; /** * Start buffering all generated output. We'll then do two things with the buffer * 1) Find stylesheets lately enqueued and move them to the header * 2) Ensure that wp_print_footer_scripts() is called */ public function __construct() { // Validate the request. $this->validate_request(); add_action( 'init', [ $this, 'start_buffer' ], -1 ); add_action( 'wp_footer', [ $this, 'print_marker' ], -1 ); } public static function init() { if ( ! isset( self::$instance ) ) { self::$instance = new ResourceManager(); } return self::$instance; } /** * Created early as possible in the wp_footer action this is the string to which we * will move JS resources after */ public function print_marker() { if ( self::is_disabled() ) { return; } // is_feed() is important to not break WordPress feeds and the WooCommerce api. if ( $this->valid_request && ! is_feed() ) { print $this->marker; } } /** * Determines if the resource manager should perform it's routines for this request */ public function validate_request() { $this->valid_request = $this->is_valid_request(); } /** * Pro, Plus, and Starter versions below these were not ready to function without the resource manager * * @return bool */ public static function addons_version_check() { if ( defined( 'NGG_PRO_PLUGIN_VERSION' ) && version_compare( NGG_PRO_PLUGIN_VERSION, '3.3', '<' ) ) { return false; } if ( defined( 'NGG_STARTER_PLUGIN_VERSION' ) && version_compare( NGG_STARTER_PLUGIN_VERSION, '1.1', '<' ) ) { return false; } if ( defined( 'NGG_PLUS_PLUGIN_VERSION' ) && version_compare( NGG_PLUS_PLUGIN_VERSION, '1.8', '<' ) ) { return false; } return true; } /** * @return bool */ public static function is_disabled(): bool { // This is admittedly an ugly hack, but much easier than reworking the entire nextgen_admin modules. // // Nonce verification is not necessary here. // // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( isset( $_GET['page'] ) && 'ngg_addgallery' === $_GET['page'] && isset( $_GET['attach_to_post'] ) ) { return false; } // Provide users a method of forcing this on should it be necessary. if ( defined( 'NGG_ENABLE_RESOURCE_MANAGER' ) && NGG_ENABLE_RESOURCE_MANAGER ) { return false; } return self::addons_version_check(); } public function is_valid_request() { $retval = true; // Nonce check is not necessary: this is not processing a form, but determining if this class' main feature // should be executed or not. // // phpcs:disable WordPress.Security.NonceVerification.Recommended // Do not apply to NextGEN's admin page. if ( is_admin() && isset( $_REQUEST['page'] ) && ! preg_match( '#^(ngg|nextgen)#', $_REQUEST['page'] ) ) { $retval = false; } // Skip anything found in the WP-Admin. if ( preg_match( '#wp-admin/#', $_SERVER['REQUEST_URI'] ) ) { $retval = false; } // Legacy custom-post based displayed galleries loaded in an iframe. elseif ( isset( $_GET['display_gallery_iframe'] ) ) { $retval = false; } // Skip XHR requests. elseif ( defined( 'WP_ADMIN' ) && WP_ADMIN && defined( 'DOING_AJAX' ) && DOING_AJAX ) { $retval = false; } // Skip NGG's 'dynamic thumbnails' URL endpoints. elseif ( strpos( $_SERVER['REQUEST_URI'], '/nextgen-image/' ) !== false ) { $retval = false; } // Do not process proxy loaders of static resources. elseif ( preg_match( '/(js|css|xsl|xml|kml)$/', $_SERVER['REQUEST_URI'] ) ) { $retval = false; } // Skip the RSS feed. elseif ( preg_match( '#/feed(/?)$#i', $_SERVER['REQUEST_URI'] ) || ! empty( $_GET['feed'] ) ) { $retval = false; } // Skip the 'dynamic stylesheets' URL endpoints used by Pro. elseif ( false !== strpos( $_SERVER['REQUEST_URI'], 'nextgen-dcss?name' ) ) { return false; } // Skip any files belonging to the NGG 1.x days. elseif ( false !== strpos( $_SERVER['REQUEST_URI'], 'nextgen-gallery/src/Legacy/' ) ) { return false; } // Do not process requests made directly to files. elseif ( preg_match( '/\\.(\\w{3,4})$/', $_SERVER['REQUEST_URI'], $match ) ) { if ( ! in_array( $match[1], [ 'htm', 'html', 'php' ] ) ) { $retval = false; } } // Skip legacy versions of the Pro Lightbox. elseif ( ( isset( $_SERVER['PATH_INFO'] ) && strpos( $_SERVER['PATH_INFO'], 'nextgen-pro-lightbox-gallery' ) !== false ) or strpos( $_SERVER['REQUEST_URI'], 'nextgen-pro-lightbox-gallery' ) !== false ) { $retval = false; } // And lastly skip all REST endpoints. elseif ( $this->is_rest_request() ) { $retval = false; } // phpcs:enable WordPress.Security.NonceVerification.Recommended return $retval; } public function is_rest_request() { return defined( 'REST_REQUEST' ) || strpos( $_SERVER['REQUEST_URI'], 'wp-json' ) !== false; } /** * Start the output buffers */ public function start_buffer() { if ( self::is_disabled() ) { return; } if ( apply_filters( 'run_ngg_resource_manager', $this->valid_request ) ) { ob_start( [ $this, 'output_buffer_handler' ] ); ob_start( [ $this, 'get_buffer' ] ); add_action( 'wp_print_footer_scripts', [ $this, 'get_resources' ], 1 ); add_action( 'admin_print_footer_scripts', [ $this, 'get_resources' ], 1 ); add_action( 'shutdown', [ $this, 'shutdown' ] ); } } public function get_resources() { ob_start(); wp_print_styles(); print_admin_styles(); $this->styles = ob_get_clean(); if ( ! is_admin() ) { ob_start(); wp_print_scripts(); $this->scripts = ob_get_clean(); } $this->wrote_footer = true; } /** * Output the buffer after PHP execution has ended (but before shutdown) * * @param $content * @return string */ public function output_buffer_handler( $content ) { return $this->output_buffer(); } /** * Removes the closing </html> tag from the output buffer. We'll then write our own closing tag * in the shutdown function after running wp_print_footer_scripts() * * @param $content * @return mixed */ public function get_buffer( $content ) { $this->buffer = $content; return ''; } /** * Moves resources to their appropriate place */ public function move_resources() { if ( $this->valid_request ) { // Move stylesheets to head. if ( $this->styles ) { $this->buffer = str_ireplace( '</head>', $this->styles . '</head>', $this->buffer ); } // Move the scripts to the bottom of the page. if ( $this->scripts ) { $this->buffer = str_ireplace( $this->marker, $this->marker . $this->scripts, $this->buffer ); } if ( $this->other_output ) { $this->buffer = str_replace( $this->marker, $this->marker . $this->other_output, $this->buffer ); } } } /** * When PHP has finished, we output the footer scripts and closing tags * * @param bool $in_shutdown * @return string */ public function output_buffer( $in_shutdown = false ) { // If the footer scripts haven't been outputted, then // we need to take action - as they're required. if ( ! $this->wrote_footer ) { // If W3TC is installed and activated, we can't output the scripts and manipulate the buffer, so we can only provide a warning. if ( defined( 'W3TC' ) && defined( 'WP_DEBUG' ) && WP_DEBUG && ! is_admin() ) { if ( ! defined( 'DONOTCACHEPAGE' ) ) { define( 'DONOTCACHEPAGE', true ); } if ( ! did_action( 'wp_footer' ) ) { error_log( "We're sorry, but your theme's page template didn't make a call to wp_footer(), which is required by NextGEN Gallery. Please add this call to your page templates." ); } else { error_log( "We're sorry, but your theme's page template didn't make a call to wp_print_footer_scripts(), which is required by NextGEN Gallery. Please add this call to your page templates." ); } } // We don't want to manipulate the buffer if it doesn't contain HTML. elseif ( strpos( $this->buffer, '</body>' ) === false ) { $this->valid_request = false; } // The output_buffer() function has been called in the PHP shutdown callback // This will allow us to print the scripts ourselves and manipulate the buffer. if ( $in_shutdown === true && $this->valid_request ) { ob_start(); if ( ! did_action( 'wp_footer' ) ) { wp_footer(); } else { wp_print_footer_scripts(); } $this->other_output = ob_get_clean(); $this->buffer = str_ireplace( '</body>', $this->marker . '</body>', $this->buffer ); } // W3TC isn't activated and we're not in the shutdown callback. We'll therefore add a shutdown callback to print the scripts. else { $this->run_shutdown = true; return ''; } } // Once we have the footer scripts, we can modify the buffer and move the resources around. if ( $this->wrote_footer ) { $this->move_resources(); } return $this->buffer; } /** * PHP shutdown callback. Manipulate and output the buffer */ public function shutdown() { if ( $this->run_shutdown ) { echo $this->output_buffer( true ); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Display/DisplayManager.php��������������������������������������������������������������������������0000644�����������������00000040664�15021223045�0011566 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\DataTypes\{DisplayType, DisplayedGallery}; use Imagely\NGG\DisplayType\{Controller, ControllerFactory}; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Router; class DisplayManager { public static $enqueued_displayed_gallery_ids = []; public static function register_hooks() { $self = new DisplayManager(); Shortcodes::add( 'ngg', [ $self, 'display_images' ] ); Shortcodes::add( 'ngg_images', [ $self, 'display_images' ] ); add_filter( 'the_content', [ $self, '_render_related_images' ] ); add_action( 'init', [ $self, 'register_resources' ], 12 ); add_action( 'admin_bar_menu', [ $self, 'add_admin_bar_menu' ], 100 ); add_action( 'wp_print_styles', [ $self, 'fix_nextgen_custom_css_order' ], PHP_INT_MAX - 1 ); add_action( 'wp_enqueue_scripts', [ $self, 'enqueue_frontend_resources' ] ); } public function enqueue_frontend_resources() { if ( ( defined( 'NGG_SKIP_LOAD_SCRIPTS' ) && NGG_SKIP_LOAD_SCRIPTS ) || $this->is_rest_request() ) { return; } // Find our content and process it. global $wp_query; // It's possible for the posts attribute to be empty or unset. if ( ! isset( $wp_query->posts ) || ! is_array( $wp_query->posts ) ) { return; } $posts = $wp_query->posts; foreach ( $posts as $post ) { if ( empty( $post->post_content ) ) { continue; } self::enqueue_frontend_resources_for_content( $post->post_content ); } } /** * Most content will come from the WP query / global $posts but it's also sometimes necessary to enqueue resources * based on the results of an output filter * * @param string $content */ public static function enqueue_frontend_resources_for_content( $content = '' ) { $manager = Shortcodes::get_instance(); $pattern = $manager->get_shortcode_regex(); $ngg_shortcodes = $manager->get_shortcodes(); $ngg_shortcodes_keys = array_keys( $ngg_shortcodes ); // Determine which shortcodes to look for; 'ngg' is the default, but there are legacy aliases. preg_match_all( $pattern, $content, $matches, PREG_SET_ORDER ); foreach ( $matches as $shortcode ) { $this_shortcode_name = $shortcode[2]; if ( ! in_array( $this_shortcode_name, $ngg_shortcodes_keys, true ) ) { continue; } $params = shortcode_parse_atts( trim( $shortcode[0], '[]' ) ); if ( in_array( $params[0], $ngg_shortcodes_keys, true ) ) { // Don't pass 0 => 'ngg' as a parameter, it's just part of the shortcode itself. unset( $params[0] ); } // And do the enqueueing process. $renderer = Renderer::get_instance(); // This is necessary for legacy shortcode compatibility. if ( is_callable( $ngg_shortcodes[ $this_shortcode_name ]['transformer'] ) ) { $params = call_user_func( $ngg_shortcodes[ $this_shortcode_name ]['transformer'], $params ); } $displayed_gallery = $renderer->params_to_displayed_gallery( $params ); // TODO: Fix Pro so this is unnecessary and then remove the following check. if ( did_action( 'wp_enqueue_scripts' ) == 1 && ! ResourceManager::addons_version_check() && in_array( $displayed_gallery->display_type, [ 'photocrati-nextgen_pro_horizontal_filmstrip', 'photocrati-nextgen_pro_slideshow' ], true ) ) { continue; } if ( ControllerFactory::has_controller( $displayed_gallery->display_type ) ) { $controller = ControllerFactory::get_controller( $displayed_gallery->display_type ); } if ( ! isset( $controller ) && class_exists( '\C_Display_Type_Controller' ) ) { $controller = new \C_Display_Type_Controller( $displayed_gallery->display_type ); } if ( ! $displayed_gallery || empty( $params ) || ! isset( $controller ) ) { continue; } self::enqueue_frontend_resources_for_displayed_gallery( $displayed_gallery, $controller ); // Prevent $controller from persisting through this loop unset( $controller ); } } /** * @param DisplayedGallery $displayed_gallery * @param Controller $controller */ public static function enqueue_frontend_resources_for_alternate_displayed_gallery( $displayed_gallery, $controller ) { // Allow basic thumbnails "use imagebrowser effect" feature to seamlessly change between display types as well // as for album display types to show galleries. $alternate_displayed_gallery = $controller->get_alternative_displayed_gallery( $displayed_gallery ); if ( $alternate_displayed_gallery === $displayed_gallery ) { return; } $alternate_controller = ControllerFactory::get_controller( $alternate_displayed_gallery->display_type ); if ( ! $alternate_controller && class_exists( 'C_Display_Type_Controller', false ) ) { $alternate_controller = \C_Display_Type_Controller::get_instance( $alternate_displayed_gallery->display_type ); } self::enqueue_frontend_resources_for_displayed_gallery( $alternate_displayed_gallery, $alternate_controller ); } /** * @param DisplayedGallery $displayed_gallery * @param Controller $controller */ public static function enqueue_frontend_resources_for_displayed_gallery( $displayed_gallery, $controller ) { if ( is_null( $displayed_gallery->id() ) ) { $displayed_gallery->id( md5( json_encode( $displayed_gallery->get_entity() ) ) ); } self::$enqueued_displayed_gallery_ids[] = $displayed_gallery->id(); $controller->enqueue_frontend_resources( $displayed_gallery ); if ( method_exists( $controller, 'get_alternative_displayed_gallery' ) ) { self::enqueue_frontend_resources_for_alternate_displayed_gallery( $displayed_gallery, $controller ); } } public function is_rest_request(): bool { if ( ! isset( $_SERVER['REQUEST_URI'] ) ) { return false; } return defined( 'REST_REQUEST' ) || false !== strpos( $_SERVER['REQUEST_URI'], 'wp-json' ); } /** * This moves the NextGen custom CSS to the last of the queue */ public function fix_nextgen_custom_css_order() { global $wp_styles; if ( in_array( 'nggallery', $wp_styles->queue, true ) ) { foreach ( $wp_styles->queue as $ndx => $style ) { if ( $style == 'nggallery' ) { unset( $wp_styles->queue[ $ndx ] ); $wp_styles->queue[] = 'nggallery'; break; } } } } static function enqueue_fontawesome() { // The official plugin is active, we don't need to do anything outside the wp-admin. if ( defined( 'FONT_AWESOME_OFFICIAL_LOADED' ) && ! is_admin() ) { return; } $settings = Settings::get_instance(); if ( $settings->get( 'disable_fontawesome' ) ) { return; } wp_register_script( 'fontawesome_v4_shim', StaticAssets::get_url( 'FontAwesome/js/v4-shims.min.js' ), [], '5.3.1' ); if ( ! wp_script_is( 'fontawesome', 'registered' ) ) { add_filter( 'script_loader_tag', [ '\Imagely\NGG\Display\DisplayManager', 'fix_fontawesome_script_tag' ], 10, 2 ); wp_enqueue_script( 'fontawesome', StaticAssets::get_url( 'FontAwesome/js/all.min.js' ), [ 'fontawesome_v4_shim' ], '5.3.1' ); } if ( ! wp_style_is( 'fontawesome', 'registered' ) ) { wp_enqueue_style( 'fontawesome_v4_shim_style', StaticAssets::get_url( 'FontAwesome/css/v4-shims.min.css' ) ); wp_enqueue_style( 'fontawesome', StaticAssets::get_url( 'FontAwesome/css/all.min.css' ) ); } wp_enqueue_script( 'fontawesome_v4_shim' ); wp_enqueue_script( 'fontawesome' ); } /** * WP doesn't allow an easy way to set the defer, crossorign, or integrity attributes on our <script> * * @param string $tag * @param string $handle * @return string */ public static function fix_fontawesome_script_tag( $tag, $handle ) { if ( 'fontawesome' !== $handle ) { return $tag; } return str_replace( ' src', ' defer crossorigin="anonymous" data-auto-replace-svg="false" data-keep-original-source="false" data-search-pseudo-elements src', $tag ); } static function _render_related_string( $sluglist = [], $maxImages = null, $type = null ) { $settings = Settings::get_instance(); if ( is_null( $type ) ) { $type = $settings->get( 'appendType' ); } if ( is_null( $maxImages ) ) { $maxImages = $settings->get( 'maxImages' ); } if ( ! $sluglist ) { switch ( $type ) { case 'tags': if ( function_exists( 'get_the_tags' ) ) { $taglist = \get_the_tags(); if ( is_array( $taglist ) ) { foreach ( $taglist as $tag ) { $sluglist[] = $tag->slug; } } } break; case 'category': $catlist = \get_the_category(); if ( is_array( $catlist ) ) { foreach ( $catlist as $cat ) { $sluglist[] = $cat->category_nicename; } } break; } } $taglist = implode( ',', $sluglist ); if ( $taglist === 'uncategorized' || empty( $taglist ) ) { return ''; } $renderer = Renderer::get_instance(); $view = new View( '', [], '' ); $retval = $renderer->display_images( [ 'source' => 'tags', 'container_ids' => $taglist, 'display_type' => NGG_BASIC_THUMBNAILS, 'images_per_page' => $maxImages, 'maximum_entity_count' => $maxImages, 'template' => $view->find_template_abspath( 'GalleryDisplay/Related', 'photocrati-nextgen_gallery_display#related' ), 'show_all_in_lightbox' => false, 'show_slideshow_link' => false, 'disable_pagination' => true, 'display_no_images_error' => false, ] ); if ( $retval ) { \wp_enqueue_style( 'nextgen_gallery_related_images' ); } return \apply_filters( 'ngg_show_related_gallery_content', $retval, $taglist ); } public function _render_related_images( $content ) { $settings = Settings::get_instance(); if ( $settings->get( 'activateTags' ) ) { $related = self::_render_related_string(); if ( null !== $related ) { $heading = $settings->get( 'relatedHeading' ); $content .= $heading . $related; } } return $content; } /** * Adds menu item to the admin bar */ public function add_admin_bar_menu() { global $wp_admin_bar; if ( \current_user_can( 'NextGEN Change options' ) ) { $wp_admin_bar->add_menu( [ 'parent' => 'ngg-menu', 'id' => 'ngg-menu-display_settings', 'title' => __( 'Gallery Settings', 'nggallery' ), 'href' => admin_url( 'admin.php?page=ngg_display_settings' ), ] ); } } /** * Registers our static settings resources so the ATP module can find them later */ public function register_resources() { // Register custom post types for compatibility. $types = [ 'displayed_gallery' => 'NextGEN Gallery - Displayed Gallery', 'display_type' => 'NextGEN Gallery - Display Type', 'gal_display_source' => 'NextGEN Gallery - Displayed Gallery Source', ]; foreach ( $types as $type => $label ) { \register_post_type( $type, [ 'label' => $label, 'publicly_queryable' => false, 'exclude_from_search' => true, ] ); } \wp_register_script( 'shave.js', StaticAssets::get_url( 'GalleryDisplay/shave.js', 'photocrati-nextgen_gallery_display#shave.js' ), [], NGG_SCRIPT_VERSION ); \wp_register_style( 'nextgen_gallery_related_images', StaticAssets::get_url( 'GalleryDisplay/nextgen_gallery_related_images.css', 'photocrati-nextgen_gallery_display#nextgen_gallery_related_images.css' ), [], NGG_SCRIPT_VERSION ); \wp_register_script( 'ngg_common', StaticAssets::get_url( 'GalleryDisplay/common.js', 'photocrati-nextgen_gallery_display#common.js' ), [ 'jquery', 'photocrati_ajax' ], NGG_SCRIPT_VERSION, true ); \wp_register_style( 'ngg_trigger_buttons', StaticAssets::get_url( 'GalleryDisplay/trigger_buttons.css', 'photocrati-nextgen_gallery_display#trigger_buttons.css' ), [], NGG_SCRIPT_VERSION ); \wp_register_script( 'ngg_waitforimages', StaticAssets::get_url( 'GalleryDisplay/jquery.waitforimages-2.4.0-modded.js', 'photocrati-nextgen_gallery_display#jquery.waitforimages-2.4.0-modded.js' ), [ 'jquery' ], NGG_SCRIPT_VERSION ); $settings = Settings::get_instance(); $router = Router::get_instance(); \wp_register_script( 'photocrati_ajax', StaticAssets::get_url( 'Legacy/ajax.min.js', 'photocrati-ajax#ajax.min.js' ), [ 'jquery' ], NGG_SCRIPT_VERSION ); $vars = [ 'url' => $settings->get( 'ajax_url' ), 'rest_url' => get_rest_url(), 'wp_home_url' => $router->get_base_url( 'home' ), 'wp_site_url' => $router->get_base_url( 'site' ), 'wp_root_url' => $router->get_base_url( 'root' ), 'wp_plugins_url' => $router->get_base_url( 'plugins' ), 'wp_content_url' => $router->get_base_url( 'content' ), 'wp_includes_url' => includes_url(), 'ngg_param_slug' => $settings->get( 'router_param_slug', 'nggallery' ), 'rest_nonce' => wp_create_nonce( 'wp_rest' ), ]; \wp_localize_script( 'photocrati_ajax', 'photocrati_ajax', $vars ); } /** * Provides the [ngg] and [ngg_images] shortcodes * * @param array $params * @param string $inner_content * @return string */ public function display_images( $params, $inner_content = null ) { $renderer = Renderer::get_instance(); return $renderer->display_images( $params, $inner_content ); } /** * Gets a list of directories in which display type template might be stored * * @param DisplayType|string $display_type * @return array */ static function get_display_type_view_dirs( $display_type ) { if ( is_string( $display_type ) ) { $display_type = DisplayTypeMapper::get_instance()->find_by_name( $display_type ); } // Create an array of directories to scan. $dirs = []; if ( ControllerFactory::has_controller( $display_type->name ) ) { $controller = ControllerFactory::get_controller( $display_type->name ); $dirs['default'] = $controller->get_template_directory_abspath(); } if ( empty( $dirs['default'] ) ) { // In case the module path cannot be determined, we must intervene here if the resulting string is just '/templates' // which is a place where template files should not be stored. $directory = \C_NextGEN_Bootstrap::get_legacy_module_directory( $display_type->name ) . DIRECTORY_SEPARATOR . 'templates'; if ( '/templates' !== $directory ) { $dirs['default'] = $directory; } } $dirs['custom'] = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'ngg' . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $display_type->name . DIRECTORY_SEPARATOR . 'templates'; /* Apply filters so third party devs can add directories for their templates */ $dirs = \apply_filters( 'ngg_display_type_template_dirs', $dirs, $display_type ); $dirs = \apply_filters( 'ngg_' . $display_type->name . '_template_dirs', $dirs, $display_type ); foreach ( $display_type->aliases as $alias ) { $dirs = \apply_filters( "ngg_{$alias}_template_dirs", $dirs, $display_type ); } return $dirs; } /** * Adds data to the DOM which is then accessible by a script * * @param string $handle * @param string $object_name * @param mixed $object_value * @param bool $define * @param bool $override * @return bool */ public static function add_script_data( $handle, $object_name, $object_value, $define = true, $override = false ) { global $wp_scripts; $retval = false; // wp_localize_script allows you to add data to the DOM, associated with a particular script. You can even // call wp_localize_script multiple times to add multiple objects to the DOM. However, there are a few problems // with wp_localize_script: // - If you call it with the same object_name more than once, you're overwriting the first call. // - You cannot namespace your objects due to the "var" keyword always being used. // // To circumvent the above issues, we're going to use the WP_Scripts object to work around the above issues. // Has the script been registered or enqueued? if ( isset( $wp_scripts->registered[ $handle ] ) ) { // Get the associated data with this script. $script = &$wp_scripts->registered[ $handle ]; $data = isset( $script->extra['data'] ) ? $script->extra['data'] : ''; // Construct the addition. $addition = $define ? "\nvar {$object_name} = " . json_encode( $object_value ) . ';' : "\n{$object_name} = " . json_encode( $object_value ) . ';'; // Add the addition. if ( $override ) { $data .= $addition; $retval = true; } elseif ( strpos( $data, $object_name ) === false ) { $data .= $addition; $retval = true; } $script->extra['data'] = $data; unset( $script ); } return $retval; } } ����������������������������������������������������������������������������Display/LightboxManager.php�������������������������������������������������������������������������0000644�����������������00000026551�15021223045�0011740 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\Settings\Settings; use Imagely\NGG\DataTypes\Lightbox; class LightboxManager { private $lightboxes = []; private $has_registered_default_lightboxes = false; /** * @var LightboxManager */ private static $_instance = null; /** * @return LightboxManager */ public static function get_instance() { if ( ! isset( self::$_instance ) ) { self::$_instance = new LightboxManager(); } return self::$_instance; } public function register_defaults() { $settings = Settings::get_instance(); // No lightbox at all. $none = new Lightbox( 'none' ); $none->title = \__( 'None', 'nggallery' ); $this->register( 'none', $none ); $simplelightbox = new Lightbox( 'simplelightbox' ); $simplelightbox->title = \__( 'Simplelightbox', 'nggallery' ); $simplelightbox->code = 'class="ngg-simplelightbox" rel="%GALLERY_NAME%"'; $simplelightbox->styles = [ [ 'Lightbox/simplelightbox/simple-lightbox.css', 'photocrati-lightbox#simplelightbox/simple-lightbox.css' ], ]; $simplelightbox->scripts = [ [ 'Lightbox/simplelightbox/simple-lightbox.js', 'photocrati-lightbox#simplelightbox/simple-lightbox.js' ], [ 'Lightbox/simplelightbox/nextgen_simple_lightbox_init.js', 'photocrati-lightbox#simplelightbox/nextgen_simple_lightbox_init.js' ], ]; $this->register( 'simplelightbox', $simplelightbox ); $fancybox = new Lightbox( 'fancybox' ); $fancybox->title = \__( 'Fancybox', 'nggallery' ); $fancybox->code = 'class="ngg-fancybox" rel="%GALLERY_NAME%"'; $fancybox->styles = [ [ 'Lightbox/fancybox/jquery.fancybox-1.3.4.css', 'photocrati-lightbox#fancybox/jquery.fancybox-1.3.4.css' ], ]; $fancybox->scripts = [ [ 'Lightbox/fancybox/jquery.easing-1.3.pack.js', 'photocrati-lightbox#fancybox/jquery.easing-1.3.pack.js' ], [ 'Lightbox/fancybox/jquery.fancybox-1.3.4.pack.js', 'photocrati-lightbox#fancybox/jquery.fancybox-1.3.4.pack.js' ], [ 'Lightbox/fancybox/nextgen_fancybox_init.js', 'photocrati-lightbox#fancybox/nextgen_fancybox_init.js' ], ]; $this->register( 'fancybox', $fancybox ); $shutter = new Lightbox( 'shutter' ); $shutter->title = \__( 'Shutter', 'nggallery' ); $shutter->code = 'class="shutterset_%GALLERY_NAME%"'; $shutter->styles = [ [ 'Lightbox/shutter/shutter.css', 'photocrati-lightbox#shutter/shutter.css' ], ]; $shutter->scripts = [ [ 'Lightbox/shutter/shutter.js', 'photocrati-lightbox#shutter/shutter.js' ], [ 'Lightbox/shutter/nextgen_shutter.js', 'photocrati-lightbox#shutter/nextgen_shutter.js' ], ]; $shutter->values = [ 'nextgen_shutter_i18n' => [ 'msgLoading' => \__( 'L O A D I N G', 'nggallery' ), 'msgClose' => \__( 'Click to Close', 'nggallery' ), ], ]; $this->register( 'shutter', $shutter ); $shutter2 = new Lightbox( 'shutter2' ); $shutter2->title = \__( 'Shutter Reloaded', 'nggallery' ); $shutter2->code = 'class="shutterset_%GALLERY_NAME%"'; $shutter2->styles = [ [ 'Lightbox/shutter_reloaded/shutter.css', 'photocrati-lightbox#shutter_reloaded/shutter.css' ], ]; $shutter2->scripts = [ [ 'Lightbox/shutter_reloaded/shutter.js', 'photocrati-lightbox#shutter_reloaded/shutter.js' ], [ 'Lightbox/shutter_reloaded/nextgen_shutter_reloaded.js', 'photocrati-lightbox#shutter_reloaded/nextgen_shutter_reloaded.js' ], ]; $shutter2->values = [ 'nextgen_shutter2_i18n' => [ \__( 'Previous', 'nggallery' ), \__( 'Next', 'nggallery' ), \__( 'Close', 'nggallery' ), \__( 'Full Size', 'nggallery' ), \__( 'Fit to Screen', 'nggallery' ), \__( 'Image', 'nggallery' ), \__( 'of', 'nggallery' ), \__( 'Loading...', 'nggallery' ), ], ]; $this->register( 'shutter2', $shutter2 ); $thickbox = new Lightbox( 'thickbox' ); $thickbox->title = \__( 'Thickbox', 'nggallery' ); $thickbox->code = "class='thickbox' rel='%GALLERY_NAME%'"; $thickbox->styles = [ 'wordpress#thickbox' ]; $thickbox->scripts = [ [ 'Lightbox/thickbox/nextgen_thickbox_init.js', 'photocrati-lightbox#thickbox/nextgen_thickbox_init.js' ], [ 'Lightbox/thickbox/thickbox.js', 'photocrati-lightbox#thickbox/thickbox.js' ], ]; $thickbox->values = [ 'nextgen_thickbox_i18n' => [ 'next' => \__( 'Next >', 'nggallery' ), 'prev' => \__( '< Prev', 'nggallery' ), 'image' => \__( 'Image', 'nggallery' ), 'of' => \__( 'of', 'nggallery' ), 'close' => \__( 'Close', 'nggallery' ), 'noiframes' => \__( 'This feature requires inline frames. You have iframes disabled or your browser does not support them.', 'nggallery' ), ], ]; $this->register( 'thickbox', $thickbox ); // Allow third parties to integrate. do_action( 'ngg_registered_default_lightboxes' ); // Custom lightbox. $custom = new Lightbox( 'custom' ); $custom->title = \__( 'Custom', 'nggallery' ); $custom->code = $settings->get( 'thumbEffectCode', [] ); $custom->styles = $settings->get( 'thumbEffectStyles', [] ); $custom->scripts = $settings->get( 'thumbEffectScripts', [] ); $this->register( 'custom_lightbox', $custom ); $this->has_registered_default_lightboxes = true; } /** * @param string $name * @param Lightbox $lightbox * @return void */ public function register( $name, $lightbox ) { $lightbox->name = $name; $this->lightboxes[ $name ] = $lightbox; } /** * @param string $name * @return void */ public function deregister( $name ) { unset( $this->lightboxes[ $name ] ); } /** * @param string $name * @return Lightbox|void */ public function get( $name ) { if ( ! $this->has_registered_default_lightboxes ) { $this->register_defaults(); } if ( isset( $this->lightboxes[ $name ] ) ) { return $this->lightboxes[ $name ]; } } /** * Returns which lightbox effect has been chosen * * Highslide and jQuery.Lightbox were removed in 2.0.73 due to licensing. If a user has selected either of those * options we silently make their selection fallback to Fancybox. * * @return Lightbox */ public function get_selected() { $settings = Settings::get_instance(); $thumbEffect = $settings->get( 'thumbEffect' ); // These have been removed from NextGEN; if they were previously selected update them to Fancybox. if ( in_array( $thumbEffect, [ 'highslide', 'lightbox' ] ) ) { $settings->set( 'thumbEffect', 'fancybox' ); } // Fallback to SimpleLightbox in case of failure. if ( ! $this->is_registered( $thumbEffect ) || empty( $thumbEffect ) ) { $settings->set( 'thumbEffect', 'simplelightbox' ); } return $this->get( $settings->get( 'thumbEffect' ) ); } /** * @return array */ public function get_all() { if ( ! $this->has_registered_default_lightboxes ) { $this->register_defaults(); } return array_values( $this->lightboxes ); } /** * @param string $name * @return bool */ public function is_registered( $name ) { return ! is_null( $this->get( $name ) ); } public function maybe_enqueue() { $settings = Settings::get_instance(); $thumbEffectContext = $settings->get( 'thumbEffectContext', '' ); if ( $thumbEffectContext != 'nextgen_images' ) { $this->enqueue(); } } /** * @param string $lightbox * @return void */ public function enqueue( $lightbox = null ) { $settings = Settings::get_instance(); $thumbEffectContext = $settings->get( 'thumbEffectContext', '' ); // If no lightbox has been provided, get the selected lightbox. if ( ! $lightbox ) { $lightbox = $this->get_selected(); } else { $lightbox = $this->get( $lightbox ); } if ( ! wp_script_is( 'ngg_lightbox_context' ) ) { wp_enqueue_script( 'ngg_lightbox_context', StaticAssets::get_url( 'Lightbox/lightbox_context.js', 'photocrati-lightbox#lightbox_context.js' ), [ 'ngg_common', 'photocrati_ajax' ], NGG_SCRIPT_VERSION, true ); } // TODO: move this into a shutter-reloaded 'value'. DisplayManager::add_script_data( 'ngg_common', 'nextgen_lightbox_settings', [ 'static_path' => trailingslashit( NGG_PLUGIN_URI ) . 'static/Lightbox/{placeholder}', 'context' => $thumbEffectContext, ], true, true ); // Enqueue lightbox resources, only if we have a configured lightbox. if ( $lightbox ) { // Add lightbox script data. if ( isset( $lightbox->values ) ) { foreach ( $lightbox->values as $name => $value ) { if ( empty( $value ) ) { continue; } DisplayManager::add_script_data( 'ngg_lightbox_context', $name, $value ); } } // Enqueue stylesheets. for ( $i = 0; $i < count( $lightbox->styles ); $i++ ) { $legacy_src = ''; $src = $lightbox->styles[ $i ]; if ( is_array( $src ) ) { list($src, $legacy_src) = $src; } if ( empty( $legacy_src ) ) { $legacy_src = $src; $src = ''; } if ( 0 === strpos( $src, 'wordpress#' ) ) { $parts = explode( 'wordpress#', $src ); wp_enqueue_style( array_pop( $parts ) ); } elseif ( 0 === strpos( $legacy_src, 'wordpress#' ) ) { $parts = explode( 'wordpress#', $legacy_src ); wp_enqueue_style( array_pop( $parts ) ); } elseif ( ! empty( $src ) || ! empty( $legacy_src ) ) { wp_enqueue_style( $lightbox->name . "-{$i}", $this->_handle_url( $src, $legacy_src ), [], NGG_SCRIPT_VERSION ); } } // Enqueue scripts. for ( $i = 0; $i < count( $lightbox->scripts ); $i++ ) { $legacy_src = ''; $src = $lightbox->scripts[ $i ]; $handle = $lightbox->name . "-{$i}"; if ( is_array( $src ) ) { list($src, $legacy_src) = $src; } if ( empty( $legacy_src ) ) { $legacy_src = $src; $src = ''; } if ( 0 === strpos( $src, 'wordpress#' ) ) { $parts = explode( 'wordpress#', $src ); wp_enqueue_script( array_pop( $parts ) ); } elseif ( 0 === strpos( $legacy_src, 'wordpress#' ) ) { $parts = explode( 'wordpress#', $legacy_src ); wp_enqueue_script( array_pop( $parts ) ); } elseif ( ! empty( $src ) || ! empty( $legacy_src ) ) { wp_enqueue_script( $handle, $this->_handle_url( $src, $legacy_src ), [ 'ngg_lightbox_context' ], NGG_SCRIPT_VERSION, true ); } } } } /** * Parses certain paths through get_static_url * * @param string $url * @param string $legacy_module_id * @return string Resulting URL */ public static function _handle_url( $url, $legacy_module_id = '' ) { if ( 0 !== strpos( $url, '/' ) && 0 !== strpos( $url, 'wordpress#' ) && 0 !== strpos( $url, 'http://' ) && 0 !== strpos( $url, 'https://' ) ) { if ( ! empty( $legacy_module_id ) && empty( $url ) ) { $url = StaticPopeAssets::get_url( $legacy_module_id ); } else { $url = StaticAssets::get_url( $url, $legacy_module_id ); } } elseif ( strpos( $url, '/' ) === 0 ) { $url = home_url( $url ); } return $url; } public function deregister_all() { $this->lightboxes = []; $this->has_registered_default_lightboxes = false; } /** * @TODO Remove this when Pro no longer requires it * @deprecated * @param string $handle * @param string $object_name * @param mixed $object_value * @param bool $define * @param bool $override * @return bool */ public function _add_script_data( $handle, $object_name, $object_value, $define = true, $override = false ) { return DisplayManager::add_script_data( $handle, $object_name, $object_value, $define, $override ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������Display/StaticAssets.php����������������������������������������������������������������������������0000644�����������������00000004153�15021223045�0011271 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; class StaticAssets { public static $default_plugin_root = NGG_PLUGIN_DIR; public static $new_override_path_name = 'nextgen-gallery-static-overrides'; /** * @param string $filename * @param false|string $legacy_module_id * @return string */ public static function get_url( $filename, $legacy_module_id = false ) { $retval = self::get_abspath( $filename, $legacy_module_id ); // Allow for overrides from WP_CONTENT/ngg/. if ( \strpos( $retval, \path_join( WP_CONTENT_DIR, 'ngg' ) ) !== false ) { $retval = \str_replace( \wp_normalize_path( WP_CONTENT_DIR ), WP_CONTENT_URL, $retval ); } // Normal plugin distributed files. $retval = \str_replace( \wp_normalize_path( WP_PLUGIN_DIR ), WP_PLUGIN_URL, $retval ); return \is_ssl() ? \str_replace( 'http:', 'https:', $retval ) : $retval; } /** * @param string $filename * @param false|string $legacy_module_id * @return string */ public static function get_abspath( $filename, $legacy_module_id = false ) { static $cache = []; $key = $filename . (string) $legacy_module_id; if ( ! isset( $cache[ $key ] ) ) { $cache[ $key ] = static::get_computed_abspath( $filename, $legacy_module_id ); } return $cache[ $key ]; } /** * @param string $filename * @param false|string $legacy_module_id * @return string */ public static function get_computed_abspath( $filename, $legacy_module_id = false ) { $files = [ 'new_paths' => \path_join( WP_CONTENT_DIR, static::$new_override_path_name . DIRECTORY_SEPARATOR . $filename ), 'default' => \path_join( static::$default_plugin_root, 'static' . DIRECTORY_SEPARATOR . $filename ), ]; if ( ! empty( $legacy_module_id ) ) { $files['legacy'] = StaticPopeAssets::get_computed_abspath( $filename, $legacy_module_id ); } $retval = ''; foreach ( $files as $label => $filename ) { if ( @\stream_resolve_include_path( $filename ) ) { $retval = $filename; break; } } if ( is_string( $retval ) ) { // Adjust for windows paths. return \wp_normalize_path( $retval ); } else { return $retval; } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Display/View.php������������������������������������������������������������������������������������0000644�����������������00000026775�15021223045�0007607 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Display; use Imagely\NGG\DisplayType\ControllerFactory; use Imagely\NGG\DisplayedGallery\TriggerManager; use Imagely\NGG\Util\Filesystem; class View { public $template = ''; public $params = []; public $queue = []; public $legacy_template = ''; public static $default_root_dir = NGG_PLUGIN_DIR; public function __construct( $template, $params = [], $legacy_template_filename = '' ) { $this->template = $template; $this->params = (array) $params; $this->legacy_template = $legacy_template_filename; // Allow display types' global template / 'view' setting to be used in place of whatever is passed as // $template from the display type controller. if ( isset( $params['displayed_gallery'] ) && isset( $params['displayed_gallery']->display_type ) && isset( $params['display_type_rendering'] ) && $params['display_type_rendering'] && ControllerFactory::has_controller( $params['displayed_gallery']->display_type ) ) { $controller = ControllerFactory::get_controller( $params['displayed_gallery']->display_type ); $this->template = $controller->get_display_type_view_abspath( $template, $params ); } } /** * Returns the variables to be used in the template * * @return array */ public function get_template_vars() { $retval = []; foreach ( $this->params as $key => $value ) { if ( strpos( $key, '_template' ) === 0 ) { $value = $this->get_template_abspath( $value ); } $retval[ $key ] = $value; } return $retval; } /** * @param string $filename * @return bool */ public function is_valid_template_filename( $filename ) { $fs = Filesystem::get_instance(); $filename = str_replace( '\\', '/', $filename ); // Do not allow PHP input streams as a source. if ( false !== strpos( $filename, '://' ) ) { return false; } // Prevent all "../" attempts. if ( false !== strpos( $filename, '../' ) ) { return false; } // Bitnami stores files in /opt/bitnami, but PHP's ReflectionClass->getFileName() can report /bitnami // which causes this method to reject files for being outside the server document root. if ( 0 === strpos( $filename, '/bitnami', 0 ) ) { $filename = '/opt' . $filename; } // The template must reside in the WordPress root or its plugin, theme, or content directories. $permitted_directories = [ $fs->get_document_root(), $fs->get_document_root( 'plugin' ), $fs->get_document_root( 'plugin_mu' ), $fs->get_document_root( 'theme' ), $fs->get_document_root( 'content' ), ]; $found = false; foreach ( $permitted_directories as $directory ) { if ( $found ) { continue; } if ( 0 === strpos( $filename, $directory ) ) { $found = true; } } if ( ! $found ) { return false; } // Filename must end with ".php". if ( substr_compare( $filename, '.php', -3 ) === 0 ) { return false; } return true; } public function get_template_abspath( string $template = null ): string { if ( ! $template ) { $template = $this->template; } $legacy_template_path = ! empty( $this->legacy_template ) ? $this->legacy_template : ''; if ( 0 === strpos( $template, DIRECTORY_SEPARATOR ) ) { // $value is an absolute path, but it must be validated first if ( ! $this->is_valid_template_filename( $template ) || ! @file_exists( $template ) ) { $display_name = esc_html( $template ); throw new \RuntimeException( esc_html( $display_name ) . ' is not a valid MVC template' ); } } else { $template = $this->find_template_abspath( $template, $legacy_template_path ); } return $template; } public function rasterize_object( ViewElement $element ) { return $element->rasterize(); } /** * @param $id * @param $type * @param $context * @return ViewElement */ public function start_element( $id, $type = null, $context = null ) { if ( $type == null ) { $type = 'element'; } $count = count( $this->queue ); $element = new ViewElement( $id, $type ); if ( $context != null ) { if ( ! is_array( $context ) ) { $context = [ 'object' => $context ]; } foreach ( $context as $context_name => $context_value ) { $element->set_context( $context_name, $context_value ); } } $this->queue[] = $element; if ( $count > 0 ) { $old_element = $this->queue[ $count - 1 ]; $content = ob_get_contents(); ob_clean(); $old_element->append( $content ); $old_element->append( $element ); } ob_start(); return $element; } public function end_element() { $content = ob_get_clean(); $element = array_pop( $this->queue ); if ( $content != null ) { $element->append( $content ); } return $element; } /** * Renders a sub-template for the view * * @param string $__template * @param array $__params * @param bool $__return Unused * @return NULL */ public function include_template( $__template, $__params = null, $__return = false ) { // Use underscores to prefix local variables to avoid conflicts wth template vars. if ( $__params === null ) { $__params = []; } // Existing templates copied from the NextGEN source will include these template paths; alias them for compatibility. if ( 'photocrati-nextgen_gallery_display#image/before' === $__template ) { $__template = 'GalleryDisplay/ImageBefore'; } elseif ( 'photocrati-nextgen_gallery_display#image/after' === $__template ) { $__template = 'GalleryDisplay/ImageAfter'; } elseif ( 'photocrati-nextgen_gallery_display#container/before' === $__template ) { $__template = 'GalleryDisplay/ContainerBefore'; } elseif ( 'photocrati-nextgen_gallery_display#container/after' === $__template ) { $__template = 'GalleryDisplay/ContainerAfter'; } elseif ( 'photocrati-nextgen_gallery_display#list/before' === $__template ) { $__template = 'GalleryDisplay/ListBefore'; } elseif ( 'photocrati-nextgen_gallery_display#list/after' === $__template ) { $__template = 'GalleryDisplay/ListAfter'; } $__params['template_origin'] = $this->template; $__target = $this->get_template_abspath( $__template ); $__origin_target = $this->get_template_abspath( $this->template ); $__image_before_target = $this->get_template_abspath( 'GalleryDisplay/ImageBefore' ); $__image_after_target = $this->get_template_abspath( 'GalleryDisplay/ImageAfter' ); if ( $__origin_target !== $__target ) { if ( $__target == $__image_before_target ) { $__image = isset( $__params['image'] ) ? $__params['image'] : null; $this->start_element( 'nextgen_gallery.image_panel', 'item', $__image ); } if ( $__target == $__image_after_target ) { $this->end_element(); } extract( $__params ); include $__target; if ( $__target == $__image_before_target ) { $__image = isset( $__params['image'] ) ? $__params['image'] : null; $this->start_element( 'nextgen_gallery.image', 'item', $__image ); } if ( $__target == $__image_after_target ) { $this->end_element(); } } return null; } /** * Gets the absolute path of an MVC template file * * @param string $template * @param string|false $module (optional) * @param string $legacy_template Non-POPE path coming from 'templates' in the plugin root. * @return string */ public function find_template_abspath( $template, $legacy_template = '' ) { $fs = Filesystem::get_instance(); // Legacy file overrides are stored in the form module_name#path. if ( ! empty( $legacy_template ) ) { list($legacy_template, $module) = $fs->parse_formatted_path( $legacy_template ); } // Append the '.php' suffix if necessary. if ( substr( $template, -strlen( '.php' ) ) !== '.php' ) { $template = $template . '.php'; } if ( substr( $legacy_template, -strlen( '.php' ) ) !== '.php' ) { $legacy_template = $legacy_template . '.php'; } // First check if the template is in the override dir. if ( ! empty( $module ) ) { $retval = $this->get_template_override_abspath( $module, $legacy_template ); } // $template is an absolute path to an existing file. if ( file_exists( $template ) ) { return $template; } // Use static:: here so this class can be extended by other plugins. if ( ! isset( $retval ) ) { $retval = path_join( static::$default_root_dir, 'templates' . DIRECTORY_SEPARATOR . $template ); } // In case this class has been extended we should use NGG provided templates if they aren't overridden. if ( ! file_exists( $retval ) ) { $retval = path_join( self::$default_root_dir, 'templates' . DIRECTORY_SEPARATOR . $template ); } if ( ! file_exists( $retval ) ) { throw new \RuntimeException( "{$retval} is not a valid MVC template" ); } return $retval; } /** * @param null|string $module_id * @return string */ public function get_template_override_dir( $module_id = null ) { $root = \trailingslashit( path_join( WP_CONTENT_DIR, 'ngg' ) ); if ( ! @file_exists( $root ) && is_writable( \trailingslashit( WP_CONTENT_DIR ) ) ) { \wp_mkdir_p( $root ); } $modules = \trailingslashit( path_join( $root, 'modules' ) ); if ( ! @file_exists( $modules ) && is_writable( $root ) ) { \wp_mkdir_p( $modules ); } if ( $module_id ) { $module_dir = \trailingslashit( path_join( $modules, $module_id ) ); if ( ! @file_exists( $module_dir ) && is_writable( $modules ) ) { \wp_mkdir_p( $module_dir ); } $template_dir = \trailingslashit( \path_join( $module_dir, 'templates' ) ); if ( ! @file_exists( $template_dir ) && is_writable( $module_dir ) ) { \wp_mkdir_p( $template_dir ); } return $template_dir; } return $modules; } /** * @param $module * @param $filename * @return string|null */ public function get_template_override_abspath( $module, $filename ) { $abspath = FileSystem::get_instance()->join_paths( $this->get_template_override_dir( $module ), $filename ); if ( @file_exists( $abspath ) ) { return $abspath; } return null; } /** * Renders the view (template) * * @param bool $return (optional) * @return string|NULL */ public function render( $return = false ) { $content = $this->rasterize_object( $this->render_object() ); if ( ! $return ) { echo $content; } return $content; } /** * @return ViewElement */ public function render_object() { // Use underscores to prefix local variables to avoid conflicts with template vars. $__element = $this->start_element( $this->template, 'template' ); $template_vars = $this->get_template_vars(); extract( $template_vars ); include $this->get_template_abspath(); $this->end_element(); if ( ( $displayed_gallery = $this->get_param( 'displayed_gallery' ) ) && $this->get_param( 'display_type_rendering' ) ) { $triggers = TriggerManager::get_instance(); $triggers->render( $__element, $displayed_gallery ); // Allow 'trigger icons' and albums' breadcrumbs and thumbnails to inject themselves. $__element = \apply_filters( 'ngg_display_type_rendering_object', $__element, $this->get_param( 'displayed_gallery' ) ); } return $__element; } /** * Adds a template parameter * * @param $key * @param $value */ public function set_param( $key, $value ) { $this->params[ $key ] = $value; } /** * Removes a template parameter * * @param $key */ public function remove_param( $key ) { unset( $this->params[ $key ] ); } /** * Gets the value of a template parameter * * @param $key * @param null $default * @return mixed */ public function get_param( $key, $default = null ) { if ( isset( $this->params[ $key ] ) ) { return $this->params[ $key ]; } else { return $default; } } } ���Settings/GlobalSettings.php�������������������������������������������������������������������������0000644�����������������00000001465�15021223045�0011776 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Settings; use Imagely\NGG\Util\Serializable; class GlobalSettings extends ManagerBase { public static $_instance = null; /** * @return GlobalSettings */ public static function get_instance() { if ( \is_null( self::$_instance ) ) { self::$_instance = new GlobalSettings(); } return self::$_instance; } public function save() { return \update_site_option( self::$option_name, $this->to_array() ); } public function load() { $this->_options = \get_site_option( self::$option_name, $this->to_array() ); if ( ! $this->_options ) { $this->_options = []; } elseif ( \is_string( $this->_options ) ) { $this->_options = Serializable::unserialize( $this->_options ); } } public function destroy() { return \delete_site_option( self::$option_name ); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Settings/ManagerBase.php����������������������������������������������������������������������������0000644�����������������00000011433�15021223045�0011216 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Settings; abstract class ManagerBase implements \ArrayAccess { protected static $option_name = 'ngg_options'; protected $_options = []; protected $_defaults = []; protected $_option_handlers = []; abstract public function save(); abstract public function destroy(); abstract public function load(); protected function __construct() { $this->load(); } /** * Adds a class to handle dynamic options * * @param string $klass * @param array $options */ public function add_option_handler( $klass, $options = [] ) { if ( ! is_array( $options ) ) { $options = [ $options ]; } foreach ( $options as $option_name ) { $this->_option_handlers[ $option_name ] = $klass; } } /** * Gets a handler used to provide a dynamic option * * @param string $option_name * @return null|mixed */ protected function _get_option_handler( $option_name, $method = 'get' ) { $retval = null; if ( isset( $this->_option_handlers[ $option_name ] ) ) { if ( ! is_object( $this->_option_handlers[ $option_name ] ) ) { $klass = $this->_option_handlers[ $option_name ]; $this->_option_handlers[ $option_name ] = new $klass(); } $retval = $this->_option_handlers[ $option_name ]; if ( ! method_exists( $retval, $method ) ) { $retval = null; } } return $retval; } /** * Gets the value of a particular setting * * @param $key * @param null $default * @return mixed */ public function get( $key, $default = null ) { $retval = $default; if ( ( $handler = $this->_get_option_handler( $key, 'get' ) ) ) { $retval = $handler->get( $key, $default ); } elseif ( isset( $this->_options[ $key ] ) ) { $retval = $this->_options[ $key ]; } // In case a stdObject has been passed in as a value, we want to only return scalar values or arrays. if ( is_object( $retval ) ) { $retval = (array) $retval; } return $retval; } /** * Sets a setting to a particular value * * @param string $key * @param mixed $value * @return mixed */ public function set( $key, $value = null, $skip_handlers = false ) { if ( is_object( $value ) ) { $value = (array) $value; } if ( is_array( $key ) ) { foreach ( $key as $k => $v ) { $this->set( $k, $v ); } } elseif ( ! $skip_handlers && ( $handler = $this->_get_option_handler( $key, 'set' ) ) ) { $handler->set( $key, $value ); } else { $this->_options[ $key ] = $value; } return $this; } /** * Deletes a setting * * @param string $key */ public function delete( $key ) { if ( ( $handler = $this->_get_option_handler( $key, 'delete' ) ) ) { $handler->delete( $key ); } else { unset( $this->_options[ $key ] ); } } /** * Determines if a setting exists or not * * @param $key * @return bool */ public function is_set( $key ) { return array_key_exists( $key, $this->_options ); } /** * Alias to is_set() * * @param $key * @return bool */ public function exists( $key ) { return $this->is_set( $key ); } public function does_not_exist( $key ) { return ! $this->exists( $key ); } public function reset() { $this->_options = []; $this->_defaults = []; } /** * This function does two things: * a) If a value hasn't been set for the specified key, or it's been set to a previously set * default value, then set this key to the value specified * b) Sets a new default value for this key */ public function set_default_value( $key, $default ) { if ( ! isset( $this->_defaults[ $key ] ) ) { $this->_defaults[ $key ] = $default; } if ( is_null( $this->get( $key, null ) ) or $this->get( $key ) == $this->_defaults[ $key ] ) { $this->set( $key, $default ); } $this->_defaults[ $key ] = $default; return $this->get( $key ); } #[\ReturnTypeWillChange] public function offsetExists( $key ) { return $this->is_set( $key ); } #[\ReturnTypeWillChange] public function offsetGet( $key ) { return $this->get( $key ); } #[\ReturnTypeWillChange] public function offsetSet( $key, $value ) { return $this->set( $key, $value ); } #[\ReturnTypeWillChange] public function offsetUnset( $key ) { $this->delete( $key ); } public function __get( $key ) { return $this->get( $key ); } public function __set( $key, $value ) { return $this->set( $key, $value ); } public function __isset( $key ) { return $this->is_set( $key ); } public function __toString() { return json_encode( $this->_options ); } public function __toArray() { ksort( $this->_options ); return $this->_options; } public function to_array() { return $this->__toArray(); } public function to_json() { return json_encode( $this->_options ); } public function from_json( $json ) { $this->_options = (array) json_decode( $json ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Settings/Installer.php������������������������������������������������������������������������������0000644�����������������00000021304�15021223045�0011004 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Settings; class Installer { private $global_settings = []; private $local_settings = []; public $blog_settings = null; public $site_settings = null; public function __construct() { $existing_options = \get_option( 'ngg_options', [] ); $this->blog_settings = Settings::get_instance(); $this->site_settings = GlobalSettings::get_instance(); $this->global_settings = \apply_filters( 'ngg_default_global_settings', [ 'gallerypath' => implode( DIRECTORY_SEPARATOR, [ 'wp-content', 'uploads', 'sites', '%BLOG_ID%', 'nggallery' ] ) . DIRECTORY_SEPARATOR, 'wpmuRoles' => false, 'wpmuImportFolder' => false, 'wpmuZipUpload' => false, 'wpmuQuotaCheck' => false, 'maximum_entity_count' => 500, 'router_param_slug' => 'nggallery', ] ); $this->local_settings = \apply_filters( 'ngg_default_settings', [ 'gallerypath' => 'wp-content' . DIRECTORY_SEPARATOR . 'gallery' . DIRECTORY_SEPARATOR, 'deleteImg' => true, // delete Images. 'usePermalinks' => false, // use permalinks for parameters. 'permalinkSlug' => 'nggallery', // the default slug for permalinks. 'graphicLibrary' => 'gd', // default graphic library. 'useMediaRSS' => false, // activate the global Media RSS file. 'galleries_in_feeds' => false, // enables rendered gallery output in RSS & Atom feeds. // Tags / categories. 'activateTags' => 0, // append related images. 'appendType' => 'tags', // look for category or tags. 'maxImages' => 7, // number of images to show. 'relatedHeading' => '<h3>' . \__( 'Related Images', 'nggallery' ) . ':</h3>', // subheading for related images. // Thumbnail Settings. 'thumbwidth' => 240, // Thumb Width. 'thumbheight' => 160, // Thumb height. 'thumbfix' => true, // Fix the dimension. 'thumbquality' => 100, // Thumb Quality. // Image Settings. 'imgWidth' => 1800, // Image Width. 'imgHeight' => 1200, // Image height. 'imgQuality' => 100, // Image Quality. 'imgBackup' => true, // Create a backup. 'imgAutoResize' => true, // Resize after upload. // Gallery Settings. 'galImages' => '24', // Number of images per page. 'galPagedGalleries' => 0, // Number of galleries per page (in a album). 'galColumns' => 0, // Number of columns for the gallery. 'galShowSlide' => false, // Show slideshow. 'galTextSlide' => \__( 'View Slideshow', 'nggallery' ), // Text for slideshow. 'galTextGallery' => \__( 'View Thumbnails', 'nggallery' ), // Text for gallery. 'galShowOrder' => 'gallery', // Show order. 'galSort' => 'sortorder', // Sort order. 'galSortDir' => 'ASC', // Sort direction. 'galNoPages' => true, // use no subpages for gallery. 'galImgBrowser' => 0, // Thumbnails feature: show ImageBrowser in place of lightbox. 'galHiddenImg' => 0, // For paged galleries we can hide image. 'galAjaxNav' => 1, // Thumbnails feature: use ajax pagination. // Thumbnail Effect. 'thumbEffect' => 'simplelightbox', 'thumbCode' => 'class="ngg-simplelightbox" rel="%GALLERY_NAME%"', 'thumbEffectContext' => 'nextgen_images', // Watermark settings. 'watermark_automatically_at_upload' => 0, 'wmPos' => 'midCenter', // Position. 'wmXpos' => 15, // X Pos. 'wmYpos' => 5, // Y Pos. 'wmType' => 'text', // Type : 'image' / 'text'. 'wmPath' => '', // Path to image. 'wmFont' => 'arial.ttf', // Font type. 'wmSize' => 30, // Font Size. 'wmText' => \get_option( 'blogname' ), // Text. 'wmColor' => 'ffffff', // Font Color. 'wmOpaque' => '33', // Font Opaque. // Image Rotator settings. 'slideFX' => 'fade', 'irWidth' => 750, 'irHeight' => 500, 'irRotatetime' => 5, // Misc. 'dynamic_image_filename_separator_use_dash' => ! isset( $existing_options['gallerypath'] ), // It is known that WPEngine disables 'order by rand()' by default, but exposes it as an option to users. 'use_alternate_random_method' => ( function_exists( 'is_wpe' ) && \is_wpe() ), // Prevent conflicts with other plugins that enqueue fontawesome. 'disable_fontawesome' => false, // Prevent the /ngg_tag/ page from being enabled. 'disable_ngg_tags_page' => false, // Duration of caching of 'random' widgets image IDs. 'random_widget_cache_ttl' => 30, // Path for the dynamic thumbnails' generator/controller. 'dynamic_thumbnail_slug' => 'nextgen-image', // Path for the dynamic stylesheets controller. 'dynamic_stylesheet_slug' => 'nextgen-dcss', // Router internal configuration. 'router_param_separator' => '--', 'router_param_prefix' => '', 'router_param_slug' => 'nggallery', // Legacy POPE compatibility & former option handlers. 'frame_event_cookie_name' => 'X-Frame-Events', 'mvc_template_dir' => '/templates', 'mvc_template_dirname' => '/templates', 'mvc_static_dirname' => '/static', 'mvc_static_dir' => '/static', 'jquery_ui_theme' => 'jquery-ui-nextgen', 'jquery_ui_theme_version' => '1.8', ] ); if ( \is_multisite() ) { if ( $options = \get_site_option( 'ngg_options' ) ) { $gallerypath = $options['gallerypath']; } else { $gallerypath = $this->global_settings['gallerypath']; } $this->local_settings['gallerypath'] = $this->gallerypath_replace( $gallerypath ); } } public function install_global_settings( $reset = false ) { foreach ( $this->global_settings as $key => $value ) { if ( $reset ) { $this->site_settings->set( $key, null ); } $this->site_settings->set_default_value( $key, $value ); } } public function install_local_settings( $reset = false ) { foreach ( $this->local_settings as $key => $value ) { if ( $reset ) { $this->blog_settings->set( $key, null ); } $this->blog_settings->set_default_value( $key, $value ); } if ( is_multisite() ) { // If this is already network activated we just need to use the existing setting // Note: attempting to use Imagely\NGG\Settings\GlobalSettings here may result in an infinite loop, // so get_site_option() is used to check. if ( $options = \get_site_option( 'ngg_options' ) ) { $gallerypath = $options['gallerypath']; } else { $gallerypath = $this->global_settings['gallerypath']; } $gallerypath = $this->gallerypath_replace( $gallerypath ); // a gallerypath setting has already been set, so we explicitly set a default AND set a new value. $this->blog_settings->set_default_value( 'gallerypath', $gallerypath ); if ( $reset ) { $this->blog_settings->set( 'gallerypath', $gallerypath ); } } } public function install( $reset = false ) { $this->install_global_settings( $reset ); $this->install_local_settings( $reset ); } public function get_global_defaults() { return $this->global_settings; } public function get_local_defaults() { return $this->local_settings; } public function gallerypath_replace( $gallerypath ) { $gallerypath = str_replace( '%BLOG_NAME%', \get_bloginfo( 'name' ), $gallerypath ); $gallerypath = str_replace( '%BLOG_ID%', \get_current_blog_id(), $gallerypath ); $gallerypath = str_replace( '%SITE_ID%', \get_current_blog_id(), $gallerypath ); return $gallerypath; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Settings/Settings.php�������������������������������������������������������������������������������0000644�����������������00000002530�15021223045�0010647 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Settings; use Imagely\NGG\Util\Serializable; class Settings extends ManagerBase { protected static $instance = null; /** * @return Settings */ public static function get_instance() { if ( is_null( self::$instance ) ) { self::$instance = new Settings(); // This setting must be an option handler as it cannot be static. self::$instance->add_option_handler( '\Imagely\NGG\Settings\Ajax_URL_Option_Handler', [ 'ajax_url' ] ); } return self::$instance; } public function save() { return \update_option( self::$option_name, $this->to_array() ); } public function load() { $this->_options = \get_option( self::$option_name, [] ); if ( ! $this->_options ) { $this->_options = []; } elseif ( is_string( $this->_options ) ) { try { $this->_options = Serializable::unserialize( $this->_options ); } catch ( \Exception $exception ) { $this->_options = []; } } } public function destroy() { \delete_option( self::$option_name ); } } class Ajax_URL_Option_Handler { public function get( $key, $default = null ) { $retval = $default; if ( $key == 'ajax_url' ) { $retval = site_url( '/index.php?' . NGG_AJAX_SLUG . '=1' ); if ( is_ssl() && strpos( $retval, 'https' ) === false ) { $retval = str_replace( 'http', 'https', $retval ); } } return $retval; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������DynamicStylesheets/Controller.php�������������������������������������������������������������������0000644�����������������00000003374�15021223045�0013222 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DynamicStylesheets; use Imagely\NGG\Display\View; use Imagely\NGG\Util\Sanitization; class Controller { public function index_action( $return = false ) { header( 'Content-Type: text/css; charset=' . get_option( 'blog_charset' ), true ); if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $manager = Manager::get_instance( 'all' ); $manager->register( 'nextgen_pro_film', 'photocrati-nextgen_pro_film#nextgen_pro_film_dyncss' ); $manager->register( 'nextgen_pro_grid_album', 'photocrati-nextgen_pro_albums#nextgen_pro_grid_album_dyncss' ); $manager->register( 'nextgen_pro_list_album', 'photocrati-nextgen_pro_albums#nextgen_pro_list_album_dyncss' ); $manager->register( 'nextgen_pro_blog', 'photocrati-nextgen_pro_blog_gallery#nextgen_pro_blog_dyncss' ); $manager->register( 'nextgen_pro_thumbnail_grid', 'photocrati-nextgen_pro_thumbnail_grid#nextgen_pro_thumbnail_grid_dyncss' ); } // Nonce verification is not necessary: this is not form data, but generated by NextGEN as part of its displayed // gallery customization for style. // // phpcs:disable WordPress.Security.NonceVerification.Recommended $data = Sanitization::recursive_stripslashes( $_REQUEST['data'] ); $name = Sanitization::recursive_stripslashes( $_REQUEST['name'] ); // phpcs:enable WordPress.Security.NonceVerification.Recommended if ( isset( $data ) && isset( $name ) ) { $manager = Manager::get_instance( 'all' ); if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $view = new \C_MVC_View( $manager->get_css_template( $name ), $manager->decode( $data ) ); } else { $view = new View( $manager->get_css_template( $name ), $manager->decode( $data ) ); } return $view->render( $return ); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DynamicStylesheets/Manager.php����������������������������������������������������������������������0000644�����������������00000005201�15021223045�0012440 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DynamicStylesheets; use Imagely\NGG\Display\View; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Settings\Settings; class Manager { protected static $_instances = []; /** * @var array<string> */ protected $templates = []; public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new Manager(); } return self::$_instances[ $context ]; } /** * Registers a template with the dynamic stylesheet utility. A template must be registered before it can be loaded. * * @param string $name * @param string $template */ public function register( $name, $template ) { $this->templates[ $name ] = $template; } public function get_css_template( $name ) { return $this->templates[ $name ]; } /** * Loads a template, along with the dynamic variables to be interpolated. * * @param string $name * @param array $data (optional) */ public function enqueue( $name, $data = [] ) { if ( ( $template_name = $this->get_css_template( $name ) ) !== false ) { if ( is_subclass_of( $data, 'C_DataMapper_Model' ) ) { $data = $data->get_entity(); } if ( defined( 'NGG_INLINE_DYNAMIC_CSS' ) && NGG_INLINE_DYNAMIC_CSS ) { $view = new View( $template_name, $data ); $css = $view->render( true ); \wp_enqueue_style( 'ngg_dyncss', StaticAssets::get_url( 'Display/DynamicStylesheets.css' ), [], NGG_SCRIPT_VERSION ); wp_add_inline_style( 'ngg_dyncss', $css ); } else { // Prevent albums with many children from creating GET URL that exceed the RFC limits. if ( isset( $data->original_album_entities ) ) { unset( $data->original_album_entities ); } $slug = Settings::get_instance()->get( 'dynamic_stylesheet_slug' ); $encoded_data = $this->encode( $data ); \wp_enqueue_style( 'dyncss-' . $template_name . $encoded_data . '@dynamic', "/{$slug}" . "?name={$name}&data={$encoded_data}", [], NGG_SCRIPT_VERSION ); } } } /** * Encodes $data * * Base64 encoding uses '==' to denote the end of the sequence, but keep it out of the url * * @param $data * @return string */ public function encode( $data ) { $data = json_encode( $data ); $data = base64_encode( $data ); $data = str_replace( '/', '\\', $data ); $data = rtrim( $data, '=' ); return $data; } /** * Decodes $data * * @param $data * @return array|mixed */ public function decode( $data ) { $data = str_replace( '\\', '/', $data ); $data = base64_decode( $data . '==' ); $data = json_decode( $data ); return $data; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayTypes/Thumbnails.php�������������������������������������������������������������������������0000644�����������������00000027133�15021223045�0012015 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DisplayType\Controller as ParentController; use Imagely\NGG\DynamicThumbnails\Manager as ThumbnailsManager; use Imagely\NGG\DataTypes\DisplayedGallery; use Imagely\NGG\Display\{StaticAssets, View}; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Router; class Thumbnails extends ParentController { /** * @param DisplayedGallery $displayed_gallery * @return DisplayedGallery */ public function get_alternative_displayed_gallery( $displayed_gallery ) { // Prevent recursive checks for further alternates causing additional modifications to the settings array. $id = $displayed_gallery->id(); if ( ! empty( self::$alternate_displayed_galleries[ $id ] ) ) { return self::$alternate_displayed_galleries[ $id ]; } $router = Router::get_instance(); $show = $router->get_parameter( 'show' ); $pid = $router->get_parameter( 'pid' ); if ( ! empty( $pid ) && isset( $displayed_gallery->display_settings['use_imagebrowser_effect'] ) && intval( $displayed_gallery->display_settings['use_imagebrowser_effect'] ) ) { $show = NGG_BASIC_IMAGEBROWSER; } // Are we to display a different display type? if ( ! empty( $show ) && $show !== NGG_BASIC_THUMBNAILS ) { $params = (array) $displayed_gallery->get_entity(); unset( $params['id'] ); unset( $params['ID'] ); $ds = $params['display_settings']; if ( ( ! empty( $ds['show_slideshow_link'] ) || ! empty( $ds['show_thumbnail_link'] ) || ! empty( $ds['use_imagebrowser_effect'] ) ) ) { return $this->set_alternative_displayed_gallery( $params, $displayed_gallery, $show ); } } return $displayed_gallery; } /** * @param DisplayedGallery $displayed_gallery * @param bool $return (optional) * @return string */ public function index_action( $displayed_gallery, $return = false ) { $router = Router::get_instance(); $storage = StorageManager::get_instance(); $dynthumbs = ThumbnailsManager::get_instance(); $display_settings = $displayed_gallery->display_settings; $gallery_id = $displayed_gallery->id(); if ( ! $display_settings['disable_pagination'] ) { $current_page = (int) $router->get_parameter( 'nggpage', $gallery_id, 1 ); } else { $current_page = 1; } $offset = $display_settings['images_per_page'] * ( $current_page - 1 ); $total = $displayed_gallery->get_entity_count(); // Get the images to be displayed. if ( $display_settings['images_per_page'] > 0 && $display_settings['show_all_in_lightbox'] ) { // the "Add Hidden Images" feature works by loading ALL images and then marking the ones not on this page // as hidden (style="display: none"). $images = $displayed_gallery->get_included_entities(); $i = 0; foreach ( $images as &$image ) { if ( $i < $display_settings['images_per_page'] * ( $current_page - 1 ) ) { $image->hidden = true; } elseif ( $i >= $display_settings['images_per_page'] * ( $current_page ) ) { $image->hidden = true; } ++$i; } } else { // just display the images for this page, as normal. $images = $displayed_gallery->get_included_entities( $display_settings['images_per_page'], $offset ); } // Are there images to display?. if ( $images ) { // Create pagination. if ( $display_settings['images_per_page'] && ! $display_settings['disable_pagination'] ) { $pagination_result = $this->create_pagination( $current_page, $total, $display_settings['images_per_page'], urldecode( $router->get_parameter( 'ajax_pagination_referrer' ) ?: '' ) ); $app = $router->get_routed_app(); $app->remove_parameter( 'ajax_pagination_referrer' ); $pagination_prev = $pagination_result['prev']; $pagination_next = $pagination_result['next']; $pagination = $pagination_result['output']; } else { list($pagination_prev, $pagination_next, $pagination) = [ null, null, null ]; } $thumbnail_size_name = 'thumbnail'; if ( $display_settings['override_thumbnail_settings'] ) { if ( $dynthumbs != null ) { $dyn_params = [ 'width' => $display_settings['thumbnail_width'], 'height' => $display_settings['thumbnail_height'], ]; if ( $display_settings['thumbnail_quality'] ) { $dyn_params['quality'] = $display_settings['thumbnail_quality']; } if ( $display_settings['thumbnail_crop'] ) { $dyn_params['crop'] = true; } if ( $display_settings['thumbnail_watermark'] ) { $dyn_params['watermark'] = true; } $thumbnail_size_name = $dynthumbs->get_size_name( $dyn_params ); } } // Generate a slideshow link. $slideshow_link = ''; if ( $display_settings['show_slideshow_link'] ) { // origin_url is necessary for ajax operations. slideshow_link_origin will NOT always exist. $origin_url = $router->get_parameter( 'ajax_pagination_referrer' ); $slideshow_link = $this->get_url_for_alternate_display_type( $displayed_gallery, NGG_BASIC_SLIDESHOW, $origin_url ); } // This setting 1) points all images to an imagebrowser display & 2) disables the lightbox effect. if ( $display_settings['use_imagebrowser_effect'] ) { if ( ! empty( $displayed_gallery->display_settings['original_display_type'] ) && ! empty( $_SERVER['NGG_ORIG_REQUEST_URI'] ) ) { $origin_url = $_SERVER['NGG_ORIG_REQUEST_URI']; } $app = $router->get_routed_app(); $url = ( ! empty( $origin_url ) ? $origin_url : $app->get_routed_url() ); $url = $app->remove_parameter( $url, null, 'image' ); $url = $this->set_param_for( $url, 'image', '%STUB%' ); $effect_code = "class='use_imagebrowser_effect' data-imagebrowser-url='{$url}'"; } else { $effect_code = $this->get_effect_code( $displayed_gallery ); } // The render functions require different processing. if ( ! empty( $display_settings['template'] ) && $display_settings['template'] != 'default' ) { $params = $this->prepare_legacy_parameters( $images, $displayed_gallery, [ 'next' => ( empty( $pagination_next ) ) ? false : $pagination_next, 'prev' => ( empty( $pagination_prev ) ) ? false : $pagination_prev, 'pagination' => $pagination, 'slideshow_link' => $slideshow_link, 'effect_code' => $effect_code, ] ); return $this->legacy_render( $display_settings['template'], $params, $return, 'gallery' ); } else { $params = $display_settings; // Additional values for the carousel display view. if ( ! empty( $router->get_parameter( 'pid' ) ) ) { foreach ( $images as $img ) { if ( $img->image_slug === $router->get_parameter( 'pid' ) ) { $params['current_image'] = $img; } } if ( isset( $pagination_result ) ) { $params['pagination_prev'] = $pagination_result['prev']; $params['pagination_next'] = $pagination_result['next']; } } if ( empty( $params['current_image'] ) ) { $params['current_image'] = reset( $images ); } $params['storage'] = $storage; $params['images'] = $images; $params['displayed_gallery_id'] = $gallery_id; $params['current_page'] = $current_page; $params['effect_code'] = $effect_code; $params['pagination'] = $pagination; $params['thumbnail_size_name'] = $thumbnail_size_name; $params['slideshow_link'] = $slideshow_link; $params = $this->prepare_display_parameters( $displayed_gallery, $params ); $view = new View( 'Thumbnails/index', $params, 'photocrati-nextgen_basic_gallery#thumbnails/index' ); return $view->render( $return ); } } elseif ( $display_settings['display_no_images_error'] ) { $view = new View( 'GalleryDisplay/NoImagesFound', [], 'photocrati-nextgen_gallery_display#no_images_found' ); return $view->render( $return ); } return ''; } /** * @param DisplayedGallery $displayed_gallery */ public function enqueue_frontend_resources( $displayed_gallery ) { parent::enqueue_frontend_resources( $displayed_gallery ); $this->enqueue_pagination_resources(); \wp_enqueue_style( 'nextgen_basic_thumbnails_style', StaticAssets::get_url( 'Thumbnails/nextgen_basic_thumbnails.css', 'photocrati-nextgen_basic_gallery#thumbnails/nextgen_basic_thumbnails.css' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_script( 'nextgen_basic_thumbnails_script', StaticAssets::get_url( 'Thumbnails/nextgen_basic_thumbnails.js', 'photocrati-nextgen_basic_gallery#thumbnails/nextgen_basic_thumbnails.js' ), [], NGG_SCRIPT_VERSION ); if ( $displayed_gallery->display_settings['ajax_pagination'] ) { \wp_enqueue_script( 'nextgen-basic-thumbnails-ajax-pagination', StaticAssets::get_url( 'Thumbnails/ajax_pagination.js', 'photocrati-nextgen_basic_gallery#thumbnails/ajax_pagination.js' ), [], NGG_SCRIPT_VERSION ); } } /** * Allows the above imagebrowser-url to return as image/23 instead of image--23 * * @param string $url * @param string $key * @param mixed $value * @param null|string $id * @param bool $use_prefix * @return string */ public function set_param_for( $url, $key, $value, $id = null, $use_prefix = false ) { $app = Router::get_instance()->get_routed_app(); $retval = $app->set_parameter( $key, $value, $id, $use_prefix, $url ); while ( preg_match( '#(image)--([^/]+)#', $retval, $matches ) ) { $retval = str_replace( $matches[0], $matches[1] . '/' . $matches[2], $retval ); } return $retval; } public function get_preview_image_url() { return StaticAssets::get_url( 'Thumbnails/thumb_preview.jpg' ); } public function get_default_settings() { $settings = Settings::get_instance(); $default_template = isset( $entity->settings['template'] ) ? 'default' : 'default-view.php'; return \apply_filters( 'ngg_thumbnails_default_settings', [ 'display_view' => $default_template, 'images_per_page' => $settings->get( 'galImages' ), 'number_of_columns' => $settings->get( 'galColumns' ), 'thumbnail_width' => $settings->get( 'thumbwidth' ), 'thumbnail_height' => $settings->get( 'thumbheight' ), 'show_all_in_lightbox' => $settings->get( 'galHiddenImg' ), 'ajax_pagination' => $settings->get( 'galAjaxNav' ), 'use_imagebrowser_effect' => $settings->get( 'galImgBrowser' ), 'template' => '', 'display_no_images_error' => 1, 'disable_pagination' => 0, // Alternative view support. 'show_slideshow_link' => $settings->get( 'galShowSlide' ) ? 1 : 0, 'slideshow_link_text' => $settings->get( 'galTextSlide' ), // override thumbnail settings. 'override_thumbnail_settings' => 0, 'thumbnail_quality' => '100', 'thumbnail_crop' => 1, 'thumbnail_watermark' => 0, // Part of the pro-modules. 'ngg_triggers_display' => 'never', ] ); } public function get_template_directory_name(): string { return 'Thumbnails'; } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_THUMBNAILS, [ 'title' => __( 'NextGEN Basic Thumbnails', 'nggallery' ), 'entity_types' => [ 'image' ], 'default_source' => 'galleries', 'view_order' => NGG_DISPLAY_PRIORITY_BASE, 'settings' => $this->get_default_settings(), 'aliases' => [ 'basic_thumbnail', 'basic_thumbnails', 'nextgen_basic_thumbnails', 'photocrati-nextgen_basic_thumbnails', ], ], $reset ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayTypes/SinglePicture.php����������������������������������������������������������������������0000644�����������������00000016733�15021223045�0012470 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DisplayType\Controller as ParentController; use Imagely\NGG\DynamicThumbnails\Manager as DynThumbs; use Imagely\NGG\DataTypes\DisplayedGallery; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\View; class SinglePicture extends ParentController { /** * @param DisplayedGallery $displayed_gallery * @param bool $return (optional) * @return string */ public function index_action( $displayed_gallery, $return = false ) { $storage = StorageManager::get_instance(); $dynthumbs = DynThumbs::get_instance(); $display_settings = $displayed_gallery->display_settings; // use this over get_included_entities() so we can display images marked 'excluded'. $displayed_gallery->skip_excluding_globally_excluded_images = true; $entities = $displayed_gallery->get_entities( 1, false, false, 'included' ); $image = array_shift( $entities ); if ( ! $image ) { $view = new View( 'GalleryDisplay/NoImagesFound', [], 'photocrati-nextgen_gallery_display#no_images_found' ); return $view->render( $return ); } switch ( $display_settings['float'] ) { case 'left': $display_settings['float'] = 'ngg-left'; break; case 'right': $display_settings['float'] = 'ngg-right'; break; case 'center': $display_settings['float'] = 'ngg-center'; break; default: $display_settings['float'] = ''; break; } $params = []; if ( ! empty( $display_settings['link'] ) ) { $target = $display_settings['link_target']; $effect_code = ''; } else { $display_settings['link'] = $storage->get_image_url( $image, 'full', true ); $target = '_self'; $effect_code = $this->get_effect_code( $displayed_gallery ); } $params['target'] = $target; // mode is a legacy parameter. if ( ! is_array( $display_settings['mode'] ) ) { $display_settings['mode'] = explode( ',', $display_settings['mode'] ); } if ( in_array( 'web20', $display_settings['mode'] ) ) { $display_settings['display_reflection'] = true; } if ( in_array( 'watermark', $display_settings['mode'] ) ) { $display_settings['display_watermark'] = true; } if ( isset( $display_settings['w'] ) ) { $display_settings['width'] = $display_settings['w']; } elseif ( isset( $display_settings['h'] ) ) { unset( $display_settings['width'] ); } if ( isset( $display_settings['h'] ) ) { $display_settings['height'] = $display_settings['h']; } elseif ( isset( $display_settings['w'] ) ) { unset( $display_settings['height'] ); } // legacy assumed no width/height meant full size unlike generate_thumbnail: force a full resolution. if ( ! isset( $display_settings['width'] ) && ! isset( $display_settings['height'] ) ) { $display_settings['width'] = $image->meta_data['width']; } if ( isset( $display_settings['width'] ) ) { $params['width'] = $display_settings['width']; } if ( isset( $display_settings['height'] ) ) { $params['height'] = $display_settings['height']; } $params['quality'] = $display_settings['quality']; $params['crop'] = $display_settings['crop']; $params['watermark'] = $display_settings['display_watermark']; $params['reflection'] = $display_settings['display_reflection']; $size = $dynthumbs->get_size_name( $params ); $thumbnail_url = $storage->get_image_url( $image, $size ); if ( ! empty( $display_settings['template'] ) && $display_settings['template'] != 'default' ) { $params = $this->prepare_legacy_parameters( [ $image ], $displayed_gallery, [ 'single_image' => true ] ); // the wrapper is a lazy-loader that calculates variables when requested. We here override those to always // return the same precalculated settings provided. $params['image']->container[0]->_cache_overrides['caption'] = $displayed_gallery->inner_content; $params['image']->container[0]->_cache_overrides['classname'] = 'ngg-singlepic ' . $display_settings['float']; $params['image']->container[0]->_cache_overrides['imageURL'] = $display_settings['link']; $params['image']->container[0]->_cache_overrides['thumbnailURL'] = $thumbnail_url; $params['target'] = $target; // if a link is present we temporarily must filter out the effect code. if ( empty( $effect_code ) ) { add_filter( 'ngg_get_thumbcode', [ $this, 'strip_thumbcode' ], 10 ); } $retval = $this->legacy_render( $display_settings['template'], $params, $return, 'singlepic' ); if ( empty( $effect_code ) ) { remove_filter( 'ngg_get_thumbcode', [ $this, 'strip_thumbcode' ], 10 ); } return $retval; } else { $params = $display_settings; $params['storage'] = &$storage; $params['image'] = &$image; $params['effect_code'] = $effect_code; $params['inner_content'] = $displayed_gallery->inner_content; $params['settings'] = $display_settings; $params['thumbnail_url'] = $thumbnail_url; $params['target'] = $target; $params = $this->prepare_display_parameters( $displayed_gallery, $params ); $view = new View( 'SinglePicture/nextgen_basic_singlepic', $params, 'photocrati-nextgen_basic_singlepic#nextgen_basic_singlepic' ); return $view->render( $return ); } } /** * The IGW popup requires substantial changes to include this display type. * * @return true */ public function is_hidden_from_igw() { return true; } /** * Intentionally disable the application of the effect code * * @param string $thumbcode Unused * @return string */ public function strip_thumbcode( $thumbcode ) { return ''; } /** * Enqueues all static resources required by this display type * * @param DisplayedGallery $displayed_gallery */ public function enqueue_frontend_resources( $displayed_gallery ) { parent::enqueue_frontend_resources( $displayed_gallery ); wp_enqueue_style( 'nextgen_basic_singlepic_style', StaticAssets::get_url( 'SinglePicture/nextgen_basic_singlepic.css', 'photocrati-nextgen_basic_singlepic#nextgen_basic_singlepic.css' ), [], NGG_SCRIPT_VERSION ); } public function get_preview_image_url() { return StaticAssets::get_url( 'SinglePicture/preview.gif' ); } public function get_template_directory_name(): string { return 'SinglePicture'; } public function get_default_settings() { return \apply_filters( 'ngg_single_picture_default_settings', [ 'crop' => 0, 'display_reflection' => 0, 'display_watermark' => 0, 'float' => '', 'height' => '', 'link' => '', 'mode' => '', 'quality' => 100, 'width' => '', 'link_target' => '_blank', 'template' => '', 'ngg_triggers_display', 'never', ] ); } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_SINGLEPIC, [ 'title' => __( 'NextGEN Basic SinglePic', 'nggallery' ), 'entity_types' => [ 'image' ], 'default_source' => 'galleries', 'view_order' => NGG_DISPLAY_PRIORITY_BASE + 60, 'hidden_from_ui' => true, // TODO remove this, use hidden_from_igw instead. 'hidden_from_igw' => true, 'aliases' => [ 'singlepic', 'singlepicture', 'basic_singlepic', 'nextgen_basic_singlepic', 'photocrati-nextgen_basic_singlepic', ], 'settings' => $this->get_default_settings(), ], $reset ); } } �������������������������������������DisplayTypes/ExtendedAlbum.php����������������������������������������������������������������������0000644�����������������00000004213�15021223045�0012422 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DisplayTypes\Albums\SharedController; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Settings\Settings; class ExtendedAlbum extends SharedController { public function __construct() { $this->legacy_template = 'photocrati-nextgen_basic_album#extended'; $this->template = 'ExtendedAlbum/extended'; } public function get_preview_image_url() { return StaticAssets::get_url( 'ExtendedAlbum/extended_preview.jpg' ); } public function get_default_settings() { $settings = Settings::get_instance(); $default_template = isset( $entity->settings['template'] ) ? 'default' : 'default-view.php'; return \apply_filters( 'ngg_extended_album_default_settings', [ 'disable_pagination' => 0, 'display_view' => $default_template, 'enable_breadcrumbs' => 1, 'enable_descriptions' => 0, 'galleries_per_page' => $settings->get( 'galPagedGalleries' ), 'gallery_display_template' => '', 'gallery_display_type' => NGG_BASIC_THUMBNAILS, 'ngg_triggers_display' => 'never', 'open_gallery_in_lightbox' => 0, 'override_thumbnail_settings' => 1, 'template' => '', 'thumbnail_crop' => 1, 'thumbnail_height' => 200, 'thumbnail_quality' => $settings->get( 'thumbquality' ), 'thumbnail_watermark' => 0, 'thumbnail_width' => 300, ] ); } public function get_template_directory_name(): string { return 'ExtendedAlbum'; } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_EXTENDED_ALBUM, [ 'title' => __( 'NextGEN Basic Extended Album', 'nggallery' ), 'entity_types' => [ 'album', 'gallery' ], 'default_source' => 'albums', 'view_order' => NGG_DISPLAY_PRIORITY_BASE + 210, 'aliases' => [ 'extended_album', 'basic_extended_album', 'nextgen_basic_extended_album', 'photocrati-nextgen_basic_extended_album', ], 'settings' => $this->get_default_settings(), ], $reset ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayTypes/Taxonomy.php���������������������������������������������������������������������������0000644�����������������00000007614�15021223045�0011527 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\DataStorage\Sanitizer; use Imagely\NGG\DisplayType\Controller as ParentController; class Taxonomy extends ParentController { public static $instance = null; protected $ngg_tag_detection_has_run = false; /** * @return Taxonomy */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new Taxonomy(); } return self::$instance; } public function render_tag( $tag ) { $mapper = DisplayTypeMapper::get_instance(); // Respect the global display type setting. $display_type = $mapper->find_by_name( NGG_BASIC_TAGCLOUD ); $display_type = ! empty( $display_type->settings['gallery_display_type'] ) ? $display_type->settings['gallery_display_type'] : NGG_BASIC_THUMBNAILS; return "[ngg source='tags' container_ids='{$tag}' slug='{$tag}' display_type='{$display_type}']"; } /** * Determines if the current page is /ngg_tag/{*} * * @param array $posts WordPress post objects * @param \WP_Query $wp_query_local * @return array WordPress post objects */ public function detect_ngg_tag( $posts, $wp_query_local ) { global $wp; global $wp_query; $wp_query_orig = false; if ( $wp_query_local !== null && $wp_query_local !== $wp_query ) { $wp_query_orig = $wp_query; $wp_query = $wp_query_local; } // This appears to be necessary for multisite installations, but I can't imagine why. More hackery.. $tag = \urldecode( \get_query_var( 'ngg_tag' ) ? \get_query_var( 'ngg_tag' ) : \get_query_var( 'name' ) ); $tag = \stripslashes( Sanitizer::strip_html( $tag ) ); // Tags may not include HTML. if ( ! $this->ngg_tag_detection_has_run // don't run more than once; necessary for certain themes. && ! \is_admin() // will destroy 'view all posts' page without this. && ! empty( $tag ) // only run when a tag has been given to WordPress. && is_string( $wp->request ) && ( stripos( $wp->request, 'ngg_tag' ) === 0 // make sure the query begins with /ngg_tag. || ( isset( $wp_query->query_vars['page_id'] ) && $wp_query->query_vars['page_id'] === 'ngg_tag' ) ) ) { $this->ngg_tag_detection_has_run = true; // WordPress somewhat-correctly generates several notices, so silence them as they're really unnecessary. if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) { error_reporting( 0 ); } // Without this all url generated from this page lacks the /ngg_tag/(slug) section of the URL. add_filter( 'ngg_wprouting_add_post_permalink', '__return_false' ); // create in-code a fake post; we feed it back to WordPress as the sole result of the "the_posts" filter. $posts = null; $posts[] = $this->create_ngg_tag_post( $tag ); $wp_query->is_404 = false; $wp_query->is_page = true; $wp_query->is_singular = true; $wp_query->is_home = false; $wp_query->is_archive = false; $wp_query->is_category = false; unset( $wp_query->query['error'] ); $wp_query->query_vars['error'] = ''; } if ( $wp_query_orig !== false ) { $wp_query = $wp_query_orig; } return $posts; } public function create_ngg_tag_post( $tag ) { $title = sprintf( __( 'Images tagged "%s"', 'nggallery' ), $tag ); $title = \apply_filters( 'ngg_basic_tagcloud_title', $title, $tag ); $post = new \stdClass(); $post->post_author = false; $post->post_name = 'ngg_tag'; $post->guid = \get_bloginfo( 'wpurl' ) . '/' . 'ngg_tag'; $post->post_title = $title; $post->post_content = $this->render_tag( $tag ); $post->ID = false; $post->post_type = 'page'; $post->post_status = 'publish'; $post->comment_status = 'closed'; $post->ping_status = 'closed'; $post->comment_count = 0; $post->post_date = current_time( 'mysql' ); $post->post_date_gmt = current_time( 'mysql', 1 ); return( $post ); } } ��������������������������������������������������������������������������������������������������������������������DisplayTypes/Albums/SharedController.php������������������������������������������������������������0000644�����������������00000103243�15021223045�0014401 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * SharedController is extended by other Album controllers and is responsible for all actual processing. * * @package NextGEN Gallery */ namespace Imagely\NGG\DisplayTypes\Albums; use Imagely\NGG\DataMappers\Album as AlbumMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DisplayType\Controller as ParentController; use Imagely\NGG\DynamicThumbnails\Manager as ThumbnailsManager; use Imagely\NGG\DataTypes\DisplayedGallery; use Imagely\NGG\Display\{DisplayManager, LightboxManager, View, ViewElement, StaticAssets}; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\Util\Router; /** * SharedController definition. */ class SharedController extends ParentController { /** * Cache of albums to be displayed. * * @var array */ public $albums = []; /** * Cache of alternate displayed galleries to render. * * @var array */ public static $alternate_displayed_galleries = []; /** * Cache of rendered HTML strings. * * @var array */ public $breadcrumb_cache = []; /** * Cache of album children from the database. * * @var array */ public $entities = []; /** * Path to a legacy template to use when rendering. * * @var string */ public $legacy_template = ''; /** * Path to the template to use when rendering. * * @var string */ public $template = ''; /** * Cache of settings to be used when rendering displayed galleries. * * @var array */ public static $display_settings = []; /** * When viewing a child gallery the album controller's add_description_to_legacy_templates() method will be * called for the gallery and then again for the root album; we only want to run once. * * @var bool Has the description HTML been added or not. */ public static $_description_added_once = false; /** * Adds rendered breadcrumbs and descriptions to a ViewElement. * * @param ViewElement $root_element A ViewElement object. * @param DisplayedGallery $displayed_gallery A DisplayedGallery object. * * @return ViewElement */ public function add_breadcrumbs_and_descriptions( ViewElement $root_element, DisplayedGallery $displayed_gallery ): ViewElement { $ds = $displayed_gallery->display_settings; // Enable album breadcrumbs. $original_entities = $this->get_original_album_entities( $ds ); if ( $this->are_breadcrumbs_enabled( $ds ) && ! empty( $original_entities ) ) { if ( ! empty( $ds['original_album_id'] ) ) { $ids = $ds['original_album_id']; } else { $ids = $displayed_gallery->container_ids; } $breadcrumbs = $this->generate_breadcrumb( $ids, $original_entities ); foreach ( $root_element->find( 'nextgen_gallery.gallery_container', true ) as $container ) { $container->insert( $breadcrumbs ); } } // Enable album descriptions. if ( $this->are_descriptions_enabled( $ds ) ) { $description = $this->generate_description( $displayed_gallery ); foreach ( $root_element->find( 'nextgen_gallery.gallery_container', true ) as $container ) { // Determine where (to be compatible with breadcrumbs) in the container to insert. $pos = 0; if ( ! empty( $container->_list ) ) { foreach ( $container->_list as $ndx => $item ) { if ( is_string( $item ) ) { $pos = $ndx; } else { break; } } } $container->insert( $description, $pos ); } } return $root_element; } /** * Prepends generated breadcrumb HTML to the $html parameter. * * @param string $html HTML string. * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return string */ public function add_breadcrumbs_to_legacy_templates( string $html, DisplayedGallery $displayed_gallery ): string { $original_album_entities = []; if ( isset( $displayed_gallery->display_settings['original_album_entities'] ) ) { $original_album_entities = $displayed_gallery->display_settings['original_album_entities']; } elseif ( isset( $displayed_gallery->display_settings['original_settings'] ) && isset( $displayed_gallery->display_settings['original_settings']['original_album_entities'] ) ) { $original_album_entities = $displayed_gallery->display_settings['original_settings']['original_album_entities']; } $breadcrumbs = $this->render_legacy_template_breadcrumbs( $displayed_gallery, $original_album_entities, $displayed_gallery->container_ids ); if ( ! empty( $breadcrumbs ) ) { return $breadcrumbs . $html; } else { return $html; } } /** * Prepends generated description HTML to the $html parameter. * * @param string $html HTML string. * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return string */ public function add_description_to_legacy_templates( string $html, DisplayedGallery $displayed_gallery ): string { $description = $this->render_legacy_template_description( $displayed_gallery ); if ( ! empty( $description ) ) { return $description . $html; } else { return $html; } } /** * Determines whether breadcrumbs are enabled. * * @param array $display_settings Array of display type settings. * * @return bool */ public function are_breadcrumbs_enabled( array $display_settings ): bool { if ( isset( $display_settings['enable_breadcrumbs'] ) && $display_settings['enable_breadcrumbs'] ) { return true; } elseif ( isset( $display_settings['original_settings'] ) && $this->are_breadcrumbs_enabled( $display_settings['original_settings'] ) ) { return true; } return false; } /** * Determines whether descriptions are enabled. * * @param array $display_settings Array of display type settings. * * @return bool */ public function are_descriptions_enabled( array $display_settings ): bool { if ( isset( $display_settings['enable_descriptions'] ) && $display_settings['enable_descriptions'] ) { return true; } elseif ( isset( $display_settings['original_settings'] ) && $this->are_descriptions_enabled( $display_settings['original_settings'] ) ) { return true; } return false; } /** * Enqueues the frontend resources needed for this displayed gallery. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. */ public function enqueue_frontend_resources( $displayed_gallery ) { // Necessary for breadcrumbs and URL routing. $renderer = Renderer::get_instance( 'inner' ); $renderer->do_app_rewrites( $displayed_gallery ); // This MUST come before the parent::enqueue_frontend_resources() so that this method can register an action // that will be triggered by the parent method. $this->prepare_display_settings( $displayed_gallery->get_entity(), $displayed_gallery->display_settings ); parent::enqueue_frontend_resources( $displayed_gallery ); $this->enqueue_pagination_resources(); \wp_enqueue_style( 'nextgen_basic_album_style', StaticAssets::get_url( 'Albums/nextgen_basic_album.css', 'photocrati-nextgen_basic_album#nextgen_basic_album.css' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_script( 'nextgen_basic_album_script', StaticAssets::get_url( 'Albums/init.js', 'photocrati-nextgen_basic_album#init.js' ), [], NGG_SCRIPT_VERSION, false ); \wp_enqueue_script( 'shave.js' ); $ds = $displayed_gallery->display_settings; if ( ( ! empty( $ds['enable_breadcrumbs'] ) ) || ( ! empty( $ds['original_settings']['enable_breadcrumbs'] ) ) ) { \wp_enqueue_style( 'nextgen_basic_album_breadcrumbs_style', StaticAssets::get_url( 'Albums/breadcrumbs.css', 'photocrati-nextgen_basic_album#breadcrumbs.css' ), [], NGG_SCRIPT_VERSION ); } } /** * Finds the parent album of a gallery. * * @param int $gallery_id Gallery ID. * @param array $sortorder Array of children belonging to an album. * * @return array */ public function find_gallery_parent( int $gallery_id, array $sortorder ): array { $map = AlbumMapper::get_instance(); $found = []; foreach ( $sortorder as $order ) { if ( strpos( $order, 'a' ) === 0 ) { $album_id = ltrim( $order, 'a' ); if ( empty( $this->breadcrumb_cache[ $order ] ) ) { $album = $map->find( $album_id ); $this->breadcrumb_cache[ $order ] = $album; // Using strict comparison here breaks the breadcrumb generation. //phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict if ( is_array( $album->sortorder ) && in_array( $gallery_id, $album->sortorder ) ) { $found[] = $album; break; } else { $found = $this->find_gallery_parent( (int) $gallery_id, $album->sortorder ); if ( $found ) { $found[] = $album; break; } } } } } return $found; } /** * Generates breadcrumb HTML. * * @param array|int $gallery_id Gallery ID. * @param array $entities Array of album children. * * @return string|null */ public function generate_breadcrumb( $gallery_id, array $entities ) { $found = []; $router = Router::get_instance(); $app = $router->get_routed_app(); if ( is_array( $gallery_id ) ) { $gallery_id = array_shift( $gallery_id ); } if ( is_array( $gallery_id ) ) { $gallery_id = $gallery_id[0]; } foreach ( $entities as $ndx => $entity ) { $tmpid = ( isset( $entity->albumdesc ) ? 'a' : '' ) . $entity->{$entity->id_field}; $this->breadcrumb_cache[ $tmpid ] = $entity; // Using strict comparison here breaks the breadcrumb generation. //phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict if ( isset( $entity->albumdesc ) && in_array( $gallery_id, $entity->sortorder ) ) { $found[] = $entity; break; } } if ( empty( $found ) ) { foreach ( $entities as $entity ) { if ( ! empty( $entity->sortorder ) ) { $found = $this->find_gallery_parent( (int) $gallery_id, $entity->sortorder ); } if ( ! empty( $found ) ) { $found[] = $entity; break; } } } $found = array_reverse( $found ); if ( strpos( $gallery_id, 'a' ) === 0 ) { $album_found = false; foreach ( $found as $found_item ) { if ( $found_item->{$found_item->id_field} === $gallery_id ) { $album_found = true; } } if ( ! $album_found ) { $album_id = ltrim( $gallery_id, 'a' ); $album = AlbumMapper::get_instance()->find( $album_id ); $found[] = $album; $this->breadcrumb_cache[ $gallery_id ] = $album; } } else { $gallery_found = false; foreach ( $entities as $entity ) { if ( isset( $entity->is_gallery ) && $entity->is_gallery && $gallery_id === $entity->{$entity->id_field} ) { $gallery_found = true; $found[] = $entity; break; } } if ( ! $gallery_found ) { $gallery = GalleryMapper::get_instance()->find( $gallery_id ); if ( null !== $gallery ) { $found[] = $gallery; $this->breadcrumb_cache[ $gallery->{$gallery->id_field} ] = $gallery; } } } $crumbs = []; if ( ! empty( $found ) ) { $end = end( $found ); reset( $found ); foreach ( $found as $ndx => $found_item ) { $type = isset( $found_item->albumdesc ) ? 'album' : 'gallery'; $id = ( 'album' === $type ? 'a' : '' ) . $found_item->{$found_item->id_field}; $entity = $this->breadcrumb_cache[ $id ]; $link = null; if ( 'album' === $type ) { $name = $entity->name; if ( $entity->pageid > 0 ) { $link = get_page_link( $entity->pageid ); } if ( empty( $link ) && $found_item !== $end ) { $link = $app->get_routed_url(); $link = $app->strip_param_segments( $link ); // Do not include the album in the URL when linking to the root element. if ( 0 !== $ndx ) { $link = $app->set_parameter_value( 'album', $entity->slug, null, false, $link ); } } } else { $name = $entity->title; } $crumbs[] = [ 'type' => $type, 'name' => $name, 'url' => $link, ]; } } // free this memory immediately. $this->breadcrumb_cache = []; $view = new View( 'Albums/breadcrumbs', [ 'breadcrumbs' => $crumbs, 'divisor' => apply_filters( 'ngg_breadcrumb_separator', ' » ' ), ], 'photocrati-nextgen_basic_album#breadcrumbs' ); return $view->render( true ); } /** * Generates description HTML. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return string|null */ public function generate_description( DisplayedGallery $displayed_gallery ) { if ( self::$_description_added_once ) { return ''; } self::$_description_added_once = true; $description = $this->get_description( $displayed_gallery ); $view = new View( 'Albums/descriptions', [ 'description' => $description, ], 'photocrati-nextgen_basic_album#descriptions' ); return $view->render( true ); } /** * Returns the correct DisplayedGallery to render under the current circumstances. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return DisplayedGallery */ public function get_alternate_displayed_gallery( DisplayedGallery $displayed_gallery ): DisplayedGallery { // Prevent recursive checks for further alternates causing additional modifications to the settings array. $id = $displayed_gallery->id(); if ( ! empty( self::$alternate_displayed_galleries[ $id ] ) ) { return self::$alternate_displayed_galleries[ $id ]; } $router = Router::get_instance(); // Without this line the param() method will always return NULL when in wp_enqueue_scripts. $renderer = Renderer::get_instance( 'inner' ); $renderer->do_app_rewrites( $displayed_gallery ); $display_settings = $displayed_gallery->display_settings; $gallery = $router->get_parameter( 'gallery' ); if ( $gallery && strpos( $gallery, 'nggpage--' ) !== 0 ) { $result = GalleryMapper::get_instance()->get_by_slug( $gallery ); if ( $result ) { $gallery = $result->{$result->id_field}; } $parent_albums = $displayed_gallery->get_albums(); $gallery_params = [ 'source' => 'galleries', 'container_ids' => [ $gallery ], 'display_type' => $display_settings['gallery_display_type'], 'original_display_type' => $displayed_gallery->display_type, 'original_settings' => $display_settings, 'original_album_entities' => $parent_albums, ]; if ( ! empty( $display_settings['gallery_display_template'] ) ) { $gallery_params['template'] = $display_settings['gallery_display_template']; } $displayed_gallery = $renderer->params_to_displayed_gallery( $gallery_params ); if ( is_null( $displayed_gallery->id() ) ) { $displayed_gallery->id( md5( wp_json_encode( $displayed_gallery->get_entity() ) ) ); } self::$alternate_displayed_galleries[ $id ] = $displayed_gallery; } return $displayed_gallery; } /** * Returns the current page as an integer. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * @return int */ public function get_current_page( DisplayedGallery $displayed_gallery ): int { $router = Router::get_instance(); return (int) $router->get_parameter( 'page', $displayed_gallery->id(), 1 ); } /** * Returns the album description string. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return string */ public function get_description( DisplayedGallery $displayed_gallery ): string { // Important: do not array_shift() $displayed_gallery->container_ids as it will affect breadcrumbs. $container_ids = $displayed_gallery->container_ids; if ( 'galleries' === $displayed_gallery->source ) { $gallery_id = array_shift( $container_ids ); $gallery = GalleryMapper::get_instance()->find( $gallery_id ); if ( $gallery && ! empty( $gallery->galdesc ) ) { return $gallery->galdesc; } } elseif ( 'albums' === $displayed_gallery->source ) { $album_id = array_shift( $container_ids ); $album = AlbumMapper::get_instance()->find( $album_id ); if ( $album && ! empty( $album->albumdesc ) ) { return $album->albumdesc; } } return ''; } /** * Get the entities belonging to the displayed gallery for the current page. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return array */ public function get_entities( DisplayedGallery $displayed_gallery ): array { $current_page = $this->get_current_page( $displayed_gallery ); $offset = $displayed_gallery->display_settings['galleries_per_page'] * ( $current_page - 1 ); return $displayed_gallery->get_included_entities( $displayed_gallery->display_settings['galleries_per_page'], $offset ); } /** * Returns the order that Album display types appear in the IGW selector. * * @return float */ public function get_order(): float { return NGG_DISPLAY_PRIORITY_BASE + NGG_DISPLAY_PRIORITY_STEP; } /** * Get the original children belonging to an album when viewing another child. * * @param array $display_settings Array of display type settings. * * @return array */ public function get_original_album_entities( array $display_settings ): array { if ( isset( $display_settings['original_album_entities'] ) ) { return $display_settings['original_album_entities']; } elseif ( isset( $display_settings['original_settings'] ) && $this->get_original_album_entities( $display_settings['original_settings'] ) ) { return $this->get_original_album_entities( $display_settings['original_settings'] ); } return []; } /** * Gets the parent album for the entity being displayed. * * @param int|string $entity_id Gallery ID. * @return null|object Album object. */ public function get_parent_album_for( $entity_id ) { $retval = null; foreach ( $this->albums as $album ) { // Using strict comparison here breaks the breadcrumb generation. //phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict if ( in_array( $entity_id, $album->sortorder ) ) { $retval = $album; break; } } return $retval; } /** * Renders the displayed gallery. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * @param bool $return Return or print the result. * * @return ?string */ public function index_action( $displayed_gallery, $return = false ) { $router = Router::get_instance(); // We need to fetch the selected album containers. We need to do this, because once we fetch the included // entities, we need to iterate over each entity and assign it a parent_id, which is the album that it belongs // to. We need to do this because the link to the gallery, is not /nggallery/gallery--id, // but /nggallery/album--id/gallery--id. // Are we to display a gallery? Ensure our 'gallery' isn't just a paginated album view. $gallery = $router->get_parameter( 'gallery' ); $album = $router->get_parameter( 'album' ); if ( $gallery && strpos( $gallery, 'nggpage--' ) !== 0 ) { // Basic albums only support one per post. if ( isset( $GLOBALS['nggShowGallery'] ) ) { return ''; } $GLOBALS['nggShowGallery'] = true; $alternate_displayed_gallery = $this->get_alternate_displayed_gallery( $displayed_gallery ); if ( $alternate_displayed_gallery !== $displayed_gallery ) { $renderer = Renderer::get_instance( 'inner' ); // For legacy templates we just generate the description & breadcrumb string and prepend it to the generated // display of the gallery. For modern templates we attach a filter to the display renderer just for this // one particular gallery, that seeks out the container element and injects the breadcrumbs there. \add_filter( 'ngg_displayed_gallery_rendering', [ $this, 'add_description_to_legacy_templates' ], 8, 2 ); \add_filter( 'ngg_displayed_gallery_rendering', [ $this, 'add_breadcrumbs_to_legacy_templates' ], 9, 2 ); \add_filter( 'ngg_display_type_rendering_object', [ $this, 'add_breadcrumbs_and_descriptions' ], 10, 2 ); $output = $renderer->display_images( $alternate_displayed_gallery, $return ); \remove_filter( 'ngg_display_type_rendering_object', [ $this, 'add_breadcrumbs_and_descriptions' ], 10 ); \remove_filter( 'ngg_displayed_gallery_rendering', [ $this, 'add_description_to_legacy_templates' ], 8 ); \remove_filter( 'ngg_displayed_gallery_rendering', [ $this, 'add_breadcrumbs_to_legacy_templates' ], 9 ); return $output; } } elseif ( ! is_null( $album ) ) { // If we're viewing a sub-album, then we use that album as a container instead. // Are we to display a sub-album? $result = AlbumMapper::get_instance()->get_by_slug( $album ); $album_sub = $result ? $result->{$result->id_field} : null; if ( null !== $album_sub ) { $album = $album_sub; } // Preserve the original album list before altering the DisplayedGallery. $original_albums = $displayed_gallery->get_albums(); if ( in_array( $album, $displayed_gallery->container_ids, false ) ) { $viewing_original_album = true; } $displayed_gallery->entity_ids = []; $displayed_gallery->sortorder = []; $displayed_gallery->container_ids = ( '0' === $album || 'all' === $album ) ? [] : [ $album ]; $displayed_gallery->display_settings['original_album_id'] = 'a' . $album_sub; $displayed_gallery->display_settings['original_album_entities'] = array_merge( $original_albums, $displayed_gallery->get_albums() ); } // Get the albums // TODO: This should probably be moved to the elseif block above. $this->albums = $displayed_gallery->get_albums(); // None of the above: Display the main album. Get the settings required for display. $entities = $this->get_entities( $displayed_gallery ); // If there are entities to be displayed. if ( $entities ) { $display_settings = $this->prepare_display_settings( $displayed_gallery->get_entity(), $displayed_gallery->display_settings ); if ( ! empty( $display_settings['template'] ) && 'default' !== $display_settings['template'] ) { // Add additional parameters. $router->get_routed_app()->remove_parameter( 'ajax_pagination_referrer' ); $display_settings['current_page'] = $this->get_current_page( $displayed_gallery ); $breadcrumbs = $this->render_legacy_template_breadcrumbs( $displayed_gallery, $entities ); $description = $this->render_legacy_template_description( $displayed_gallery ); // If enabled enqueue the child entities as JSON for lightboxes to read. $retval = $this->legacy_render( $display_settings['template'], $display_settings, $return, 'album' ); if ( ! empty( $description ) ) { $retval = $description . $retval; } if ( ! isset( $viewing_original_album ) && ! empty( $breadcrumbs ) ) { $retval = $breadcrumbs . $retval; } return $retval; } else { $params = $display_settings; $params = $this->prepare_display_parameters( $displayed_gallery, $params ); $view = new View( $this->template, $params, $this->legacy_template ); // Rather than messing with filters and return values, this method just directly calls add_breadcrumbs_and_descriptions(). $view_element = $view->render_object(); if ( ! isset( $viewing_original_album ) ) { $view_element = $this->add_breadcrumbs_and_descriptions( $view_element, $displayed_gallery ); } $content = $view->rasterize_object( $view_element ); if ( ! $return ) { // We cannot truly escape this content as it may come from user-supplied or 3rd party templates. echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } return $content; } } else { $view = new View( 'GalleryDisplay/NoImagesFound', [], 'photocrati-nextgen_gallery_display#no_images_found' ); return $view->render( $return ); } } /** * Determines whether the DisplayedGallery is a basic album. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return bool */ public function is_basic_album( DisplayedGallery $displayed_gallery ): bool { return in_array( $displayed_gallery->display_type, [ NGG_BASIC_COMPACT_ALBUM, NGG_BASIC_EXTENDED_ALBUM ], true ); } /** * Creates a displayed gallery of a gallery belonging to an album. Shared by index_action() and enqueue_frontend_resources() * to allow lightboxes to open album children directly. * * @param \stdClass $gallery Object. * @param array $display_settings An Array of display type settings. * * @return object */ public function make_child_displayed_gallery( \stdClass $gallery, array $display_settings ) { $gallery->displayed_gallery = new DisplayedGallery(); $gallery->displayed_gallery->container_ids = [ $gallery->{$gallery->id_field} ]; $gallery->displayed_gallery->display_settings = $display_settings; $gallery->displayed_gallery->returns = 'included'; $gallery->displayed_gallery->source = 'galleries'; $gallery->displayed_gallery->images_list_count = $gallery->displayed_gallery->get_entity_count(); $gallery->displayed_gallery->is_album_gallery = true; $gallery->displayed_gallery->to_transient(); $displayed_gallery = $gallery->displayed_gallery; // Add "galleries = {};". DisplayManager::add_script_data( 'ngg_common', 'galleries', new \stdClass(), true, false ); DisplayManager::add_script_data( 'ngg_common', 'galleries.gallery_' . $displayed_gallery->id(), (array) $displayed_gallery->get_entity(), false ); DisplayManager::add_script_data( 'ngg_common', 'galleries.gallery_' . $displayed_gallery->id() . '.wordpress_page_root', get_permalink(), false ); do_action( 'ngg_albums_enqueue_child_entity_data', $displayed_gallery ); return $gallery; } /** * Prepares the correct display settings to use for the current situation. Registers album children when necessary * for the "Open album children in lightbox" feature. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * @param array $params Array of display type settings. * * @return array */ public function prepare_display_settings( DisplayedGallery $displayed_gallery, array $params ): array { $image_gen = ThumbnailsManager::get_instance(); $image_mapper = ImageMapper::get_instance(); $router = Router::get_instance(); $storage = StorageManager::get_instance(); $app = $router->get_routed_app(); $pagination_result = $this->create_pagination( $this->get_current_page( $displayed_gallery ), $displayed_gallery->get_entity_count(), $params['galleries_per_page'], urldecode( $router->get_parameter( 'ajax_pagination_referrer' ) ?: '' ) ); $params['displayed_gallery'] = $displayed_gallery; $params['entities'] = $this->get_entities( $displayed_gallery ); $params['pagination'] = $pagination_result['output']; $params['pagination_next'] = $pagination_result['next']; $params['pagination_prev'] = $pagination_result['prev']; if ( empty( $displayed_gallery->display_settings['override_thumbnail_settings'] ) ) { // legacy templates expect these dimensions. $image_gen_params = [ 'width' => 91, 'height' => 68, 'crop' => true, ]; } else { // use settings requested by user. $image_gen_params = [ 'width' => $displayed_gallery->display_settings['thumbnail_width'], 'height' => $displayed_gallery->display_settings['thumbnail_height'], 'quality' => isset( $displayed_gallery->display_settings['thumbnail_quality'] ) ? $displayed_gallery->display_settings['thumbnail_quality'] : 100, 'crop' => isset( $displayed_gallery->display_settings['thumbnail_crop'] ) ? $displayed_gallery->display_settings['thumbnail_crop'] : null, 'watermark' => isset( $displayed_gallery->display_settings['thumbnail_watermark'] ) ? $displayed_gallery->display_settings['thumbnail_watermark'] : null, ]; } // so user templates can know how big the images are expected to be. $params['image_gen_params'] = $image_gen_params; // Transform entities. $params['galleries'] = $params['entities']; unset( $params['entities'] ); foreach ( $params['galleries'] as &$gallery ) { // Get the preview image url. $gallery->previewurl = ''; if ( $gallery->previewpic && $gallery->previewpic > 0 ) { $image = $image_mapper->find( intval( $gallery->previewpic ) ); if ( $image ) { $gallery->previewpic_image = $image; $gallery->previewpic_fullsized_url = $storage->get_image_url( $image ); $gallery->previewurl = $storage->get_image_url( $image, $image_gen->get_size_name( $image_gen_params ) ); $gallery->previewname = $gallery->name; } else { $gallery->no_previewpic = true; } } // Get the page link. If the entity is an album, then the url will // look like /nggallery/album--slug. $id_field = $gallery->id_field; if ( $gallery->is_album ) { if ( $gallery->pageid > 0 ) { $gallery->pagelink = get_page_link( $gallery->pageid ); } else { $pagelink = $app->get_routed_url( true ); $pagelink = $app->remove_parameter( 'album', null, $pagelink ); $pagelink = $app->remove_parameter( 'gallery', null, $pagelink ); $pagelink = $app->remove_parameter( 'nggpage', null, $pagelink ); $pagelink = $app->set_parameter( 'album', $gallery->slug, null, false, $pagelink ); $gallery->pagelink = $pagelink; } } else { // Otherwise, if it's a gallery then it will look like // /nggallery/album--slug/gallery--slug. if ( $gallery->pageid > 0 ) { $gallery->pagelink = get_page_link( $gallery->pageid ); } if ( empty( $gallery->pagelink ) ) { $pagelink = $app->get_routed_url(); $parent_album = $this->get_parent_album_for( $gallery->$id_field ); if ( $parent_album ) { $pagelink = $app->remove_parameter( 'album', null, $pagelink ); $pagelink = $app->remove_parameter( 'gallery', null, $pagelink ); $pagelink = $app->remove_parameter( 'nggpage', null, $pagelink ); $pagelink = $app->set_parameter( 'album', $parent_album->slug, null, false, $pagelink ); } elseif ( [ '0' ] === $displayed_gallery->container_ids || [ '' ] === $displayed_gallery->container_ids ) { // Legacy compat: use an album slug of 'all' if we're missing a container_id. $pagelink = $app->set_parameter( 'album', 'all', null, false, $pagelink ); } else { $pagelink = $app->remove_parameter( 'nggpage', null, $pagelink ); $pagelink = $app->remove_parameter( 'album', null, $pagelink ); $pagelink = $app->set_parameter( 'album', 'album', null, false, $pagelink ); } $gallery->pagelink = $app->set_parameter( 'gallery', $gallery->slug, null, false, $pagelink ); } } // Mark the child type. $gallery->entity_type = isset( $gallery->is_gallery ) && intval( $gallery->is_gallery ) ? 'gallery' : 'album'; // If this setting is on we need to inject an effect code. if ( ! empty( $displayed_gallery->display_settings['open_gallery_in_lightbox'] ) && 'gallery' === $gallery->entity_type ) { $gallery = $this->make_child_displayed_gallery( $gallery, $displayed_gallery->display_settings ); $lightbox = LightboxManager::get_instance()->get_selected(); if ( $lightbox->is_supported( $displayed_gallery ) ) { $gallery->displayed_gallery->effect_code = $this->get_effect_code( $gallery->displayed_gallery ); } } // Let plugins modify the gallery. $gallery = \apply_filters( 'ngg_album_galleryobject', $gallery ); } /* * Register each gallery belonging to the album that has just been rendered, so that when the MVC controller * system 'catches up' and runs $this->render_object() that method knows what galleries to inline as JS. */ if ( $this->is_basic_album( $displayed_gallery ) ) { $id = $displayed_gallery->ID(); foreach ( $params['galleries'] as &$gallery ) { if ( $gallery->is_album ) { continue; } $this->entities[ $id ][] = $gallery; } } $params['album'] = reset( $this->albums ); $params['albums'] = $this->albums; // Clean up. unset( $storage ); unset( $image_mapper ); unset( $image_gen ); unset( $image_gen_params ); self::$display_settings[ $displayed_gallery->id() ] = $params; return $params; } /** * Renders breadcrumb HTML for legacy templates. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * @param array $entities Array of album children. * @param ?int $gallery_id Gallery ID. * * @return string|null */ public function render_legacy_template_breadcrumbs( DisplayedGallery $displayed_gallery, array $entities, $gallery_id = false ) { $ds = $displayed_gallery->display_settings; if ( ! empty( $entities ) && ! empty( $ds['template'] ) && $this->are_breadcrumbs_enabled( $ds ) ) { if ( $gallery_id ) { if ( is_array( $gallery_id ) ) { $ids = $gallery_id; } else { $ids = [ $gallery_id ]; } } elseif ( ! empty( $ds['original_album_id'] ) ) { $ids = $ds['original_album_id']; } else { $ids = $displayed_gallery->container_ids; } if ( ! empty( $ds['original_album_entities'] ) ) { $breadcrumb_entities = $ds['original_album_entities']; } else { $breadcrumb_entities = $entities; } return $this->generate_breadcrumb( $ids, $breadcrumb_entities ); } else { return ''; } } /** * Renders description HTML for legacy templates. * * @param DisplayedGallery $displayed_gallery DisplayedGallery object. * * @return string|null */ public function render_legacy_template_description( DisplayedGallery $displayed_gallery ) { if ( ! empty( $displayed_gallery->display_settings['template'] ) && $this->are_descriptions_enabled( $displayed_gallery->display_settings ) ) { return $this->generate_description( $displayed_gallery ); } else { return ''; } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayTypes/TagCloud.php���������������������������������������������������������������������������0000644�����������������00000012715�15021223045�0011411 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DisplayType\Controller as ParentController; use Imagely\NGG\DataTypes\DisplayedGallery; use Imagely\NGG\Display\{StaticAssets, View}; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\Util\Router; class TagCloud extends ParentController { /** * @param DisplayedGallery $displayed_gallery * * @return DisplayedGallery */ public function get_alternative_displayed_gallery( $displayed_gallery ) { // Prevent recursive checks for further alternates causing additional modifications to the settings array. $id = $displayed_gallery->id(); if ( ! empty( self::$alternate_displayed_galleries[ $id ] ) ) { return self::$alternate_displayed_galleries[ $id ]; } $router = Router::get_instance(); $tag = \urldecode( $router->get_parameter( 'gallerytag', null, '' ) ); // The display setting 'display_type' has been removed to 'gallery_display_type'. $display_settings = $displayed_gallery->display_settings; if ( isset( $display_settings['display_type'] ) ) { $display_settings['gallery_display_type'] = $display_settings['display_type']; unset( $display_settings['display_type'] ); } // we're looking at a tag, so show images w/that tag as a thumbnail gallery. if ( ! \is_home() && ! empty( $tag ) ) { $params = [ 'source' => 'tags', 'container_ids' => [ esc_attr( $tag ) ], 'display_type' => $displayed_gallery->display_settings['gallery_display_type'], 'original_display_type' => $displayed_gallery->display_type, 'original_settings' => $displayed_gallery->display_settings, ]; $renderer = Renderer::get_instance(); $alternate_displayed_gallery = $renderer->params_to_displayed_gallery( $params ); if ( is_null( $alternate_displayed_gallery->id() ) ) { $alternate_displayed_gallery->id( md5( json_encode( $alternate_displayed_gallery->get_entity() ) ) ); } self::$alternate_displayed_galleries[ $id ] = $alternate_displayed_gallery; return $alternate_displayed_gallery; } return $displayed_gallery; } /** * @param DisplayedGallery $displayed_gallery * @param bool $return (optional) * * @return string */ public function index_action( $displayed_gallery, $return = false ) { $router = Router::get_instance(); // we're looking at a tag, so show images w/that tag as a thumbnail gallery. if ( ! \is_home() && ! empty( $router->get_parameter( 'gallerytag' ) ) ) { $displayed_gallery = $this->get_alternative_displayed_gallery( $displayed_gallery ); return Renderer::get_instance()->display_images( $displayed_gallery ); } $application = $router->get_routed_app(); $display_settings = $displayed_gallery->display_settings; $defaults = [ 'exclude' => '', 'format' => 'list', 'include' => $displayed_gallery->get_term_ids_for_tags(), 'largest' => 22, 'link' => 'view', 'number' => $display_settings['number'], 'order' => 'ASC', 'orderby' => 'name', 'smallest' => 8, 'taxonomy' => 'ngg_tag', 'unit' => 'pt', ]; $args = \wp_parse_args( '', $defaults ); // Always query top tags. $tags = \get_terms( $args['taxonomy'], array_merge( $args, [ 'orderby' => 'count', 'order' => 'DESC', ] ) ); foreach ( $tags as $key => $tag ) { $tags[ $key ]->link = $application->set_parameter( 'gallerytag', $tag->slug, null, false, $application->get_routed_url( true ) ); $tags[ $key ]->id = $tag->term_id; } $params = $display_settings; $params['inner_content'] = $displayed_gallery->inner_content; $params['tagcloud'] = \wp_generate_tag_cloud( $tags, $args ); $params['displayed_gallery_id'] = $displayed_gallery->id(); $params = $this->prepare_display_parameters( $displayed_gallery, $params ); $view = new View( 'TagCloud/nextgen_basic_tagcloud', $params, 'photocrati-nextgen_basic_tagcloud#nextgen_basic_tagcloud' ); return $view->render( $return ); } /** * Enqueues all static resources required by this display type * * @param DisplayedGallery $displayed_gallery */ public function enqueue_frontend_resources( $displayed_gallery ) { parent::enqueue_frontend_resources( $displayed_gallery ); wp_enqueue_style( 'photocrati-nextgen_basic_tagcloud-style', StaticAssets::get_url( 'TagCloud/nextgen_basic_tagcloud.css', 'photocrati-nextgen_basic_singlepic#nextgen_basic_singlepic.css' ), [], NGG_SCRIPT_VERSION ); } public function get_preview_image_url() { return StaticAssets::get_url( 'TagCloud/preview.gif' ); } public function get_template_directory_name(): string { return 'TagCloud'; } public function get_default_settings() { return \apply_filters( 'ngg_tag_cloud_default_settings', [ 'gallery_display_type' => NGG_BASIC_THUMBNAILS, 'ngg_triggers_display' => 'never', 'number' => 45, ] ); } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_TAGCLOUD, [ 'title' => __( 'NextGEN Basic TagCloud', 'nggallery' ), 'entity_types' => [ 'image' ], 'default_source' => 'tags', 'view_order' => NGG_DISPLAY_PRIORITY_BASE + 100, 'aliases' => [ 'tagcloud', 'basic_tagcloud', 'nextgen_basic_tagcloud', 'photocrati-nextgen_basic_tagcloud', ], 'settings' => $this->get_default_settings(), ], $reset ); } } ���������������������������������������������������DisplayTypes/Slideshow.php��������������������������������������������������������������������������0000644�����������������00000014315�15021223045�0011646 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DisplayType\Controller as ParentController; use Imagely\NGG\DataTypes\DisplayedGallery; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\View; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Router; /** * @implements \Imagely\NGG\DisplayType\ControllerAbstract */ class Slideshow extends ParentController { /** * @param DisplayedGallery $displayed_gallery * @return DisplayedGallery */ public function get_alternative_displayed_gallery( $displayed_gallery ) { // Prevent recursive checks for further alternates causing additional modifications to the settings array. $id = $displayed_gallery->id(); if ( ! empty( self::$alternate_displayed_galleries[ $id ] ) ) { return self::$alternate_displayed_galleries[ $id ]; } $show = Router::get_instance()->get_parameter( 'show' ); // Are we to display a different display type? if ( ! empty( $show ) && $show !== NGG_BASIC_SLIDESHOW ) { $params = (array) $displayed_gallery->get_entity(); unset( $params['id'] ); unset( $params['ID'] ); $ds = $params['display_settings']; if ( ( ! empty( $ds['show_slideshow_link'] ) || ! empty( $ds['show_thumbnail_link'] ) ) ) { return $this->set_alternative_displayed_gallery( $params, $displayed_gallery, $show ); } } return $displayed_gallery; } /** * @param DisplayedGallery $displayed_gallery * @param bool $return (optional) * @return string */ public function index_action( $displayed_gallery, $return = false ) { $router = Router::get_instance(); // We now hide option for triggers on this display type. This ensures they do not show based on past settings. $displayed_gallery->display_settings['ngg_triggers_display'] = 'never'; // Get the images to be displayed. $current_page = (int) $router->get_parameter( 'nggpage', 1 ); if ( ( $images = $displayed_gallery->get_included_entities() ) ) { // Get the gallery storage component. $storage = StorageManager::get_instance(); // Create parameter list for the view. $params = $displayed_gallery->display_settings; $params['storage'] = $storage; $params['images'] = $images; $params['displayed_gallery_id'] = $displayed_gallery->id(); $params['current_page'] = $current_page; $params['effect_code'] = $this->get_effect_code( $displayed_gallery ); $params['anchor'] = 'ngg-slideshow-' . $displayed_gallery->id() . '-' . rand( 1, getrandmax() ) . $current_page; $params['placeholder'] = StaticAssets::get_url( 'Slideshow/placeholder.gif', 'photocrati-nextgen_basic_gallery#slideshow/placeholder.gif' ); // This was not set correctly in previous versions. if ( empty( $params['cycle_effect'] ) ) { $params['cycle_effect'] = 'fade'; } // Are we to generate a thumbnail link? if ( $displayed_gallery->display_settings['show_thumbnail_link'] ) { $params['thumbnail_link'] = $this->get_url_for_alternate_display_type( $displayed_gallery, NGG_BASIC_THUMBNAILS ); } $params = $this->prepare_display_parameters( $displayed_gallery, $params ); $view = new View( 'Slideshow/index', $params, 'photocrati-nextgen_basic_gallery#slideshow/index' ); } else { // No images found. $view = new View( 'GalleryDisplay/NoImagesFound', [], 'photocrati-nextgen_gallery_display#no_images_found' ); } return $view->render( $return ); } /** * @param DisplayedGallery $displayed_gallery */ public function enqueue_frontend_resources( $displayed_gallery ) { parent::enqueue_frontend_resources( $displayed_gallery ); wp_enqueue_style( 'ngg_basic_slideshow_style', StaticAssets::get_url( 'Slideshow/ngg_basic_slideshow.css', 'photocrati-nextgen_basic_gallery#slideshow/ngg_basic_slideshow.css' ), [], NGG_SCRIPT_VERSION ); wp_enqueue_style( 'ngg_slick_slideshow_style', StaticAssets::get_url( 'Slideshow/slick/slick.css', 'photocrati-nextgen_basic_gallery#slideshow/slick/slick.css' ), [], NGG_SCRIPT_VERSION ); wp_enqueue_style( 'ngg_slick_slideshow_theme', StaticAssets::get_url( 'Slideshow/slick/slick-theme.css', 'photocrati-nextgen_basic_gallery#slideshow/slick/slick-theme.css' ), [], NGG_SCRIPT_VERSION ); wp_register_script( 'ngg_slick', StaticAssets::get_url( 'Slideshow/slick/slick-1.8.0-modded.js', 'photocrati-nextgen_basic_gallery#slideshow/slick/slick-1.8.0-modded.js' ), [ 'jquery' ], NGG_SCRIPT_VERSION ); wp_enqueue_script( 'ngg_basic_slideshow_script', StaticAssets::get_url( 'Slideshow/ngg_basic_slideshow.js', 'photocrati-nextgen_basic_gallery#slideshow/ngg_basic_slideshow.js' ), [ 'ngg_slick' ], NGG_SCRIPT_VERSION, true ); } public function get_preview_image_url() { return StaticAssets::get_url( 'Slideshow/slideshow_preview.jpg' ); } public function get_template_directory_name(): string { return 'Slideshow'; } public function get_default_settings() { $settings = Settings::get_instance(); return \apply_filters( 'ngg_slideshow_default_settings', [ 'gallery_width' => $settings->get( 'irWidth' ), 'gallery_height' => $settings->get( 'irHeight' ), 'show_thumbnail_link' => $settings->get( 'galShowSlide' ) ? 1 : 0, 'thumbnail_link_text' => $settings->get( 'galTextGallery' ), 'template' => '', 'display_view' => 'default', 'autoplay' => 1, 'pauseonhover' => 1, 'arrows' => 0, 'interval' => 3000, 'transition_speed' => 300, 'transition_style' => 'fade', 'ngg_triggers_display' => 'never', ] ); } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_SLIDESHOW, [ 'title' => __( 'NextGEN Basic Slideshow', 'nggallery' ), 'entity_types' => [ 'image' ], 'default_source' => 'galleries', 'view_order' => NGG_DISPLAY_PRIORITY_BASE + 10, 'aliases' => [ 'basic_slideshow', 'nextgen_basic_slideshow', 'photocrati-nextgen_basic_slideshow', ], 'settings' => $this->get_default_settings(), ], $reset ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DisplayTypes/ImageBrowser.php�����������������������������������������������������������������������0000644�����������������00000017737�15021223045�0012306 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DataStorage\MetaData as MetaDataStorage; use Imagely\NGG\DisplayType\Controller as ParentController; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\View; use Imagely\NGG\Util\Router; use Imagely\NGG\Util\URL; class ImageBrowser extends ParentController { /** * @return string */ public function index_action( $displayed_gallery, $return = false ) { // Force the trigger icon display off, regardless of past settings. $displayed_gallery->display_settings['ngg_triggers_display'] = 'never'; $picture_list = []; foreach ( $displayed_gallery->get_included_entities() as $image ) { $picture_list[ $image->{$image->id_field} ] = $image; } if ( ! $picture_list ) { $view = new View( 'GalleryDisplay/NoImagesFound', [], 'photocrati-nextgen_gallery_display#no_images_found' ); return $view->render( $return ); } $settings = $displayed_gallery->display_settings; $storage = StorageManager::get_instance(); $imap = ImageMapper::get_instance(); $router = Router::get_instance(); $application = $router->get_routed_app(); // the pid may be a slug so we must track it & the slug target's database id. $pid = $router->get_parameter( 'pid' ); $numeric_pid = null; // makes the upcoming which-image-am-I loop easier. $picture_array = []; foreach ( $picture_list as $picture ) { $picture_array[] = $picture->{$imap->get_primary_key_column()}; } // Determine which image in the list we need to display. if ( ! empty( $pid ) ) { if ( is_numeric( $pid ) && ! empty( $picture_list[ $pid ] ) ) { $numeric_pid = intval( $pid ); } else { // in the case it's a slug we need to search for the pid. foreach ( $picture_list as $key => $picture ) { if ( $picture->image_slug == $pid || strtoupper( $picture->image_slug ) === strtoupper( urlencode( $pid ) ) ) { $numeric_pid = $key; break; } } } } else { reset( $picture_array ); $numeric_pid = current( $picture_array ); } // get ids to the next and previous images. $total = count( $picture_array ); $key = array_search( $numeric_pid, $picture_array ); if ( ! $key ) { $numeric_pid = reset( $picture_array ); $key = key( $picture_array ); } // for "viewing image #13 of $total". $picture_list_pos = $key + 1; // our image to display // TODO: Remove the use of LegacyImage type. $picture = new \Imagely\NGG\DataTypes\LegacyImage( $imap->find( $numeric_pid ), $displayed_gallery, true ); $picture = apply_filters( 'ngg_image_object', $picture, $numeric_pid ); // determine URI to the next & previous images. $back_pid = ( $key >= 1 ) ? $picture_array[ $key - 1 ] : end( $picture_array ); // 'show' is set when using the imagebrowser as an alternate view to a thumbnail or slideshow for which the // basic-gallery module will rewrite the show parameter into existence as long as 'image' is set. We remove // 'show' here so navigation appears fluid. $current_url = $application->get_routed_url(); if ( $router->get_parameter( 'ajax_pagination_referrer' ) ) { $current_url = $router->get_parameter( 'ajax_pagination_referrer' ); } $prev_image_link = $application->set_parameter_value( 'pid', $picture_list[ $back_pid ]->image_slug, null, false, $current_url ); $prev_image_link = ( $application->remove_parameter( 'show', $displayed_gallery->id(), $prev_image_link ) ); $next_pid = ( $key < ( $total - 1 ) ) ? $picture_array[ $key + 1 ] : reset( $picture_array ); $next_image_link = $application->set_parameter_value( 'pid', $picture_list[ $next_pid ]->image_slug, null, false, $current_url ); $next_image_link = ( $application->remove_parameter( 'show', $displayed_gallery->id(), $next_image_link ) ); // css class. $anchor = 'ngg-imagebrowser-' . $displayed_gallery->id() . '-' . ( \get_the_ID() === false ? 0 : \get_the_ID() ); // try to read EXIF data, but fallback to the db presets. $meta = new MetaDataStorage( $picture ); $meta->sanitize(); $meta_results = [ 'exif' => $meta->get_EXIF(), 'iptc' => $meta->get_IPTC(), 'xmp' => $meta->get_XMP(), 'db' => $meta->get_saved_meta(), ]; $meta_results['exif'] = ( $meta_results['exif'] === false ) ? $meta_results['db'] : $meta_results['exif']; // Disable triggers IF we're rendering inside an ajax-pagination request; var set in common.js. // Nonce verification is not necessary here. // // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( isset( $_POST['ajax_referrer'] ) ) { $displayed_gallery->display_settings['ngg_triggers_display'] = 'never'; } if ( ! empty( $settings['template'] ) && $settings['template'] != 'default' ) { $picture->href_link = $picture->get_href_link(); $picture->previous_image_link = $prev_image_link; $picture->previous_pid = $back_pid; $picture->next_image_link = $next_image_link; $picture->next_pid = $next_pid; $picture->number = $picture_list_pos; $picture->total = $total; $picture->anchor = $anchor; return $this->legacy_render( $settings['template'], [ 'image' => $picture, 'meta' => $meta, 'exif' => $meta_results['exif'], 'iptc' => $meta_results['iptc'], 'xmp' => $meta_results['xmp'], 'db' => $meta_results['db'], 'displayed_gallery' => $displayed_gallery, ], true, 'imagebrowser' ); } else { $params = $settings; $params['anchor'] = $anchor; $params['image'] = $picture; $params['storage'] = $storage; $params['previous_pid'] = $back_pid; $params['next_pid'] = $next_pid; $params['number'] = $picture_list_pos; $params['total'] = $total; $params['previous_image_link'] = $prev_image_link; $params['next_image_link'] = $next_image_link; $params['effect_code'] = $this->get_effect_code( $displayed_gallery ); $params = $this->prepare_display_parameters( $displayed_gallery, $params ); $view = new View( 'ImageBrowser/default-view', $params, 'photocrati-nextgen_basic_imagebrowser#nextgen_basic_imagebrowser' ); return $view->render( $return ); } return ''; } public function enqueue_frontend_resources( $displayed_gallery ) { parent::enqueue_frontend_resources( $displayed_gallery ); wp_enqueue_style( 'nextgen_basic_imagebrowser_style', StaticAssets::get_url( 'ImageBrowser/style.css', 'photocrati-nextgen_basic_imagebrowser#style.css' ), [], NGG_SCRIPT_VERSION ); wp_enqueue_script( 'nextgen_basic_imagebrowser_script', StaticAssets::get_url( 'ImageBrowser/imagebrowser.js', 'photocrati-nextgen_basic_imagebrowser#imagebrowser.js' ), [ 'ngg_common' ], NGG_SCRIPT_VERSION, true ); } public function get_preview_image_url() { return StaticAssets::get_url( 'ImageBrowser/preview.jpg' ); } public function get_default_settings() { return \apply_filters( 'ngg_image_browser_default_settings', [ 'display_view' => 'default-view.php', 'template' => '', 'ajax_pagination' => '1', 'ngg_triggers_display' => 'never', ] ); } public function get_template_directory_name(): string { return 'ImageBrowser'; } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_IMAGEBROWSER, [ 'title' => __( 'NextGEN Basic ImageBrowser', 'nggallery' ), 'entity_types' => [ 'image' ], 'default_source' => 'galleries', 'view_order' => NGG_DISPLAY_PRIORITY_BASE + 20, 'aliases' => [ 'imagebrowser', 'basic_imagebrowser', 'nextgen_basic_imagebrowser', 'photocrati-nextgen_basic_imagebrowser', ], 'settings' => $this->get_default_settings(), ], $reset ); } } ���������������������������������DisplayTypes/CompactAlbum.php�����������������������������������������������������������������������0000644�����������������00000004221�15021223045�0012247 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DisplayTypes; use Imagely\NGG\DisplayTypes\Albums\SharedController; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Settings\Settings; class CompactAlbum extends SharedController { public function __construct() { $this->legacy_template = 'photocrati-nextgen_basic_album#compact'; $this->template = 'CompactAlbum/compact'; } public function get_preview_image_url() { return StaticAssets::get_url( 'CompactAlbum/compact_preview.jpg' ); } public function get_default_settings() { $settings = Settings::get_instance(); $default_template = isset( $entity->settings['template'] ) ? 'default' : 'default-view.php'; return \apply_filters( 'ngg_compact_album_default_settings', [ 'disable_pagination' => 0, 'display_view' => $default_template, 'enable_breadcrumbs' => 1, 'enable_descriptions' => 0, 'galleries_per_page' => $settings->get( 'galPagedGalleries' ), 'gallery_display_template' => '', 'gallery_display_type' => NGG_BASIC_THUMBNAILS, 'ngg_triggers_display' => 'never', 'open_gallery_in_lightbox' => 0, 'override_thumbnail_settings' => 1, 'template' => '', 'thumbnail_crop' => 1, 'thumbnail_height' => 160, 'thumbnail_quality' => $settings->get( 'thumbquality' ), 'thumbnail_watermark' => 0, 'thumbnail_width' => 240, ] ); } public function get_template_directory_name(): string { return 'CompactAlbum'; } public function install( $reset = false ) { $this->install_display_type( NGG_BASIC_COMPACT_ALBUM, [ 'title' => __( 'NextGEN Basic Compact Album', 'nggallery' ), 'entity_types' => [ 'album', 'gallery' ], 'default_source' => 'albums', 'view_order' => NGG_DISPLAY_PRIORITY_BASE + 200, 'aliases' => [ 'compact_album', 'basic_album_compact', 'basic_compact_album', 'nextgen_basic_album', 'photocrati-nextgen_basic_compact_album', ], 'settings' => $this->get_default_settings(), ], $reset ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IGW/Controller.php����������������������������������������������������������������������������������0000644�����������������00000062270�15021223045�0010027 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\IGW; use Imagely\NGG\DataMappers\Album as AlbumMapper; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\DataMappers\DisplayedGallery as DisplayedGalleryMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\Admin\FormManager; use Imagely\NGG\DisplayType\ControllerFactory; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\StaticPopeAssets; use Imagely\NGG\Display\View; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\DisplayedGallery\SourceManager; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Router; use Imagely\NGG\Util\Security; use Imagely\NGG\Util\URL; class Controller { public static $_instances = []; protected $displayed_gallery; /** @var \C_NextGen_Admin_Page_Controller|null $parent */ protected $parent = null; protected $attach_to_post_scripts = []; protected $attach_to_post_styles = []; public function __construct() { $this->parent = \C_NextGen_Admin_Page_Controller::get_instance(); $this->_load_displayed_gallery(); if ( ! has_action( 'wp_print_scripts', [ $this, 'filter_scripts' ] ) ) { add_action( 'wp_print_scripts', [ $this, 'filter_scripts' ] ); } if ( ! has_action( 'wp_print_scripts', [ $this, 'filter_styles' ] ) ) { add_action( 'wp_print_scripts', [ $this, 'filter_styles' ] ); } } static function get_instance( string $context = 'all' ): Controller { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new Controller( $context ); } return self::$_instances[ $context ]; } /** * Necessary for compatibility with Pro. * * @TODO Remove when use of this method has been removed from Pro */ public static function has_method(): bool { return false; } public function _load_displayed_gallery() { $mapper = DisplayedGalleryMapper::get_instance(); // Fetch the displayed gallery by ID. if ( ( $id = $this->parent->param( 'id' ) ) ) { $this->displayed_gallery = $mapper->find( $id ); } elseif ( isset( $_REQUEST['shortcode'] ) && isset( $_REQUEST['nonce'] ) && \wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'ngg_attach_to_post_iframe' ) ) { // Fetch the displayed gallery by shortcode. $shortcode = base64_decode( $_REQUEST['shortcode'] ); // $shortcode lacks the opening and closing brackets but still begins with 'ngg ' or 'ngg_images ' which are not parameters. $params = preg_replace( '/^(ngg|ngg_images) /i', '', $shortcode, 1 ); $params = stripslashes( $params ); $params = str_replace( [ '[', ']' ], [ '[', ']' ], $params ); $params = shortcode_parse_atts( $params ); $this->displayed_gallery = Renderer::get_instance()->params_to_displayed_gallery( $params ); } // If all else fails, then create fresh with a new displayed gallery. if ( empty( $this->displayed_gallery ) ) { $this->displayed_gallery = $mapper->create(); } } /** * Gets all dependencies for a particular resource that has been registered using wp_register_style/wp_register_script * * @param $handle * @param $type * * @return array */ public function get_resource_dependencies( $handle, $type ) { $retval = []; $wp_resources = $GLOBALS[ $type ]; if ( ( $index = array_search( $handle, $wp_resources->registered ) ) !== false ) { $registered_script = $wp_resources->registered[ $index ]; if ( $registered_script->deps ) { foreach ( $registered_script->deps as $dep ) { $retval[] = $dep; $retval = array_merge( $retval, $this->get_script_dependencies( $handle ) ); } } } return $retval; } public function get_script_dependencies( $handle ) { return $this->get_resource_dependencies( $handle, 'wp_scripts' ); } public function get_style_dependencies( $handle ) { return $this->get_resource_dependencies( $handle, 'wp_styles' ); } public function get_ngg_provided_resources( $type ) { $wp_resources = $GLOBALS[ $type ]; $retval = []; foreach ( $wp_resources->queue as $handle ) { $script = $wp_resources->registered[ $handle ]; if ( strpos( $script->src, plugin_dir_url( NGG_PLUGIN_BASENAME ) ) !== false ) { $retval[] = $handle; } if ( defined( 'NGG_PRO_PLUGIN_BASENAME' ) && strpos( $script->src, plugin_dir_url( NGG_PRO_PLUGIN_BASENAME ) ) !== false ) { $retval[] = $handle; } if ( defined( 'NGG_PLUS_PLUGIN_BASENAME' ) && strpos( $script->src, plugin_dir_url( NGG_PLUS_PLUGIN_BASENAME ) ) !== false ) { $retval[] = $handle; } } return array_unique( $retval ); } public function get_ngg_provided_scripts() { return $this->get_ngg_provided_resources( 'wp_scripts' ); } public function get_ngg_provided_styles() { return $this->get_ngg_provided_resources( 'wp_styles' ); } public function get_igw_allowed_scripts() { $retval = []; foreach ( $this->get_ngg_provided_scripts() as $handle ) { $retval[] = $handle; $retval = array_merge( $retval, $this->get_script_dependencies( $handle ) ); } foreach ( $this->get_display_type_scripts() as $handle ) { $retval[] = $handle; $retval = array_merge( $retval, $this->get_script_dependencies( $handle ) ); } foreach ( $this->attach_to_post_scripts as $handle ) { $retval[] = $handle; $retval = array_merge( $retval, $this->get_script_dependencies( $handle ) ); } return array_unique( apply_filters( 'ngg_igw_approved_scripts', $retval ) ); } public function get_display_type_scripts() { global $wp_scripts; $wp_scripts->old_queue = $wp_scripts->queue; $wp_scripts->queue = []; $mapper = DisplayTypeMapper::get_instance(); foreach ( $mapper->find_all() as $display_type ) { $form = \C_Form::get_instance( $display_type->name ); $form->enqueue_static_resources(); } $retval = $wp_scripts->queue; $wp_scripts->queue = $wp_scripts->old_queue; unset( $wp_scripts->old_queue ); return $retval; } public function get_display_type_styles() { global $wp_styles; $wp_styles->old_queue = $wp_styles->queue; $wp_styles->queue = []; $mapper = DisplayTypeMapper::get_instance(); foreach ( $mapper->find_all() as $display_type ) { $form = \C_Form::get_instance( $display_type->name ); $form->enqueue_static_resources(); } $retval = $wp_styles->queue; $wp_styles->queue = $wp_styles->old_queue; unset( $wp_styles->old_queue ); return $retval; } public function get_igw_allowed_styles() { $retval = []; foreach ( $this->get_ngg_provided_styles() as $handle ) { $retval[] = $handle; $retval = array_merge( $retval, $this->get_style_dependencies( $handle ) ); } foreach ( $this->get_display_type_styles() as $handle ) { $retval[] = $handle; $retval = array_merge( $retval, $this->get_style_dependencies( $handle ) ); } foreach ( $this->attach_to_post_styles as $handle ) { $retval[] = $handle; $retval = array_merge( $retval, $this->get_style_dependencies( $handle ) ); } return array_unique( apply_filters( 'ngg_igw_approved_styles', $retval ) ); } public function filter_scripts() { global $wp_scripts; $new_queue = []; $current_queue = $wp_scripts->queue; $approved = $this->get_igw_allowed_scripts(); foreach ( $current_queue as $handle ) { if ( in_array( $handle, $approved ) ) { $new_queue[] = $handle; } } $wp_scripts->queue = $new_queue; } public function filter_styles() { global $wp_styles; $new_queue = []; $current_queue = $wp_styles->queue; $approved = $this->get_igw_allowed_styles(); foreach ( $current_queue as $handle ) { if ( in_array( $handle, $approved ) ) { $new_queue[] = $handle; } } $wp_styles->queue = $new_queue; } /** * Necessary for compatibility with Pro. * * @TODO Remove when use of this method has been removed from Pro * @return false */ public function mark_script( $handle ) { return false; } public function enqueue_display_tab_js() { // Enqueue backbone.js library, required by the Attach to Post display tab. wp_enqueue_script( 'backbone' ); // provided by WP. // Enqueue the backbone app for the display tab. Get all entities used by the display tab. $context = 'attach_to_post'; $gallery_mapper = GalleryMapper::get_instance(); $album_mapper = AlbumMapper::get_instance(); $image_mapper = ImageMapper::get_instance(); $display_type_mapper = DisplayTypeMapper::get_instance(); $sources = SourceManager::get_instance(); $router = Router::get_instance(); $settings = Settings::get_instance(); // Get the nextgen tags. global $wpdb; $tags = $wpdb->get_results( "SELECT DISTINCT name AS 'id', name FROM {$wpdb->terms} WHERE term_id IN ( SELECT term_id FROM {$wpdb->term_taxonomy} WHERE taxonomy = 'ngg_tag' )" ); $all_tags = new \stdClass(); $all_tags->name = 'All'; $all_tags->id = 'All'; array_unshift( $tags, $all_tags ); $display_types = []; $display_type_mapper->flush_query_cache(); $all_display_types = $display_type_mapper->find_all(); if ( \C_NextGEN_Bootstrap::get_pro_api_version() >= 4.0 ) { foreach ( $all_display_types as $display_type ) { $available = ControllerFactory::has_controller( $display_type->name ); if ( ! \apply_filters( 'ngg_atp_show_display_type', $available, $display_type ) ) { continue; } if ( ! ControllerFactory::has_controller( $display_type->name ) ) { continue; } $controller = ControllerFactory::get_controller( $display_type->name ); if ( $controller->is_hidden_from_igw() ) { continue; } $display_type->preview_image_url = $controller->get_preview_image_url(); $display_types[] = $display_type; } } else { foreach ( $all_display_types as $display_type ) { if ( ( isset( $display_type->hidden_from_igw ) && $display_type->hidden_from_igw ) || ( isset( $display_type->hidden_from_ui ) && $display_type->hidden_from_ui ) ) { continue; } $available = ControllerFactory::has_controller( $display_type->name ); if ( ! $available && class_exists( '\C_Component_Registry' ) ) { $available = \C_Component_Registry::get_instance()->is_module_loaded( $display_type->name ); if ( ! $available && defined( 'NGG_PRO_ALBUMS' ) && in_array( $display_type->name, [ \NGG_PRO_LIST_ALBUM, \NGG_PRO_GRID_ALBUM ] ) ) { $available = true; } } if ( ! \apply_filters( 'ngg_atp_show_display_type', $available, $display_type ) ) { continue; } if ( ControllerFactory::has_controller( $display_type->name ) ) { $controller = ControllerFactory::get_controller( $display_type->name ); $display_type->preview_image_url = $controller->get_preview_image_url(); } else { $display_type->preview_image_url = StaticPopeAssets::get_url( $display_type->preview_image_relpath ); } $display_types[] = $display_type; } } usort( $display_types, [ $this, '_display_type_list_sort' ] ); \wp_enqueue_script( 'ngg_display_tab', StaticAssets::get_url( 'AttachToPost/display_tab.js', 'photocrati-attach_to_post#display_tab.js' ), [ 'jquery', 'backbone', 'photocrati_ajax' ], NGG_SCRIPT_VERSION ); \wp_localize_script( 'ngg_display_tab', 'igw_data', [ 'displayed_gallery_preview_url' => $router->get_url( '/' . NGG_ATTACH_TO_POST_SLUG . '/preview', false ), 'displayed_gallery' => $this->displayed_gallery->get_entity(), 'sources' => $sources->get_all(), 'gallery_primary_key' => $gallery_mapper->get_primary_key_column(), 'galleries' => $gallery_mapper->find_all(), 'albums' => $album_mapper->find_all(), 'tags' => $tags, 'display_types' => $display_types, 'nonce' => wp_create_nonce( 'wp_rest' ), 'image_primary_key' => $image_mapper->get_primary_key_column(), 'display_type_priority_base' => NGG_DISPLAY_PRIORITY_BASE, 'display_type_priority_step' => NGG_DISPLAY_PRIORITY_STEP, // Nonce verification has already been performed by the methods that invoke this method. // phpcs:ignore WordPress.Security.NonceVerification.Recommended 'shortcode_ref' => isset( $_REQUEST['ref'] ) ? floatval( $_REQUEST['ref'] ) : null, 'shortcode_defaults' => [ 'order_by' => $settings->get( 'galSort' ), 'order_direction' => $settings->get( 'galSortDir' ), 'returns' => 'included', 'maximum_entity_count' => $settings->get( 'maximum_entity_count' ), ], 'shortcode_attr_replacements' => [ 'source' => 'src', 'container_ids' => 'ids', 'display_type' => 'display', ], 'i18n' => [ 'sources' => \__( 'Are you inserting a Gallery (default), an Album, or images based on Tags?', 'nggallery' ), 'optional' => \__( '(optional)', 'nggallery' ), 'slug_tooltip' => \__( 'Sets an SEO-friendly name to this gallery for URLs. Currently only in use by the Pro Lightbox', 'nggallery' ), 'slug_label' => \__( 'Slug', 'nggallery' ), 'no_entities' => \__( 'No entities to display for this source', 'nggallery' ), 'exclude_question' => \__( 'Exclude?', 'nggallery' ), 'select_gallery' => \__( 'Select a Gallery', 'nggallery' ), 'galleries' => \__( 'Select one or more galleries (click in box to see available galleries).', 'nggallery' ), 'albums' => \__( 'Select one album (click in box to see available albums).', 'nggallery' ), ], ] ); } public function start_resource_monitoring() { global $wp_scripts, $wp_styles; $this->attach_to_post_scripts = []; $this->attach_to_post_styles = []; $wp_styles->before_monitoring = $wp_styles->queue; $wp_scripts->before_monitoring = $wp_styles->queue; } public function stop_resource_monitoring() { global $wp_scripts, $wp_styles; $this->attach_to_post_scripts = array_diff( $wp_scripts->queue, $wp_scripts->before_monitoring ); $this->attach_to_post_styles = array_diff( $wp_styles->queue, $wp_styles->before_monitoring ); } public function enqueue_backend_resources() { $this->start_resource_monitoring(); // Enqueue frame event publishing. \wp_enqueue_script( 'frame_event_publisher' ); \wp_enqueue_script( 'ngg_tabs', StaticAssets::get_url( 'AttachToPost/ngg_tabs.js', 'photocrati-attach_to_post#ngg_tabs.js' ), [ 'jquery-ui-tabs', 'jquery-ui-sortable', 'jquery-ui-tooltip', 'jquery-ui-accordion' ], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'buttons' ); // Ensure select2. \wp_enqueue_style( 'ngg_select2' ); \wp_enqueue_script( 'ngg_select2' ); // Ensure that the Photocrati AJAX library is loaded. \wp_enqueue_script( 'photocrati_ajax' ); // Enqueue logic for the Attach to Post interface as a whole. \wp_enqueue_script( 'ngg_attach_to_post_js', StaticAssets::get_url( 'AttachToPost/attach_to_post.js', 'photocrati-attach_to_post#attach_to_post.js' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'ngg_attach_to_post', StaticAssets::get_url( 'AttachToPost/attach_to_post.css', 'photocrati-attach_to_post#attach_to_post.css' ), [], NGG_SCRIPT_VERSION ); \wp_dequeue_script( 'debug-bar-js' ); \wp_dequeue_style( 'debug-bar-css' ); $this->enqueue_display_tab_js(); if ( ! \M_Marketing::is_plus_or_pro_enabled() ) { $marketing = new Marketing(); $marketing->enqueue_display_tab_js(); } \do_action( 'ngg_igw_enqueue_scripts' ); \do_action( 'ngg_igw_enqueue_styles' ); $this->stop_resource_monitoring(); } /** * Renders the interface * * @param bool $return * @return string */ public function index_action( $return = true ) { $parent = \C_NextGen_Admin_Page_Controller::get_instance(); $parent->enqueue_backend_resources(); $parent->do_not_cache(); $this->enqueue_backend_resources(); \wp_enqueue_style( 'nggadmin', NGGALLERY_URLPATH . 'admin/css/nggadmin.css', [], NGG_SCRIPT_VERSION, 'screen' ); \do_action( 'admin_enqueue_scripts' ); // If Elementor is also active a fatal error is generated due to this method not existing. if ( ! function_exists( 'wp_print_media_templates' ) ) { require_once ABSPATH . WPINC . '/media-template.php'; } $view = new View( 'AttachToPost/attach_to_post', [ 'page_title' => $this->_get_page_title(), 'tabs' => $this->_get_main_tabs(), 'logo' => StaticPopeAssets::get_url( 'photocrati-nextgen_admin#imagely_icon.png' ), ], 'photocrati-attach_to_post#attach_to_post' ); return $view->render( $return ); } /** * Returns the page title of the Attach to Post interface * * @return string */ public function _get_page_title() { return \__( 'NextGEN Gallery - Attach To Post', 'nggallery' ); } /** * Returns the main tabs displayed on the Attach to Post interface * * @return array */ public function _get_main_tabs() { $retval = []; if ( Security::is_allowed( 'NextGEN Manage gallery' ) ) { $retval['displayed_tab'] = [ 'content' => $this->_render_display_tab(), 'title' => \__( 'Insert Into Page', 'nggallery' ), ]; } if ( Security::is_allowed( 'NextGEN Upload images' ) ) { $retval['create_tab'] = [ 'content' => $this->_render_create_tab(), 'title' => \__( 'Upload Images', 'nggallery' ), ]; } if ( Security::is_allowed( 'NextGEN Manage others gallery' ) && Security::is_allowed( 'NextGEN Manage gallery' ) ) { $retval['galleries_tab'] = [ 'content' => $this->_render_galleries_tab(), 'title' => \__( 'Manage Galleries', 'nggallery' ), ]; } if ( Security::is_allowed( 'NextGEN Edit album' ) ) { $retval['albums_tab'] = [ 'content' => $this->_render_albums_tab(), 'title' => \__( 'Manage Albums', 'nggallery' ), ]; } return apply_filters( 'ngg_attach_to_post_main_tabs', $retval ); } /** * Renders a NextGen Gallery page in an iframe, suited for the attach to post * interface * * @param string $page * @param null|int $tab_id (optional) * @return string */ public function _render_ngg_page_in_frame( $page, $tab_id = null ) { $frame_url = \admin_url( "/admin.php?page={$page}&attach_to_post" ); $frame_url = Router::esc_url( $frame_url ); if ( $tab_id ) { $tab_id = " id='ngg-iframe-{$tab_id}'"; } return "<iframe name='{$page}' frameBorder='0'{$tab_id} class='ngg-attach-to-post ngg-iframe-page-{$page}' scrolling='yes' src='{$frame_url}'></iframe>"; } /** * Renders the display tab for adjusting how images/galleries will be displayed * * @return string */ public function _render_display_tab() { $view = new View( 'AttachToPost/display_tab', [ 'messages' => [], 'displayed_gallery' => $this->displayed_gallery, 'tabs' => $this->_get_display_tabs(), ], 'photocrati-attach_to_post#display_tab' ); return $view->render( true ); } /** * Renders the tab used primarily for Gallery and Image creation * * @return string */ public function _render_create_tab() { return $this->_render_ngg_page_in_frame( 'ngg_addgallery', 'create_tab' ); } /** * Renders the tab used for Managing Galleries * * @return string */ public function _render_galleries_tab() { return $this->_render_ngg_page_in_frame( 'nggallery-manage-gallery', 'galleries_tab' ); } /** * Renders the tab used for Managing Albums. */ public function _render_albums_tab() { return $this->_render_ngg_page_in_frame( 'nggallery-manage-album', 'albums_tab' ); } public function _display_type_list_sort( $type_1, $type_2 ) { $order_1 = $type_1->view_order; $order_2 = $type_2->view_order; if ( $order_1 == null ) { $order_1 = NGG_DISPLAY_PRIORITY_BASE; } if ( $order_2 == null ) { $order_2 = NGG_DISPLAY_PRIORITY_BASE; } if ( $order_1 > $order_2 ) { return 1; } if ( $order_1 < $order_2 ) { return -1; } return 0; } /** * Gets a list of tabs to render for the "Display" tab */ public function _get_display_tabs() { // The ATP requires more memmory than some applications, somewhere around 60MB. // Because it's such an important feature of NextGEN Gallery, we temporarily disable // any memory limits. if ( ! extension_loaded( 'suhosin' ) ) { @ini_set( 'memory_limit', -1 ); } return [ 'choose_display_tab' => $this->_render_choose_display_tab(), 'display_settings_tab' => $this->_render_display_settings_tab(), 'preview_tab' => $this->_render_preview_tab(), ]; } /** * Renders the accordion tab, "What would you like to display?" */ public function _render_choose_display_tab() { return [ 'id' => 'choose_display', 'title' => \__( 'Choose Display', 'nggallery' ), 'content' => $this->_render_display_source_tab_contents() . $this->_render_display_type_tab_contents(), ]; } /** * Renders the contents of the source tab * * @return string */ public function _render_display_source_tab_contents() { $view = new View( 'AttachToPost/display_tab_source', [ 'i18n' => [], ], 'photocrati-attach_to_post#display_tab_source' ); return $view->render( true ); } /** * Renders the contents of the display type tab */ public function _render_display_type_tab_contents() { $view = new View( 'AttachToPost/display_tab_type', [], 'photocrati-attach_to_post#display_tab_type' ); return $view->render( true ); } /** * Renders the display settings tab for the Attach to Post interface * * @return array */ public function _render_display_settings_tab() { return [ 'id' => 'display_settings_tab', 'title' => \__( 'Customize Display Settings', 'nggallery' ), 'content' => $this->_render_display_settings_contents(), ]; } /** * If editing an existing displayed gallery, retrieves the name * of the display type * * @return string */ public function _get_selected_display_type_name() { $retval = ''; if ( $this->displayed_gallery ) { $retval = $this->displayed_gallery->display_type; } return $retval; } /** * Is the displayed gallery that's being edited using the specified display * type? * * @param string $name name of the display type * @return bool */ public function is_displayed_gallery_using_display_type( $name ) { $retval = false; if ( $this->displayed_gallery ) { $retval = $this->displayed_gallery->display_type == $name; } return $retval; } /** * Renders the contents of the display settings tab * * @return string */ public function _render_display_settings_contents() { $retval = []; // Get all display setting forms. $form_manager = FormManager::get_instance(); $forms = $form_manager->get_forms( NGG_DISPLAY_SETTINGS_SLUG, true ); // Display each form. foreach ( $forms as $form ) { // Enqueue the form's static resources. $form->enqueue_static_resources(); // Determine which classes to use for the form's "class" attribute. $model = $form->get_model(); if ( null === $model ) { continue; } $current = $this->is_displayed_gallery_using_display_type( $model->name ); $css_class = $current ? 'display_settings_form' : 'display_settings_form hidden'; $defaults = $model->settings; // If this form is used to provide the display settings for the current // displayed gallery, then we need to override the forms settings // with the displayed gallery settings. if ( $current ) { $settings = $this->parent->array_merge_assoc( $model->settings, $this->displayed_gallery->display_settings, true ); $model->settings = $settings; } // Output the display settings form. $view = new View( 'AttachToPost/display_settings_form', [ 'settings' => $form->render(), 'display_type_name' => $model->name, 'css_class' => $css_class, 'defaults' => $defaults, ], 'photocrati-attach_to_post#display_settings_form' ); $retval[] = $view->render( true ); } // In addition, we'll render a form that will be displayed when no display type has been selected in the // Attach to Post interface. Render the default "no display type selected" view. $css_class = $this->_get_selected_display_type_name() ? 'display_settings_form hidden' : 'display_settings_form'; $view = new View( 'AttachToPost/no_display_type_selected', [ 'no_display_type_selected' => \__( 'No display type selected', 'nggallery' ), 'css_class' => $css_class, ], 'photocrati-attach_to_post#no_display_type_selected' ); $retval[] = $view->render( true ); // Return all display setting forms. return implode( "\n", $retval ); } /** * Renders the tab used to preview included images * * @return array */ public function _render_preview_tab() { return [ 'id' => 'preview_tab', 'title' => \__( 'Sort or Exclude Images', 'nggallery' ), 'content' => $this->_render_preview_tab_contents(), ]; } /** * Renders the contents of the "Preview" tab. * * @return string */ public function _render_preview_tab_contents() { $view = new View( 'AttachToPost/preview_tab', [], 'photocrati-attach_to_post#preview_tab' ); return $view->render( true ); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IGW/EventPublisher.php������������������������������������������������������������������������������0000644�����������������00000011026�15021223045�0010634 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\IGW; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Settings\GlobalSettings; class EventPublisher { protected static $instance = null; protected $setting_name = null; public function __construct() { $this->setting_name = Settings::get_instance()->get( 'frame_event_cookie_name' ); } public function register_hooks() { add_action( 'init', [ $this, 'register_script' ] ); add_filter( 'ngg_admin_script_handles', [ $this, 'add_script_to_ngg_pages' ] ); add_action( 'ngg_enqueue_frame_event_publisher_script', [ $this, 'enqueue_script' ] ); // Elementor's editor.php runs `new \WP_Scripts()` which requires we register scripts on both init and this // action if we want the attach-to-post code to function (which relies on frame_event_publisher). add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'register_script' ] ); // Emit frame communication events. if ( $this->does_request_require_frame_communication() ) { add_action( 'ngg_created_new_gallery', [ $this, 'new_gallery_event' ] ); add_action( 'ngg_after_new_images_added', [ $this, 'images_added_event' ] ); add_action( 'ngg_page_event', [ $this, 'nextgen_page_event' ] ); add_action( 'ngg_manage_tags', [ $this, 'manage_tags_event' ] ); } } public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new EventPublisher(); } return self::$instance; } /** * Encodes data for a setting * * @param array $data * @return string */ protected function encode( $data ) { return \rawurlencode( \json_encode( $data ) ); } /** * Decodes data from a setting * * @param string $data * @return array */ protected function decode( $data ) { return (array) \json_decode( \rawurldecode( $data ) ); } /** * Adds a setting to the frame events * * @param array $data * @return array */ public function add_event( $data ) { $id = \md5( \serialize( $data ) ); $data['context'] = 'attach_to_post'; $write_cookie = true; if ( \defined( 'XMLRPC_REQUEST' ) ) { $write_cookie = XMLRPC_REQUEST == false; } if ( $write_cookie ) { \setrawcookie( $this->setting_name . '_' . $id, $this->encode( $data ), \time() + 10800, '/', \parse_url( \site_url(), PHP_URL_HOST ) ); } return $data; } /* TODO: Determine if this is necessary and remove it */ public function add_script_to_ngg_pages( $scripts ) { $scripts['frame_event_publisher'] = NGG_SCRIPT_VERSION; return $scripts; } public function enqueue_script() { wp_enqueue_script( 'frame_event_publisher' ); wp_localize_script( 'frame_event_publisher', 'frame_event_publisher_domain', [ parse_url( site_url(), PHP_URL_HOST ) ] ); } public function register_script() { wp_register_script( 'frame_event_publisher', StaticAssets::get_url( 'IGW/frame_event_publisher.js', 'photocrati-frame_communication#frame_event_publisher.js' ), [ 'jquery' ], NGG_SCRIPT_VERSION ); } public function does_request_require_frame_communication(): bool { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return ( strpos( $_SERVER['REQUEST_URI'], 'attach_to_post' ) !== false or ( isset( $_SERVER['HTTP_REFERER'] ) && strpos( $_SERVER['HTTP_REFERER'], 'attach_to_post' ) !== false ) or array_key_exists( 'attach_to_post', $_REQUEST ) ); } /** * Notify frames that a new gallery has been created * * @param int $gallery_id */ public function new_gallery_event( $gallery_id ) { $gallery = GalleryMapper::get_instance()->find( $gallery_id ); if ( $gallery ) { $this->add_event( [ 'event' => 'new_gallery', 'gallery_id' => intval( $gallery_id ), 'gallery_title' => $gallery->title, ] ); } } /** * Notifies a frame that images have been added to a gallery * * @param int $gallery_id * @param array $image_ids */ public function images_added_event( $gallery_id, $image_ids = [] ) { $this->add_event( [ 'event' => 'images_added', 'gallery_id' => intval( $gallery_id ), ] ); } /** * Notifies a frame that an action has been performed on a particular NextGEN page * * @param array $event */ public function nextgen_page_event( $event ) { $this->add_event( $event ); } /** * Notifies a frame that the tags have changed * * @param array $tags */ public function manage_tags_event( $tags = [] ) { $this->add_event( [ 'event' => 'manage_tags', 'tags' => $tags, ] ); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IGW/Marketing.php�����������������������������������������������������������������������������������0000644�����������������00000006471�15021223045�0007626 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\IGW; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\View; class Marketing { public function new_pro_display_type_upsell( $id, $name, $title = '', $preview_mvc_path = null ) { return [ 'ID' => $id, 'default_source' => 'galleries', 'entity_types' => [ 'image' ], 'hidden_from_igw' => false, 'hidden_from_ui' => false, 'name' => $name, 'title' => $title, 'preview_image_url' => $preview_mvc_path ? StaticAssets::get_url( $preview_mvc_path ) : '', ]; } public function get_pro_display_types() { return [ $this->new_pro_display_type_upsell( -1, 'pro-tile', __( 'Pro Tile', 'nggallery' ), 'IGW/Marketing/pro-tile-preview.jpg' ), $this->new_pro_display_type_upsell( -2, 'pro-mosaic', __( 'Pro Mosaic', 'nggallery' ), 'IGW/Marketing/pro-mosaic-preview.jpg' ), $this->new_pro_display_type_upsell( -3, 'pro-masonry', __( 'Pro Masonry', 'nggallery' ), 'IGW/Marketing/pro-masonry-preview.jpg' ), $this->new_pro_display_type_upsell( -4, 'igw-promo' ), ]; } public function get_marketing_cards() { $pro_tile = new \C_Marketing_Block_Popup( __( 'Pro Tile Gallery', 'nggallery' ), \M_Marketing::get_i18n_fragment( 'feature_not_available', __( 'the Pro Tile Gallery', 'nggallery' ) ), \M_Marketing::get_i18n_fragment( 'lite_coupon' ), StaticAssets::get_url( 'IGW/Marketing/pro-tile-preview.jpg' ), 'igw', 'tiledgallery' ); $pro_masonry = new \C_Marketing_Block_Popup( __( 'Pro Masonry Gallery', 'nggallery' ), \M_Marketing::get_i18n_fragment( 'feature_not_available', __( 'the Pro Masonry Gallery', 'nggallery' ) ), \M_Marketing::get_i18n_fragment( 'lite_coupon' ), StaticAssets::get_url( 'IGW/Marketing/pro-masonry-preview.jpg' ), 'igw', 'masonrygallery' ); $pro_mosaic = new \C_Marketing_Block_Popup( __( 'Pro Mosaic Gallery', 'nggallery' ), \M_Marketing::get_i18n_fragment( 'feature_not_available', __( 'the Pro Mosaic Gallery', 'nggallery' ) ), \M_Marketing::get_i18n_fragment( 'lite_coupon' ), StaticAssets::get_url( 'IGW/Marketing/pro-mosaic-preview.jpg' ), 'igw', 'mosaicgallery' ); return [ 'pro-tile' => '<div>' . $pro_tile->render() . '</div>', 'pro-masonry' => '<div>' . $pro_masonry->render() . '</div>', 'pro-mosaic' => '<div>' . $pro_mosaic->render() . '</div>', ]; } public function enqueue_display_tab_js() { $view = new View( 'IGW/marketing' ); $data = [ 'display_types' => $this->get_pro_display_types(), 'i18n' => [ 'get_pro' => __( 'Requires NextGEN Pro', 'nggallery' ), ], 'templates' => $this->get_marketing_cards(), 'igw_promo' => $view->render( true ), ]; \wp_enqueue_style( 'jquery-modal' ); \wp_enqueue_script( 'igw_display_type_upsells', StaticAssets::get_url( 'IGW/Marketing/igw_display_type_upsells.js' ), [ 'ngg_display_tab', 'jquery-modal' ], NGG_SCRIPT_VERSION ); \wp_localize_script( 'igw_display_type_upsells', 'igw_display_type_upsells', $data ); \M_Marketing::enqueue_blocks_style(); \wp_add_inline_style( 'ngg_attach_to_post', '.display_type_preview:nth-child(5) {clear: both;} .ngg-marketing-block-display-type-settings label {color: darkgray !important;}' ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������IGW/BlockManager.php��������������������������������������������������������������������������������0000644�����������������00000011550�15021223045�0010224 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\IGW; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Util\URL; /** * Handles the NextGEN block and post thumbnail */ class BlockManager { protected static $instance = null; /** * @return BlockManager */ static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new BlockManager(); } return self::$instance; } public function register_hooks() { add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_post_thumbnails' ], 1 ); add_action( 'enqueue_block_assets', [ $this, 'ngg_enqueue_block_assets' ] ); // Adds NextGEN thumbnail support to all posts with 'thumbnail' support by adding a field for posts/pages to // set the ngg_post_thumbnail via REST API. add_action( 'init', function () { array_map( function ( $post_type ) { add_post_type_support( $post_type, 'custom-fields' ); register_meta( $post_type, 'ngg_post_thumbnail', [ 'type' => 'integer', 'single' => true, 'show_in_rest' => true, ] ); add_action( 'rest_insert_' . $post_type, [ $this, 'set_or_remove_ngg_post_thumbnail' ], PHP_INT_MAX - 1, 2 ); }, get_post_types_by_support( 'thumbnail' ) ); }, 11 ); } public function ngg_enqueue_block_assets() { // Check if we are in the admin area. if ( is_admin() ) { // Get the current screen. $current_screen = get_current_screen(); // Check if we are in the Block Editor or the Site Editor. if ( $current_screen && ( $current_screen->is_block_editor() || $current_screen->id === 'site-editor' ) ) { \wp_enqueue_script( 'nextgen-block-js', StaticAssets::get_url( 'IGW/Block/build/block.min.js', 'photocrati-nextgen_block#build/block.min.js' ), [ 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-compose' ], NGG_SCRIPT_VERSION, true ); \wp_localize_script( 'nextgen-block-js', 'add_ngg_gallery_block_i18n', [ 'edit' => \__( 'Edit', 'nggallery' ), 'delete' => \__( 'Delete', 'nggallery' ), 'create' => \__( 'Add NextGEN Gallery', 'nggallery' ), 'h3' => \__( 'NextGEN Gallery', 'nggallery' ), 'nonce' => \wp_create_nonce( 'ngg_attach_to_post_iframe' ), ] ); \wp_enqueue_style( 'nextgen-block-css', StaticAssets::get_url( 'IGW/Block/editor.css', 'photocrati-nextgen_block#editor.css' ), [ 'wp-edit-blocks' ], NGG_SCRIPT_VERSION ); } } } public function set_or_remove_ngg_post_thumbnail( $post, $request ) { $json = @json_decode( $request->get_body() ); $target = null; if ( ! is_object( $json ) ) { return; } // WordPress 5.3 changed how the featured-image metadata was submitted to the server. if ( isset( $json->meta ) && property_exists( $json->meta, 'ngg_post_thumbnail' ) ) { $target = $json->meta; } elseif ( property_exists( $json, 'ngg_post_thumbnail' ) ) { $target = $json; } if ( ! $target ) { return; } if( 0 === $target->ngg_post_thumbnail) { // Thumbnail ID is zero, skip deleting. return; } $storage = StorageManager::get_instance(); // Was the post thumbnail removed? if ( ! $target->ngg_post_thumbnail ) { \delete_post_thumbnail( $post->ID ); $storage->delete_from_media_library( $target->ngg_post_thumbnail ); } else { // Was it added? $storage->set_post_thumbnail( $post->ID, $target->ngg_post_thumbnail ); } } public function enqueue_post_thumbnails() { \add_thickbox(); \wp_enqueue_script( 'ngg-post-thumbnails', StaticAssets::get_url( 'IGW/Block/build/post-thumbnail.min.js', 'photocrati-nextgen_block#build/post-thumbnail.min.js' ), [ 'lodash', 'wp-element', 'wp-data', 'wp-editor', 'wp-components', 'wp-i18n', 'photocrati_ajax' ], NGG_SCRIPT_VERSION ); $nonce = \wp_create_nonce( 'ngg_set_post_thumbnails' ); \wp_localize_script( 'ngg-post-thumbnails', 'ngg_featured_image', [ 'modal_url' => \admin_url( "/media-upload.php?nonce={$nonce}&post_id=%post_id%&type=image&tab=nextgen&from=block-editor&TB_iframe=true" ), ] ); // Nonce verification is not necessary: this injects some extra CSS on the add/edit page/post page. // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( preg_match( '/media-upload\.php/', $_SERVER['REQUEST_URI'] ) && 'nextgen' === $_GET['tab'] ) { \wp_add_inline_style( 'wp-admin', '#media-upload-header {display: none; }' ); if ( isset( $_GET['from'] ) && 'block-editor' === sanitize_text_field( wp_unslash( $_GET['from'] ) ) ) { \add_action( 'admin_enqueue_scripts', [ $this, 'media_upload_footer' ] ); } } // phpcs:enable WordPress.Security.NonceVerification.Recommended } public function media_upload_footer() { \wp_add_inline_script( 'image-edit', 'window.NGGSetAsThumbnail = top.set_ngg_post_thumbnail' ); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������IGW/ATPManager.php����������������������������������������������������������������������������������0000644�����������������00000030740�15021223045�0007620 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\IGW; use Imagely\NGG\DataMappers\DisplayedGallery as DisplayedGalleryMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\Display\{DisplayManager, StaticAssets, View}; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\{Security, URL}; class ATPManager { public $attach_to_post_tinymce_plugin = 'NextGEN_AttachToPost'; public static $substitute_placeholders = true; protected static $instance = null; public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new ATPManager(); } return self::$instance; } public static function is_atp_url() { return strpos( strtolower( $_SERVER['REQUEST_URI'] ), NGG_ATTACH_TO_POST_SLUG ) !== false; } public function register_hooks() { add_filter( 'wpseo_opengraph_image', [ $this, 'hide_preview_image_from_yoast' ] ); add_filter( 'wpseo_twitter_image', [ $this, 'hide_preview_image_from_yoast' ] ); add_filter( 'wpseo_sitemap_urlimages', [ $this, 'remove_preview_images_from_yoast_sitemap' ], null, 2 ); // Admin-only hooks. if ( is_admin() ) { add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_static_resources' ], -100 ); // Elementor's editor.php runs `new \WP_Scripts()` which requires we enqueue scripts on both // admin_enqueue_scripts and this action if we want our resources to be used with the page builder. add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'enqueue_static_resources' ] ); add_action( 'media_buttons', [ $this, 'add_media_button' ], 15 ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_tinymce_resources' ] ); add_filter( 'mce_buttons', [ $this, 'add_attach_to_post_button' ] ); add_filter( 'mce_external_plugins', [ $this, 'add_attach_to_post_tinymce_plugin' ] ); add_filter( 'wp_mce_translation', [ $this, 'add_attach_to_post_tinymce_i18n' ] ); add_action( 'admin_print_scripts', [ $this, 'print_tinymce_placeholder_template' ] ); add_action( 'admin_init', [ $this, 'route_insert_gallery_window' ] ); } // Add hook to substitute displayed gallery placeholders. if ( ! is_admin() ) { add_filter( 'the_content', [ $this, 'substitute_placeholder_imgs' ], PHP_INT_MAX, 1 ); } } /** * Route the IGW requests using wp-admin */ function route_insert_gallery_window() { if ( isset( $_REQUEST[ NGG_ATTACH_TO_POST_SLUG ] ) && isset( $_REQUEST['nonce'] ) && \wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'ngg_attach_to_post_iframe' ) ) { print ( new Controller() )->index_action(); exit(); } } /** * Renders the underscore template used by TinyMCE for IGW placeholders */ public function print_tinymce_placeholder_template() { $view = new View( 'AttachToPost/tinymce_placeholder', [], 'photocrati-attach_to_post#tinymce_placeholder' ); $template = $view->find_template_abspath( 'AttachToPost/tinymce_placeholder', 'photocrati-attach_to_post#tinymce_placeholder' ); readfile( $template ); } /** * Prevents ATP preview image placeholders from being used as opengraph / twitter metadata * * @param string $image * @return null|string */ public function hide_preview_image_from_yoast( $image ) { if ( strpos( $image, NGG_ATTACH_TO_POST_SLUG ) !== false ) { return null; } return $image; } /** * Removes IGW preview/placeholder images from Yoast's sitemap * * @param $images * @param $post_id * @return array */ public function remove_preview_images_from_yoast_sitemap( $images, $post_id ) { $retval = []; foreach ( $images as $image ) { if ( strpos( $image['src'], NGG_ATTACH_TO_POST_SLUG ) === false ) { $retval[] = $image; } else { // Lookup images for the displayed gallery. if ( preg_match( '/(\d+)$/', $image['src'], $match ) ) { $displayed_gallery_id = $match[1]; $mapper = DisplayedGalleryMapper::get_instance(); $displayed_gallery = $mapper->find( $displayed_gallery_id, true ); if ( $displayed_gallery ) { $gallery_storage = StorageManager::get_instance(); $settings = Settings::get_instance(); $source_obj = $displayed_gallery->get_source(); if ( in_array( 'image', $source_obj->returns ) ) { foreach ( $displayed_gallery->get_entities() as $image ) { $named_image_size = $settings->get( 'imgAutoResize' ) ? 'full' : 'thumb'; $sitemap_image = [ 'src' => $gallery_storage->get_image_url( $image, $named_image_size ), 'alt' => $image->alttext, 'title' => $image->description ? $image->description : $image->alttext, ]; $retval[] = $sitemap_image; } } } } } } return $retval; } /** * In 2.0.66.X and earlier, ATP placeholder images used a different url than what 2.0.69 uses and must be converted. * * @param string $content * @return string */ public function fix_preview_images( $content ) { $content = str_replace( site_url( '/' . NGG_ATTACH_TO_POST_SLUG . '/preview/id--' ), admin_url( '/?' . NGG_ATTACH_TO_POST_SLUG . '=' . NGG_ATTACH_TO_POST_SLUG . '/preview/id--' ), $content ); $content = str_replace( site_url( '/index.php/' . NGG_ATTACH_TO_POST_SLUG . '/preview/id--' ), admin_url( '/?' . NGG_ATTACH_TO_POST_SLUG . '=' . NGG_ATTACH_TO_POST_SLUG . '/preview/id--' ), $content ); return $content; } public function add_media_button() { $search = [ Security::is_allowed( 'NextGEN Attach Interface' ), Security::is_allowed( 'NextGEN Use TinyMCE' ), ]; if ( in_array( false, $search ) ) { return; } $button_url = StaticAssets::get_url( 'AttachToPost/igw_button.png', 'photocrati-attach_to_post#igw_button.png' ); $label = \__( 'Add Gallery', 'nggallery' ); $igw_url = admin_url( '/?' . NGG_ATTACH_TO_POST_SLUG . '=1' ); $igw_url .= '&nonce=' . \wp_create_nonce( 'ngg_attach_to_post_iframe' ); $igw_url .= '&KeepThis=true&TB_iframe=true&height=600&width=1000'; printf( '<a href="%s" data-editor="content" class="button ngg-add-gallery thickbox" id="ngg-media-button" class="button" ><img src="%s" style="padding:0 4px 0 0; margin-left: -2px; margin-top:-3px; max-width: 20px;">%s</a>', $igw_url, $button_url, $label ); } /** * Substitutes the gallery placeholder content with the gallery type frontend * view, returns a list of static resources that need to be loaded * * @param string $content */ public function substitute_placeholder_imgs( $content ) { $content = $this->fix_preview_images( $content ); // To match ATP entries we compare the stored url against a generic path; entries MUST have a gallery ID. if ( preg_match_all( '#<img.*http(s)?://(.*)?' . NGG_ATTACH_TO_POST_SLUG . '(=|/)preview(/|&|&)id(=|--)(\\d+).*?>#mi', $content, $matches, PREG_SET_ORDER ) ) { $mapper = DisplayedGalleryMapper::get_instance(); foreach ( $matches as $match ) { // Find the displayed gallery. $displayed_gallery_id = $match[6]; $displayed_gallery = $mapper->find( $displayed_gallery_id, true ); // Get the content for the displayed gallery. $retval = '<p>' . _( 'Invalid Displayed Gallery' ) . '</p>'; if ( $displayed_gallery ) { $retval = ''; $renderer = Renderer::get_instance(); if ( defined( 'NGG_SHOW_DISPLAYED_GALLERY_ERRORS' ) && NGG_SHOW_DISPLAYED_GALLERY_ERRORS && ! $displayed_gallery->is_valid() ) { $retval .= var_export( $displayed_gallery->validation(), true ); } if ( self::$substitute_placeholders ) { $retval .= $renderer->render( $displayed_gallery, true ); } } $content = str_replace( $match[0], $retval, $content ); } } return $content; } /** * Enqueues static resources required by the Attach-To-Post interface */ public function enqueue_static_resources() { // Enqueue resources needed at post/page level. if ( $this->is_new_or_edit_post_screen() ) { \wp_enqueue_script( 'nextgen_admin_js' ); \wp_enqueue_style( 'nextgen_admin_css' ); \wp_enqueue_script( 'frame_event_publisher' ); DisplayManager::enqueue_fontawesome(); \wp_register_script( 'Base64', StaticAssets::get_url( 'AttachToPost/base64.js', 'photocrati-attach_to_post#base64.js' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'ngg_attach_to_post_dialog', StaticAssets::get_url( 'AttachToPost/attach_to_post_dialog.css', 'photocrati-attach_to_post#attach_to_post_dialog.css' ), [ 'gritter' ], NGG_SCRIPT_VERSION ); \wp_enqueue_script( 'ngg-igw', StaticAssets::get_url( 'AttachToPost/igw.js', 'photocrati-attach_to_post#igw.js' ), [ 'jquery', 'Base64', 'gritter' ], NGG_SCRIPT_VERSION ); \wp_localize_script( 'ngg-igw', 'ngg_igw_i18n', [ 'nextgen_gallery' => \__( 'NextGEN Gallery', 'nggallery' ), 'edit' => \__( 'Edit', 'nggallery' ), 'remove' => \__( 'Delete', 'nggallery' ), ] ); // Nonce verification is not necessary here: we are only enqueueing resources for the IGW iframe children. // phpcs:disable WordPress.Security.NonceVerification.Recommended } elseif ( isset( $_REQUEST['attach_to_post'] ) || isset( $_REQUEST['nextgen-attach_to_post'] ) || ( isset( $_REQUEST['page'] ) && false !== strpos( $_REQUEST['page'], 'nggallery' ) ) ) { // phpcs:enable WordPress.Security.NonceVerification.Recommended \wp_enqueue_script( 'iframely', StaticAssets::get_url( 'AttachToPost/iframely.js', 'photocrati-attach_to_post#iframely.js' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'iframely', StaticAssets::get_url( 'AttachToPost/iframely.css', 'photocrati-attach_to_post#iframely.css' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'nextgen_addgallery_page' ); \wp_enqueue_style( 'ngg_marketing_blocks_style' ); \wp_enqueue_style( 'uppy' ); \wp_enqueue_script( 'nextgen_admin_js' ); \wp_enqueue_style( 'nextgen_admin_css' ); } } public function is_new_or_edit_post_screen() { return preg_match( '/\/wp-admin\/(post|post-new|site-editor)\.php$/', $_SERVER['SCRIPT_NAME'] ); } public function can_use_tinymce() { $checks = [ Security::is_allowed( 'NextGEN Attach Interface' ), Security::is_allowed( 'NextGEN Use TinyMCE' ), \get_user_option( 'rich_editing' ) == 'true', ]; return ! in_array( false, $checks ); } /** * Enqueues resources needed by the TinyMCE editor */ public function enqueue_tinymce_resources() { if ( $this->is_new_or_edit_post_screen() ) { \add_editor_style( 'https://fonts.googleapis.com/css?family=Lato' ); \add_editor_style( StaticAssets::get_url( 'AttachToPost/ngg_attach_to_post_tinymce_plugin.css', 'photocrati-attach_to_post#ngg_attach_to_post_tinymce_plugin.css' ) ); \wp_enqueue_script( 'photocrati_ajax' ); \wp_localize_script( 'media-editor', 'igw', [ 'url' => \admin_url( '/?' . NGG_ATTACH_TO_POST_SLUG . '=1' ), ] ); \wp_localize_script( 'photocrati_ajax', 'ngg_tinymce_plugin', [ 'url' => add_query_arg( 'ver', NGG_SCRIPT_VERSION, StaticAssets::get_url( 'AttachToPost/ngg_attach_to_post_tinymce_plugin.js', 'photocrati-attach_to_post#ngg_attach_to_post_tinymce_plugin.js' ) ), 'i18n' => [ 'button_label' => \__( 'Add NextGEN Gallery', 'nggallery' ), ], 'name' => $this->attach_to_post_tinymce_plugin, 'nonce' => \wp_create_nonce( 'ngg_attach_to_post_iframe' ), ] ); } } /** * Adds a TinyMCE button for the Attach To Post plugin * * @param array $buttons * @return array */ public function add_attach_to_post_button( $buttons ) { if ( $this->can_use_tinymce() ) { array_push( $buttons, 'separator', $this->attach_to_post_tinymce_plugin ); } return $buttons; } /** * Adds the Attach To Post TinyMCE plugin * * @param array $plugins * @return array * @uses mce_external_plugins filter */ public function add_attach_to_post_tinymce_plugin( $plugins ) { if ( $this->can_use_tinymce() ) { $plugins[ $this->attach_to_post_tinymce_plugin ] = \add_query_arg( 'ver', NGG_SCRIPT_VERSION, StaticAssets::get_url( 'AttachToPost/ngg_attach_to_post_tinymce_plugin.js', 'photocrati-attach_to_post#ngg_attach_to_post_tinymce_plugin.js' ) ); } return $plugins; } /** * Adds the Attach To Post TinyMCE i18n strings * * @param $mce_translation * @return mixed */ public function add_attach_to_post_tinymce_i18n( $mce_translation ) { $mce_translation['ngg_attach_to_post.title'] = \__( 'Attach NextGEN Gallery to Post', 'nggallery' ); return $mce_translation; } } ��������������������������������Widget/MediaRSS.php���������������������������������������������������������������������������������0000644�����������������00000006744�15021223045�0010114 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Widget; use Imagely\NGG\Display\View; use Imagely\NGG\Settings\Settings; class MediaRSS extends \WP_Widget { public $options; public function __construct() { $widget_ops = [ 'classname' => 'ngg_mrssw', 'description' => \__( 'Widget that displays Media RSS links for NextGEN Gallery.', 'nggallery' ), ]; parent::__construct( 'ngg-mrssw', \__( 'NextGEN Media RSS', 'nggallery' ), $widget_ops ); } /** * @param array $instance */ public function form( $instance ) { // Default settings. $instance = \wp_parse_args( (array) $instance, [ 'mrss_text' => \__( 'Media RSS', 'nggallery' ), 'mrss_title' => \__( 'Link to the main image feed', 'nggallery' ), 'show_global_mrss' => true, 'show_icon' => true, 'title' => 'Media RSS', ] ); $view = new View( 'Widget/Form/MediaRSS', [ 'self' => $this, 'instance' => $instance, 'title' => \esc_attr( $instance['title'] ), 'mrss_text' => \esc_attr( $instance['mrss_text'] ), 'mrss_title' => \esc_attr( $instance['mrss_title'] ), ], 'photocrati-widget#form_mediarss' ); return $view->render(); } /** * @param array $new_instance * @param array $old_instance * @return array */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; $instance['title'] = esc_attr( $new_instance['title'] ); $instance['show_global_mrss'] = $new_instance['show_global_mrss']; $instance['show_icon'] = $new_instance['show_icon']; $instance['mrss_text'] = esc_attr( $new_instance['mrss_text'] ); $instance['mrss_title'] = esc_attr( $new_instance['mrss_title'] ); return $instance; } /** * @param array $args * @param array $instance */ public function widget( $args, $instance ) { // these are handled by extract() but I want to silence my IDE warnings that these vars don't exist. $before_widget = null; $before_title = null; $after_widget = null; $after_title = null; $widget_id = null; \extract( $args ); $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? ' ' : $instance['title'], $instance, $this->id_base ); $view = new View( 'Widget/Display/MediaRSS', [ 'self' => $this, 'instance' => $instance, 'title' => $title, 'settings' => Settings::get_instance(), 'before_widget' => $before_widget, 'before_title' => $before_title, 'after_widget' => $after_widget, 'after_title' => $after_title, 'widget_id' => $widget_id, ], 'photocrati-widget#display_mediarss' ); $view->render(); } /** * @param $mrss_url * @param bool $show_icon * @param string $title * @param string $text * @return string */ public function get_mrss_link( $mrss_url, $show_icon = true, $title = '', $text = '' ) { $out = ''; if ( $show_icon ) { $icon_url = NGGALLERY_URLPATH . 'images/mrss-icon.gif'; $out .= "<a href='". \esc_url( $mrss_url ) ."' title='" . \esc_attr( $title ) . "' class='ngg-media-rss-link'>"; $out .= "<img src='". \esc_url( $icon_url ) ."' alt='MediaRSS Icon' title='" . \esc_attr( $title ) . "' class='ngg-media-rss-icon' />"; $out .= '</a> '; } if ( '' !== $text ) { $out .= "<a href='". \esc_url( $mrss_url ) ."' title='" . \esc_attr( $title ) . "' class='ngg-media-rss-link'>"; $out .= \esc_attr( $text ); $out .= '</a>'; } return $out; } } ����������������������������Widget/Slideshow.php��������������������������������������������������������������������������������0000644�����������������00000017203�15021223045�0010436 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Widget; use Imagely\NGG\DisplayTypes\Slideshow as SlideshowController; use Imagely\NGG\DataTypes\DisplayedGallery; use Imagely\NGG\Display\DisplayManager; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\StaticPopeAssets; use Imagely\NGG\Display\View; use Imagely\NGG\DisplayedGallery\Renderer; class Slideshow extends \WP_Widget { protected static $displayed_gallery_ids = []; public function __construct() { $widget_ops = [ 'classname' => 'widget_slideshow', 'description' => \__( 'Show a NextGEN Gallery Slideshow', 'nggallery' ), ]; parent::__construct( 'slideshow', \__( 'NextGEN Slideshow', 'nggallery' ), $widget_ops ); // Determine what widgets will exist in the future, create their displayed galleries, enqueue their resources, // and cache the resulting displayed gallery for later rendering to avoid the ID changing due to misc attributes // in $args being different now and at render time ($args is sidebar information that is not relevant). \add_action( 'wp_enqueue_scripts', function () { // Prevent enqueueing resources if the widget is not in use. if ( ! is_active_widget( false, false, 'slideshow', true ) ) { return; } global $wp_registered_sidebars; $sidebars = \wp_get_sidebars_widgets(); $options = $this->get_settings(); foreach ( $sidebars as $sidebar_name => $sidebar ) { if ( 'wp_inactive_widgets' === $sidebar_name || ! $sidebar ) { continue; } foreach ( $sidebar as $widget ) { if ( \strpos( $widget, 'slideshow-', 0 ) !== 0 ) { continue; } $id = \str_replace( 'slideshow-', '', $widget ); if ( isset( $options[ $id ] ) ) { $sidebar_data = $wp_registered_sidebars[ $sidebar_name ]; $sidebar_data['widget_id'] = $widget; // These are normally replaced at display time but we're building our cache before then. $sidebar_data['before_widget'] = \str_replace( '%1$s', $widget, $sidebar_data['before_widget'] ); $sidebar_data['before_widget'] = \str_replace( '%2$s', 'widget_slideshow', $sidebar_data['before_widget'] ); $sidebar_data['widget_name'] = \__( 'NextGEN Slideshow', 'nggallery' ); $displayed_gallery = $this->get_displayed_gallery( $sidebar_data, $options[ $id ] ); self::$displayed_gallery_ids[ $widget ] = $displayed_gallery; $controller = new SlideshowController(); DisplayManager::enqueue_frontend_resources_for_displayed_gallery( $displayed_gallery, $controller ); } } } \wp_enqueue_style( 'nextgen_widgets_style', StaticAssets::get_url( 'Widget/display.css', 'photocrati-widget#widgets.css' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'nextgen_basic_slideshow_style', StaticPopeAssets::get_url( 'Slideshow/ngg_basic_slideshow.css', 'photocrati-nextgen_basic_gallery#slideshow/ngg_basic_slideshow.css' ), [], NGG_SCRIPT_VERSION ); }, 11 ); } /** * @param array $args * @param array $instance * @return DisplayedGallery $displayed_gallery */ public function get_displayed_gallery( $args, $instance ) { if ( empty( $instance['limit'] ) ) { $instance['limit'] = 10; } $params = [ 'container_ids' => $instance['galleryid'], 'display_type' => 'photocrati-nextgen_basic_slideshow', 'gallery_width' => $instance['width'], 'gallery_height' => $instance['height'], 'source' => 'galleries', 'slug' => 'widget-' . $args['widget_id'], 'entity_types' => [ 'image' ], 'show_thumbnail_link' => false, 'show_slideshow_link' => false, 'use_imagebrowser_effect' => false, // just to be safe. 'ngg_triggers_display' => 'never', ]; if ( 0 === $instance['galleryid'] ) { $params['source'] = 'random_images'; $params['maximum_entity_count'] = $instance['limit']; unset( $params['container_ids'] ); } $displayed_gallery = Renderer::get_instance()->params_to_displayed_gallery( $params ); if ( is_null( $displayed_gallery->id() ) ) { $displayed_gallery->id( \md5( \json_encode( $displayed_gallery->get_entity() ) ) ); } return $displayed_gallery; } /** * @param array $instance */ public function form( $instance ) { global $wpdb; // Default settings. $instance = \wp_parse_args( (array) $instance, [ 'galleryid' => '0', 'height' => '120', 'title' => 'Slideshow', 'width' => '160', 'limit' => '10', ] ); $view = new View( 'Widget/Form/Slideshow', [ 'self' => $this, 'instance' => $instance, 'title' => \esc_attr( $instance['title'] ), 'height' => \esc_attr( $instance['height'] ), 'width' => \esc_attr( $instance['width'] ), 'limit' => \esc_attr( $instance['limit'] ), 'tables' => $wpdb->get_results( "SELECT * FROM {$wpdb->nggallery} ORDER BY 'name' ASC" ), ], 'photocrati-widget#form_slideshow' ); return $view->render(); } /** * @param array $new_instance * @param array $old_instance * @return array */ public function update( $new_instance, $old_instance ) { $nh = $new_instance['height']; $nw = $new_instance['width']; if ( empty( $nh ) || 0 === (int) $nh ) { $new_instance['height'] = 120; } if ( empty( $nw ) || 0 === (int) $nw ) { $new_instance['width'] = 160; } if ( empty( $new_instance['limit'] ) ) { $new_instance['limit'] = 10; } $instance = $old_instance; $instance['title'] = esc_attr( $new_instance['title'] ); $instance['galleryid'] = (int) $new_instance['galleryid']; $instance['height'] = (int) $new_instance['height']; $instance['width'] = (int) $new_instance['width']; $instance['limit'] = (int) $new_instance['limit']; return $instance; } /** * @param array $args * @param array $instance */ public function widget( $args, $instance ) { // these are handled by extract() but I want to silence my IDE warnings that these vars don't exist. $before_widget = null; $before_title = null; $after_widget = null; $after_title = null; $widget_id = null; \extract( $args ); $title = \apply_filters( 'widget_title', empty( $instance['title'] ) ? \__( 'Slideshow', 'nggallery' ) : $instance['title'], $instance, $this->id_base ); $view = new View( 'Widget/Display/Slideshow', [ 'self' => $this, 'instance' => $instance, 'title' => $title, 'out' => $this->render_slideshow( $args, $instance ), 'before_widget' => $before_widget, 'before_title' => $before_title, 'after_widget' => $after_widget, 'after_title' => $after_title, 'widget_id' => $widget_id, ], 'photocrati-widget#display_slideshow' ); $view->render(); } /** * @param $args * @param $instance * @return string */ public function render_slideshow( $args, $instance ) { // This displayed gallery is created dynamically at runtime. if ( empty( self::$displayed_gallery_ids[ $args['widget_id'] ] ) ) { $displayed_gallery = $this->get_displayed_gallery( $args, $instance ); self::$displayed_gallery_ids[ $displayed_gallery->id() ] = $displayed_gallery; } else { // The displayed gallery was created during the action wp_enqueue_resources and was cached to avoid ID conflicts. $displayed_gallery = self::$displayed_gallery_ids[ $args['widget_id'] ]; } return \apply_filters( 'ngg_show_slideshow_widget_content', Renderer::get_instance()->display_images( $displayed_gallery ), $instance['galleryid'], $instance['width'], $instance['height'] ); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Widget/Gallery.php����������������������������������������������������������������������������������0000644�����������������00000026231�15021223045�0010075 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Widget; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DisplayTypes\Thumbnails; use Imagely\NGG\Display\DisplayManager; use Imagely\NGG\Display\StaticAssets; use Imagely\NGG\Display\StaticPopeAssets; use Imagely\NGG\Display\View; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Transient; class Gallery extends \WP_Widget { protected static $displayed_gallery_ids = []; public function __construct() { $widget_ops = [ 'classname' => 'ngg_images', 'description' => \__( 'Add recent or random images from the galleries', 'nggallery' ), ]; parent::__construct( 'ngg-images', \__( 'NextGEN Widget', 'nggallery' ), $widget_ops ); // Determine what widgets will exist in the future, create their displayed galleries, enqueue their resources, // and cache the resulting displayed gallery for later rendering to avoid the ID changing due to misc attributes // in $args being different now and at render time ($args is sidebar information that is not relevant). \add_action( 'wp_enqueue_scripts', function () { // Prevent enqueueing resources if the widget is not in use. if ( ! is_active_widget( false, false, 'ngg-images', true ) ) { return; } global $wp_registered_sidebars; $sidebars = \wp_get_sidebars_widgets(); $options = $this->get_settings(); foreach ( $sidebars as $sidebar_name => $sidebar ) { if ( $sidebar_name === 'wp_inactive_widgets' || ! $sidebar ) { continue; } foreach ( $sidebar as $widget ) { if ( \strpos( $widget, 'ngg-images-', 0 ) !== 0 ) { continue; } $id = \str_replace( 'ngg-images-', '', $widget ); if ( isset( $options[ $id ] ) ) { $sidebar_data = $wp_registered_sidebars[ $sidebar_name ]; $sidebar_data['widget_id'] = $widget; // These are normally replaced at display time but we're building our cache before then. $sidebar_data['before_widget'] = \str_replace( '%1$s', $widget, $sidebar_data['before_widget'] ); $sidebar_data['before_widget'] = \str_replace( '%2$s', 'ngg_images', $sidebar_data['before_widget'] ); $sidebar_data['widget_name'] = \__( 'NextGEN Widget', 'nggallery' ); $displayed_gallery = $this->get_displayed_gallery( $sidebar_data, $options[ $id ] ); self::$displayed_gallery_ids[ $widget ] = $displayed_gallery; $controller = new Thumbnails(); DisplayManager::enqueue_frontend_resources_for_displayed_gallery( $displayed_gallery, $controller ); } } } // Now enqueue the basic styling for the display itself. \wp_enqueue_style( 'nextgen_widgets_style', StaticAssets::get_url( 'Widget/display.css', 'photocrati-widget#widgets.css' ), [], NGG_SCRIPT_VERSION ); \wp_enqueue_style( 'nextgen_basic_thumbnails_style', StaticPopeAssets::get_url( 'Thumbnails/nextgen_basic_thumbnails.css', 'photocrati-nextgen_basic_gallery#thumbnails/nextgen_basic_thumbnails.css' ), [], NGG_SCRIPT_VERSION ); }, 11 ); // It is important that this run at priority 11 or higher so that M_Gallery_Display->enqueue_frontend_resources() has run first. } /** * @return array */ public function get_defaults() { return [ 'exclude' => 'all', 'height' => '75', 'items' => '4', 'list' => '', 'show' => 'thumbnail', 'title' => 'Gallery', 'type' => 'recent', 'webslice' => true, 'width' => '100', ]; } /** * @param array $instance */ public function form( $instance ) { // defaults. $instance = \wp_parse_args( (array) $instance, $this->get_defaults() ); $view = new View( 'Widget/Form/Gallery', [ 'self' => $this, 'instance' => $instance, 'title' => \esc_attr( $instance['title'] ), 'items' => \intval( $instance['items'] ), 'height' => \esc_attr( $instance['height'] ), 'width' => \esc_attr( $instance['width'] ), ], 'photocrati-widget#form_gallery' ); return $view->render(); } /** * @param array $new_instance * @param array $old_instance * @return array */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; // do not allow 0 or less. if ( (int) $new_instance['items'] <= 0 ) { $new_instance['items'] = 4; } // for clarity: empty the list if we're showing every gallery anyway. if ( $new_instance['exclude'] == 'all' ) { $new_instance['list'] = ''; } // remove gallery ids that do not exist. if ( \in_array( $new_instance['exclude'], [ 'denied', 'allow' ] ) ) { // do search. $mapper = GalleryMapper::get_instance(); $ids = \explode( ',', $new_instance['list'] ); foreach ( $ids as $ndx => $id ) { if ( ! $mapper->find( $id ) ) { unset( $ids[ $ndx ] ); } } $new_instance['list'] = \implode( ',', $ids ); } // reset to show all galleries IF there are no valid galleries in the list. if ( $new_instance['exclude'] !== 'all' && empty( $new_instance['list'] ) ) { $new_instance['exclude'] = 'all'; } $instance['title'] = \esc_attr( $new_instance['title'] ); $instance['items'] = (int) $new_instance['items']; $instance['type'] = $new_instance['type']; $instance['show'] = $new_instance['show']; $instance['width'] = (int) $new_instance['width']; $instance['height'] = (int) $new_instance['height']; $instance['exclude'] = $new_instance['exclude']; $instance['list'] = $new_instance['list']; $instance['webslice'] = (bool) $new_instance['webslice']; return $instance; } /** * @param array $args * @param array $instance * @return \Imagely\NGG\DataTypes\DisplayedGallery $displayed_gallery */ public function get_displayed_gallery( $args, $instance ) { $settings = Settings::get_instance(); // these are handled by extract() but I want to silence my IDE warnings that these vars don't exist. $before_widget = null; $before_title = null; $after_widget = null; $after_title = null; $widget_id = null; \extract( $args ); $title = \apply_filters( 'widget_title', empty( $instance['title'] ) ? ' ' : $instance['title'], $instance, $this->id_base ); // Used later. $renderer = Renderer::get_instance(); $view = new View( 'Widget/Display/Gallery', [], 'photocrati-widget#display_gallery' ); // IE8 webslice support if needed. if ( ! empty( $instance['webslice'] ) ) { $before_widget .= '<div class="hslice" id="ngg-webslice">'; $before_title = \str_replace( 'class="', 'class="entry-title ', $before_title ); $after_widget = '</div>' . $after_widget; } $source = ( $instance['type'] == 'random' ? 'random_images' : 'recent' ); $template = ! empty( $instance['template'] ) ? $instance['template'] : $view->find_template_abspath( 'Widget/Display/Gallery', 'photocrati-widget#display_gallery' ); $params = [ 'slug' => 'widget-' . $args['widget_id'], 'source' => $source, 'display_type' => NGG_BASIC_THUMBNAILS, 'images_per_page' => $instance['items'], 'maximum_entity_count' => $instance['items'], 'template' => $template, 'image_type' => $instance['show'] == 'original' ? 'full' : 'thumb', 'show_all_in_lightbox' => false, 'show_slideshow_link' => false, 'show_thumbnail_link' => false, 'use_imagebrowser_effect' => false, 'disable_pagination' => true, 'image_width' => $instance['width'], 'image_height' => $instance['height'], 'ngg_triggers_display' => 'never', 'widget_setting_title' => $title, 'widget_setting_before_widget' => $before_widget, 'widget_setting_before_title' => $before_title, 'widget_setting_after_widget' => $after_widget, 'widget_setting_after_title' => $after_title, 'widget_setting_width' => $instance['width'], 'widget_setting_height' => $instance['height'], 'widget_setting_show_setting' => $instance['show'], 'widget_setting_widget_id' => $widget_id, ]; switch ( $instance['exclude'] ) { case 'all': break; case 'denied': $mapper = GalleryMapper::get_instance(); $gallery_ids = []; $list = \explode( ',', $instance['list'] ); foreach ( $mapper->find_all() as $gallery ) { if ( ! \in_array( $gallery->{$gallery->id_field}, $list ) ) { $gallery_ids[] = $gallery->{$gallery->id_field}; } } $params['container_ids'] = \implode( ',', $gallery_ids ); break; case 'allow': $params['container_ids'] = $instance['list']; break; } // "Random" galleries are a bit resource intensive when querying the database and widgets are generally // going to be on every page a site may serve. Because the displayed gallery renderer does *NOT* cache the // HTML of random galleries the following is a bit of a workaround: for random widgets we create a displayed // gallery object and then cache the results of get_entities() so that, for at least as long as // NGG_RENDERING_CACHE_TTL seconds, widgets will be temporarily cached. if ( \in_array( $params['source'], [ 'random', 'random_images' ] ) && (float) $settings->get( 'random_widget_cache_ttl' ) > 0 ) { $displayed_gallery = $renderer->params_to_displayed_gallery( $params ); if ( \is_null( $displayed_gallery->id() ) ) { $displayed_gallery->id( \md5( \json_encode( $displayed_gallery->get_entity() ) ) ); } $cache_group = 'random_widget_gallery_ids'; $cache_params = [ $displayed_gallery->get_entity() ]; $transientM = Transient::get_instance(); $key = $transientM->generate_key( $cache_group, $cache_params ); $ids = $transientM->get( $key, false ); if ( ! empty( $ids ) ) { $params['image_ids'] = $ids; } else { $ids = []; foreach ( $displayed_gallery->get_entities( $instance['items'], false, true ) as $item ) { $ids[] = $item->{$item->id_field}; } $params['image_ids'] = \implode( ',', $ids ); $transientM->set( $key, $params['image_ids'], ( (float) $settings->random_widget_cache_ttl * 60 ) ); } $params['source'] = 'images'; unset( $params['container_ids'] ); } $final_displayed_gallery = $renderer->params_to_displayed_gallery( $params ); if ( is_null( $final_displayed_gallery->id() ) ) { $final_displayed_gallery->id( \md5( \json_encode( $final_displayed_gallery->get_entity() ) ) ); } return $final_displayed_gallery; } /** * @param array $args * @param array $instance */ public function widget( $args, $instance ) { // This displayed gallery is created dynamically at runtime. if ( empty( self::$displayed_gallery_ids[ $args['widget_id'] ] ) ) { $displayed_gallery = $this->get_displayed_gallery( $args, $instance ); self::$displayed_gallery_ids[ $displayed_gallery->id() ] = $displayed_gallery; } else { // The displayed gallery was created during the action wp_enqueue_resources and was cached to avoid ID conflicts. $displayed_gallery = self::$displayed_gallery_ids[ $args['widget_id'] ]; } print Renderer::get_instance()->display_images( $displayed_gallery ); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMappers/Image.php�������������������������������������������������������������������������������0000644�����������������00000014655�15021223045�0010505 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMappers; use Imagely\NGG\DataTypes\Gallery as GalleryType; use Imagely\NGG\DataTypes\Image as ImageType; use Imagely\NGG\DataMapper\TableDriver; use Imagely\NGG\Display\I18N; use Imagely\NGG\Util\Transient; class Image extends TableDriver { private static $instance = null; public $model_class = 'Imagely\NGG\DataTypes\Image'; public $primary_key_column = 'pid'; // Necessary for legacy compatibility. public $custom_post_name = 'mixin_nextgen_table_extras'; public function __construct() { $this->define_column( 'alttext', 'TEXT' ); $this->define_column( 'description', 'TEXT' ); $this->define_column( 'exclude', 'INT', 0 ); $this->define_column( 'filename', 'VARCHAR(255)' ); $this->define_column( 'galleryid', 'BIGINT', 0 ); $this->define_column( 'image_slug', 'VARCHAR(255)' ); $this->define_column( 'imagedate', 'DATETIME' ); $this->define_column( 'meta_data', 'TEXT' ); $this->define_column( 'pid', 'BIGINT', 0 ); $this->define_column( 'post_id', 'BIGINT', 0 ); $this->define_column( 'sortorder', 'BIGINT', 0 ); $this->define_column( 'updated_at', 'BIGINT' ); $this->define_column( 'extras_post_id', 'BIGINT', 0 ); $this->add_serialized_column( 'meta_data' ); if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $this->define_column( 'pricelist_id', 'BIGINT', 0, true ); } parent::__construct( 'ngg_pictures' ); } /** * @return Image|\Imagely\NGGPro\Commerce\DataMappers\Image */ static function get_instance() { if ( is_null( self::$instance ) ) { $class = apply_filters( 'ngg_datamapper_client_image', __CLASS__ ); self::$instance = new $class(); } return self::$instance; } /** * @param int|ImageType $entity * @return ImageType */ public function find( $entity ) { /** @var ImageType $result */ $result = parent::find( $entity ); return $result; } /** * @param GalleryType $gallery * @param bool $model * * @return ImageType[] */ public function find_all_for_gallery( $gallery, $model = true ) { $retval = []; $gallery_id = 0; if ( is_object( $gallery ) ) { if ( isset( $gallery->id_field ) ) { $gallery_id = $gallery->{$gallery->id_field}; } else { $key = $this->get_primary_key_column(); if ( isset( $gallery->$key ) ) { $gallery_id = $gallery->$key; } } } elseif ( is_numeric( $gallery ) ) { $gallery_id = $gallery; } if ( $gallery_id ) { $retval = $this->select()->where( [ 'galleryid = %s', $gallery_id ] )->run_query( false, $model ); } return $retval; } public function reimport_metadata( $image_or_id ) { if ( is_int( $image_or_id ) ) { $image = $this->find( $image_or_id ); } else { $image = $image_or_id; } // Reset all image details that would have normally been imported. if ( is_array( $image->meta_data ) ) { unset( $image->meta_data['saved'] ); } \nggAdmin::import_MetaData( $image ); return $this->save( $image ); } /** * @param ImageType $image * @return bool */ public function get_id( $image ) { $retval = false; if ( $image instanceof \stdClass ) { if ( isset( $image->id_field ) ) { $retval = $image->{$image->id_field}; } } else { $retval = $image->id(); } // If we still don't have an id then we find the primary key and try fetching it manually. if ( ! $retval ) { $key = $this->get_primary_key_column(); $retval = $image->$key; } return $retval; } /** * @param ImageType $entity * @return bool */ public function destroy( $entity ) { $retval = parent::destroy( $entity ); // Delete tag associations with the image. if ( ! is_numeric( $entity ) ) { $entity = $entity->{$entity->id_field}; } \wp_delete_object_term_relationships( $entity, 'ngg_tag' ); Transient::flush( 'displayed_gallery_rendering' ); return $retval; } /** * @param ImageType $entity * @return bool|TableDriver */ public function save_entity( $entity ) { $entity->updated_at = time(); $retval = parent::save_entity( $entity ); if ( $retval ) { include_once NGGALLERY_ABSPATH . '/admin/functions.php'; $image_id = $this->get_id( $entity ); if ( ! isset( $entity->meta_data['saved'] ) ) { \nggAdmin::import_MetaData( $image_id ); } Transient::flush( 'displayed_gallery_rendering' ); } return $retval; } /** * @param ImageType $entity * @return string */ public function get_post_title( $entity ) { return $entity->alttext; } public function set_defaults( $entity ) { $this->set_default_value( $entity, 'post_id', 0 ); $this->set_default_value( $entity, 'exclude', 0 ); $this->set_default_value( $entity, 'sortorder', 0 ); $this->set_default_value( $entity, 'description', '' ); $this->set_default_value( $entity, 'alttext', '' ); if ( ( ! isset( $entity->imagedate ) ) || $entity->imagedate == '0000-00-00 00:00:00' ) { $entity->imagedate = date( 'Y-m-d H:i:s' ); } // If a filename is set and no 'alttext' is set; then set the 'alttext' to the basename of the filename. if ( isset( $entity->filename ) ) { $path_parts = I18N::mb_pathinfo( $entity->filename ); $alttext = ( ! isset( $path_parts['filename'] ) ) ? substr( $path_parts['basename'], 0, strpos( $path_parts['basename'], '.' ) ) : $path_parts['filename']; $this->set_default_value( $entity, 'alttext', $alttext ); } if ( ! empty( $entity->alttext ) && empty( $entity->image_slug ) ) { $entity->image_slug = \nggdb::get_unique_slug( \sanitize_title_with_dashes( $entity->alttext ), 'image' ); } // Ensure that the exclude parameter is an integer or boolean-evaluated value. if ( is_string( $entity->exclude ) ) { $entity->exclude = intval( $entity->exclude ); } $entity->description = trim( $entity->description ); $entity->alttext = trim( $entity->alttext ); if ( ! is_admin() && ! empty( $entity->{$entity->id_field} ) ) { if ( ! empty( $entity->description ) ) { $entity->description = I18N::translate( $entity->description, 'pic_' . $entity->{$entity->id_field} . '_description' ); } if ( ! empty( $entity->alttext ) ) { $entity->alttext = I18N::translate( $entity->alttext, 'pic_' . $entity->{$entity->id_field} . '_alttext' ); } } } /** * @param string $value * @return mixed|null * @throws \Exception * @deprecated * @todo Remove this when the minimum Pro API level is 4.0 or higher. */ public function unserialize( string $value ) { return \Imagely\NGG\Util\Serializable::unserialize( $value ); } } �����������������������������������������������������������������������������������DataMappers/DisplayedGallery.php��������������������������������������������������������������������0000644�����������������00000004031�15021223045�0012704 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMappers; use Imagely\NGG\DataMapper\WPPostDriver; use Imagely\NGG\DataMappers\DisplayType as DisplayTypeMapper; use Imagely\NGG\Settings\Settings; class DisplayedGallery extends WPPostDriver { protected static $instance = null; public $model_class = 'Imagely\NGG\DataTypes\DisplayedGallery'; public function __construct() { parent::__construct( 'displayed_gallery' ); } /** * @return DisplayedGallery */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new DisplayedGallery(); } return self::$instance; } /** * @param \Imagely\NGG\DataTypes\DisplayedGallery $entity * @return null|\Imagely\NGG\DataTypes\DisplayType */ public function get_display_type( $entity ) { $mapper = DisplayTypeMapper::get_instance(); return $mapper->find_by_name( $entity->display_type ); } public function has_method( $name ) { return method_exists( $this, $name ); } /** * Sets defaults needed for the entity * * @param \Imagely\NGG\DataTypes\DisplayedGallery $entity */ public function set_defaults( $entity ) { // Ensure that we have a settings array. if ( ! isset( $entity->display_settings ) ) { $entity->display_settings = []; } // Default ordering. $settings = Settings::get_instance(); $this->set_default_value( $entity, 'order_by', $settings->get( 'galSort' ) ); $this->set_default_value( $entity, 'order_direction', $settings->get( 'galSortDir' ) ); // Ensure we have an exclusions array. $this->set_default_value( $entity, 'exclusions', [] ); // Ensure other properties exist. $this->set_default_value( $entity, 'container_ids', [] ); $this->set_default_value( $entity, 'excluded_container_ids', [] ); $this->set_default_value( $entity, 'sortorder', [] ); $this->set_default_value( $entity, 'entity_ids', [] ); $this->set_default_value( $entity, 'returns', 'included' ); // Set maximum_entity_count. $this->set_default_value( $entity, 'maximum_entity_count', $settings->get( 'maximum_entity_count' ) ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMappers/DisplayType.php�������������������������������������������������������������������������0000644�����������������00000007153�15021223045�0011725 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMappers; use Imagely\NGG\DataMapper\WPPostDriver; use Imagely\NGG\DisplayType\ControllerFactory; class DisplayType extends WPPostDriver { public static $instance; public $model_class = 'Imagely\NGG\DataTypes\DisplayType'; public function __construct() { // Define columns. $this->define_column( 'ID', 'BIGINT', 0 ); $this->define_column( 'default_source', 'VARCHAR(255)' ); $this->define_column( 'name', 'VARCHAR(255)' ); $this->define_column( 'preview_image_relpath', 'VARCHAR(255)' ); $this->define_column( 'title', 'VARCHAR(255)' ); $this->define_column( 'view_order', 'BIGINT', NGG_DISPLAY_PRIORITY_BASE ); $this->define_column( 'settings', 'MEDIUMTEXT' ); $this->add_serialized_column( 'settings' ); $this->add_serialized_column( 'entity_types' ); parent::__construct( 'display_type' ); } /** * @return DisplayType|\Imagely\NGGPro\DataMappers\DisplayType */ public static function get_instance() { if ( ! isset( self::$instance ) ) { $class = apply_filters( 'ngg_datamapper_client_display_type', __CLASS__ ); self::$instance = new $class(); } return self::$instance; } /** * @param string $name * @return null|\Imagely\NGG\DataTypes\DisplayType */ public function find_by_name( $name ) { $retval = null; $this->select(); $this->where( [ 'name = %s', $name ] ); $results = $this->run_query(); if ( ! $results ) { foreach ( $this->find_all() as $entity ) { if ( $entity->name == $name || ( isset( $entity->aliases ) && is_array( $entity->aliases ) && in_array( $name, $entity->aliases ) ) ) { $retval = $entity; break; } } } else { $retval = $results[0]; } return $retval; } /** * @param string|array $entity_type e.g. image, gallery, album * @return null|\Imagely\NGG\DataTypes\DisplayType[] */ public function find_by_entity_type( $entity_type ) { $find_entity_types = is_array( $entity_type ) ? $entity_type : [ $entity_type ]; $retval = null; foreach ( $this->find_all() as $display_type ) { foreach ( $find_entity_types as $entity_type ) { if ( isset( $display_type->entity_types ) && in_array( $entity_type, $display_type->entity_types ) ) { $retval[] = $display_type; break; } } } return $retval; } /** * @param \Imagely\NGG\DataTypes\DisplayType $entity * @return string */ public function get_post_title( $entity ) { return $entity->title; } /** * @param \Imagely\NGG\DataTypes\DisplayType $entity */ public function set_defaults( $entity ) { if ( ! isset( $entity->settings ) ) { $entity->settings = []; } $this->set_default_value( $entity, 'aliases', [] ); $this->set_default_value( $entity, 'default_source', '' ); $this->set_default_value( $entity, 'hidden_from_igw', false ); $this->set_default_value( $entity, 'hidden_from_ui', false ); // TODO: remove. $this->set_default_value( $entity, 'preview_image_relpath', '' ); $this->set_default_value( $entity, 'settings', 'use_lightbox_effect', true ); $this->set_default_value( $entity, 'view_order', NGG_DISPLAY_PRIORITY_BASE ); if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $this->set_default_value( $entity, 'settings', 'is_ecommerce_enabled', false ); } // Ensure that no display settings are ever missing if the controller provides defaults. if ( ControllerFactory::has_controller( $entity->name ) ) { $controller = ControllerFactory::get_controller( $entity->name ); if ( ! method_exists( $controller, 'get_default_settings' ) ) { return; } $entity->settings = array_merge( $controller->get_default_settings(), $entity->settings ); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMappers/Album.php�������������������������������������������������������������������������������0000644�����������������00000005512�15021223045�0010513 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMappers; use Imagely\NGG\DataMapper\TableDriver; use Imagely\NGG\Display\I18N; use Imagely\NGG\Util\Transient; class Album extends TableDriver { private static $instance = null; public $model_class = 'Imagely\NGG\DataTypes\Album'; public $primary_key_column = 'id'; // Necessary for legacy compatibility. public $custom_post_name = 'mixin_nextgen_table_extras'; public function __construct() { $this->define_column( 'albumdesc', 'TEXT' ); $this->define_column( 'id', 'BIGINT', 0 ); $this->define_column( 'name', 'VARCHAR(255)' ); $this->define_column( 'pageid', 'BIGINT', 0 ); $this->define_column( 'previewpic', 'BIGINT', 0 ); $this->define_column( 'slug', 'VARCHAR(255' ); $this->define_column( 'sortorder', 'TEXT' ); $this->define_column( 'extras_post_id', 'BIGINT', 0 ); $this->add_serialized_column( 'sortorder' ); parent::__construct( 'ngg_album' ); } /** * @return Album */ static function get_instance() { if ( is_null( self::$instance ) ) { self::$instance = new Album(); } return self::$instance; } /** * @param string $slug * @return null|\Imagely\NGG\DataTypes\Album */ public function get_by_slug( $slug ) { $results = $this->select()->where( [ 'slug = %s', sanitize_title( $slug ) ] )->limit( 1 )->run_query(); return array_pop( $results ); } public function save_entity( $entity ) { $retval = parent::save_entity( $entity ); if ( $retval ) { \do_action( 'ngg_album_updated', $entity ); Transient::flush( 'displayed_gallery_rendering' ); } return $retval; } /** * @param \Imagely\NGG\DataTypes\Album */ public function set_defaults( $entity ) { $this->set_default_value( $entity, 'name', '' ); $this->set_default_value( $entity, 'albumdesc', '' ); $this->set_default_value( $entity, 'sortorder', [] ); $this->set_default_value( $entity, 'previewpic', 0 ); $this->set_default_value( $entity, 'exclude', 0 ); if ( isset( $entity->name ) && ! isset( $entity->slug ) ) { $entity->slug = \nggdb::get_unique_slug( sanitize_title( $entity->name ), 'album' ); } if ( ! is_admin() && ! empty( $entity->{$entity->id_field} ) ) { if ( ! empty( $entity->name ) ) { $entity->name = I18N::translate( $entity->name, 'album_' . $entity->{$entity->id_field} . '_name' ); } if ( ! empty( $entity->albumdesc ) ) { $entity->albumdesc = I18N::translate( $entity->albumdesc, 'album_' . $entity->{$entity->id_field} . '_description' ); } // these fields are set when the album is a child to another album. if ( ! empty( $entity->title ) ) { $entity->title = I18N::translate( $entity->title, 'album_' . $entity->{$entity->id_field} . '_name' ); } if ( ! empty( $entity->galdesc ) ) { $entity->galdesc = I18N::translate( $entity->galdesc, 'album_' . $entity->{$entity->id_field} . '_description' ); } } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������DataMappers/Gallery.php�����������������������������������������������������������������������������0000644�����������������00000017757�15021223045�0011070 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\DataMappers; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DataTypes\Gallery as GalleryType; use Imagely\NGG\DataMapper\TableDriver; use Imagely\NGG\Display\I18N; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Transient; class Gallery extends TableDriver { private static $instance = null; public $model_class = 'Imagely\NGG\DataTypes\Gallery'; public $primary_key_column = 'gid'; // Necessary for legacy compatibility. public $custom_post_name = 'mixin_nextgen_table_extras'; public function __construct() { $this->define_column( 'author', 'INT', 0 ); $this->define_column( 'extras_post_id', 'BIGINT', 0 ); $this->define_column( 'galdesc', 'MEDIUMTEXT' ); $this->define_column( 'gid', 'BIGINT', 0 ); $this->define_column( 'name', 'VARCHAR(255)' ); $this->define_column( 'pageid', 'INT', 0 ); $this->define_column( 'path', 'TEXT' ); $this->define_column( 'previewpic', 'INT', 0 ); $this->define_column( 'slug', 'VARCHAR(255)' ); $this->define_column( 'title', 'TEXT' ); if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { $this->define_column( 'pricelist_id', 'BIGINT', 0, true ); } apply_filters( 'ngg_gallery_mapper_columns', $this ); parent::__construct( 'ngg_gallery' ); } /** * @return Gallery|\Imagely\NGGPro\Commerce\DataMappers\Gallery */ public static function get_instance() { if ( ! self::$instance ) { $class = apply_filters( 'ngg_datamapper_client_gallery', __CLASS__ ); self::$instance = new $class(); } return self::$instance; } /** * @param int|GalleryType * @return GalleryType|null */ public function find( $entity ) { /** @var GalleryType $result */ $result = parent::find( $entity ); return $result; } /** * @param string $slug * @return GalleryType|null */ public function get_by_slug( $slug ) { $sanitized_slug = sanitize_title( $slug ); // Try finding the gallery by slug first; if nothing is found assume that the user passed a gallery id. $retval = $this->select()->where( [ 'slug = %s', $sanitized_slug ] )->limit( 1 )->run_query(); // NextGen used to turn "This & That" into "this-&-that" when assigning gallery slugs. if ( empty( $retval ) && strpos( $slug, '&' ) !== false ) { return $this->get_by_slug( str_replace( '&', '&', $slug ) ); } return reset( $retval ); } public function set_preview_image( $gallery, $image, $only_if_empty = false ) { $retval = false; // We need the gallery object. if ( is_numeric( $gallery ) ) { $gallery = $this->find( $gallery ); } // We need the image id. if ( ! is_numeric( $image ) ) { if ( method_exists( $image, 'id' ) ) { $image = $image->id(); } else { $image = $image->{$image->id_field}; } } if ( $gallery && $image ) { if ( ( $only_if_empty && ! $gallery->previewpic ) or ! $only_if_empty ) { $gallery->previewpic = $image; $retval = $this->save( $gallery ); } } return $retval; } /** * Uses the title property as the post title when the Custom Post driver is used * * @param object $entity * @return string */ public function get_post_title( $entity ) { return $entity->title; } public function save_entity( $entity ) { $storage = StorageManager::get_instance(); // A bug in NGG 2.1.24 allowed galleries to be created with spaces in the directory name, unreplaced by dashes // This causes a few problems everywhere, so we here allow users a way to fix those galleries by just re-saving. if ( false !== strpos( $entity->path, ' ' ) ) { $abspath = $storage->get_gallery_abspath( $entity->{$entity->id_field} ); $pre_path = $entity->path; $entity->path = str_replace( ' ', '-', $entity->path ); $new_abspath = str_replace( $pre_path, $entity->path, $abspath ); // Begin adding -1, -2, etc. until we have a safe target: rename() will overwrite existing directories. if ( @file_exists( $new_abspath ) ) { $max_count = 100; $count = 0; $corrected_abspath = $new_abspath; while ( @file_exists( $corrected_abspath ) && $count <= $max_count ) { ++$count; $corrected_abspath = $new_abspath . '-' . $count; } $new_abspath = $corrected_abspath; $entity->path = $entity->path . '-' . $count; } if( ! class_exists( 'WP_Filesystem_Direct' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php'; } $wpfs = new \WP_Filesystem_Direct( null ); $wpfs->move( $abspath, $new_abspath ); } $slug = $entity->slug; $entity->slug = str_replace( ' ', '-', $entity->slug ); $entity->slug = sanitize_title( $entity->slug ); if ( $slug != $entity->slug ) { $entity->slug = \nggdb::get_unique_slug( $entity->slug, 'gallery' ); } $retval = parent::save_entity( $entity ); if ( $retval ) { $path = $storage->get_gallery_abspath( $entity ); if ( ! file_exists( $path ) ) { wp_mkdir_p( $path ); do_action( 'ngg_created_new_gallery', $entity->{$entity->id_field} ); } Transient::flush( 'displayed_gallery_rendering' ); } return $retval; } public function destroy( $entity, $with_dependencies = false ) { $retval = false; if ( $entity ) { if ( is_numeric( $entity ) ) { $gallery_id = $entity; $entity = $this->find( $gallery_id ); } else { $gallery_id = $entity->{$entity->id_field}; } // TODO: Look into making this operation more efficient. if ( $with_dependencies ) { $image_mapper = ImageMapper::get_instance(); // Delete the image files from the filesystem. $settings = Settings::get_instance(); if ( $settings->deleteImg ) { $storage = StorageManager::get_instance(); $storage->delete_gallery( $entity ); } // Delete the image records from the DB. foreach ( $image_mapper->find_all_for_gallery( $gallery_id ) as $image ) { $image_mapper->destroy( $image ); } $image_key = $image_mapper->get_primary_key_column(); $image_table = $image_mapper->get_table_name(); // Delete tag associations no longer needed. The following SQL statement deletes all tag associates for // images that no longer exist. global $wpdb; // $wpdb->prepare() cannot be used just yet as it only supported the %i placeholder for column names as of // WordPress 6.2 which is newer than NextGEN's current minimum WordPress version. // // TODO: Once NextGEN's minimum WP version is 6.2 or higher use wpdb->prepare() here. // // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( " DELETE wptr.* FROM {$wpdb->term_relationships} wptr INNER JOIN {$wpdb->term_taxonomy} wptt ON wptt.term_taxonomy_id = wptr.term_taxonomy_id WHERE wptt.term_taxonomy_id = wptr.term_taxonomy_id AND wptt.taxonomy = 'ngg_tag' AND wptr.object_id NOT IN (SELECT {$image_key} FROM {$image_table})" ); // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared } $retval = parent::destroy( $entity ); if ( $retval ) { do_action( 'ngg_delete_gallery', $entity ); Transient::flush( 'displayed_gallery_rendering' ); } } return $retval; } /** * @param GalleryType $entity */ public function set_defaults( $entity ) { // If author is missing, then set to the current user id. $this->set_default_value( $entity, 'author', get_current_user_id() ); $this->set_default_value( $entity, 'pageid', 0 ); $this->set_default_value( $entity, 'previewpic', 0 ); if ( ! is_admin() && ! empty( $entity->{$entity->id_field} ) ) { if ( ! empty( $entity->title ) ) { $entity->title = I18N::translate( $entity->title, 'gallery_' . $entity->{$entity->id_field} . '_name' ); } if ( ! empty( $entity->galdesc ) ) { $entity->galdesc = I18N::translate( $entity->galdesc, 'gallery_' . $entity->{$entity->id_field} . '_description' ); } } } } �����������������Util/Filesystem.php���������������������������������������������������������������������������������0000644�����������������00000020174�15021223045�0010314 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\Display\StaticPopeAssets; class Filesystem { protected static $_instances = []; public $_document_root; /** * @return Filesystem */ public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new Filesystem(); } return self::$_instances[ $context ]; } public function __construct() { $this->_document_root = $this->set_document_root( ABSPATH ); } /** * Gets the document root for this application * * @param string $type Must be one of plugins, plugins_mu, templates, styles, content, gallery, or root * @return string */ public function get_document_root( $type = 'root' ) { switch ( $type ) { case 'plugins': case 'plugin': $retval = WP_PLUGIN_DIR; break; case 'plugins_mu': case 'plugin_mu': $retval = WPMU_PLUGIN_DIR; break; case 'templates': case 'template': case 'themes': case 'theme': $retval = \get_template_directory(); break; case 'styles': case 'style': case 'stylesheets': case 'stylesheet': $retval = \get_stylesheet_directory(); break; case 'content': $retval = WP_CONTENT_DIR; break; case 'gallery': case 'galleries': $root_type = NGG_GALLERY_ROOT_TYPE; if ( 'content' == $root_type ) { $retval = WP_CONTENT_DIR; } else { $retval = $this->_document_root; } break; default: $retval = $this->_document_root; } return \wp_normalize_path( $retval ); } public function get_absolute_path( $path ) { $parts = \array_filter( \explode( DIRECTORY_SEPARATOR, $path ), 'strlen' ); $absolutes = []; foreach ( $parts as $part ) { if ( '.' == $part ) { continue; } if ( '..' == $part ) { \array_pop( $absolutes ); } else { $absolutes[] = $part; } } return \wp_normalize_path( \implode( DIRECTORY_SEPARATOR, $absolutes ) ); } /** * Sets the document root for this application * * @param string $value * @return string */ public function set_document_root( $value ) { // some web servers like home.pl and PhpStorm put the document root in "/" or (even weirder) "//". if ( DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR == $value ) { $value = DIRECTORY_SEPARATOR; } if ( DIRECTORY_SEPARATOR !== $value ) { $value = \rtrim( $value, '/\\' ); } return ( $this->_document_root = $value ); } public function add_trailing_slash( $path ) { return \rtrim( $path, '/\\' ) . DIRECTORY_SEPARATOR; } /** * Returns a calculated path to a file. * * This is used *once* by Pro's ecommerce module and cannot be removed just yet. * TODO: remove this eventually. * * @param string $path * @param string|false $module (optional) * @deprecated Use Imagely\NGG\Display\StaticAssets::get_abspath() * @return string */ public function get_abspath( $path, $module = false ) { return StaticPopeAssets::get_abspath( $path, $module ); } /** * Gets the absolute path to a file/directory for a specific Pope product. If the path doesn't exist, then NULL is returned. * * @param string $path * @param string|false $module (optional) * @param bool $relpath (optional) * @param array $search_paths (optional) * @deprecated This is only used by NextGEN Pro's comments module and should not be adopted in new code. * @return string|NULL */ public function find_abspath( $path, $module = false ) { if ( \strpos( $path, '#' ) !== false ) { $parts = \explode( '#', $path ); if ( \count( $parts ) === 2 ) { $path = $parts[1]; $module = $parts[0]; } else { $path = $parts[0]; } } if ( ! $module ) { die( \sprintf( 'find_abspath requires a path and module. Received %s and %s', $path, \strval( $module ) ) ); } $module_dir = \C_Component_Registry::get_instance()->get_module_dir( $module ); $path = \preg_replace( '#^/{1,2}#', '', $path, 1 ); $retval = \path_join( $module_dir, $path ); // Adjust for windows paths. return \wp_normalize_path( $retval ); } /** * @param string $abspath * @return bool */ public function delete( $abspath ) { $retval = false; if ( \file_exists( $abspath ) ) { // Delete single file. if ( \is_file( $abspath ) ) { @\wp_delete_file( $abspath ); } else { // Delete directory. foreach ( \scandir( $abspath ) as $relpath ) { if ( \in_array( $relpath, [ '.', '..' ] ) ) { continue; } $sub_abspath = $this->join_paths( $abspath, $relpath ); $this->delete( $sub_abspath ); } } $retval = ! \file_exists( $abspath ); } return $retval; } /** * Joins multiple path segments together * * @deprecated use path_join() instead when you can * @return string */ public function join_paths() { $segments = []; $retval = []; $params = func_get_args(); $this->_flatten_array( $params, $segments ); foreach ( $segments as $segment ) { $segment = trim( $segment, '/\\' ); $pieces = array_values( \preg_split( '#[/\\\\]#', $segment ) ); $segment = join( DIRECTORY_SEPARATOR, $pieces ); if ( ! $retval ) { $retval = $segment; } elseif ( strpos( $segment, $retval ) !== false ) { $retval = $segment; } else { $retval = $retval . DIRECTORY_SEPARATOR . $segment; } } if ( strpos( $retval, $this->get_document_root() ) !== 0 && ( strtoupper( substr( PHP_OS, 0, 3 ) ) != 'WIN' ) ) { $retval = DIRECTORY_SEPARATOR . trim( $retval, '/\\' ); } // Check for and adjust Windows UNC paths (\\server\share\) for network mounted sites. if ( ( strtoupper( substr( PHP_OS, 0, 3 ) ) == 'WIN' ) && substr( $this->get_document_root(), 0, 2 ) === '\\\\' ) { $retval = '\\\\' . $retval; } return $retval; } protected function _flatten_array( $obj, &$arr ) { if ( \is_array( $obj ) ) { foreach ( $obj as $inner_obj ) { $this->_flatten_array( $inner_obj, $arr ); } } elseif ( $obj ) { $arr[] = $obj; } } /** * Parses the path for a module and filename * * @param string $str * @return array [path => module] */ public function parse_formatted_path( $str ) { $module = false; $path = $str; $parts = explode( '#', $path ); if ( count( $parts ) > 1 ) { $module = array_shift( $parts ); $path = array_shift( $parts ); } return [ $path, $module ]; } /** * Empties a directory of all of its content * * @param string $directory Absolute path * @param bool $recursive Remove files from subdirectories of the cache * @param string $regex (optional) Only remove files matching pattern; '/^.+\.png$/i' will match all .png */ public function flush_directory( $directory, $recursive = true, $regex = null ) { // It is possible that the cache directory has not been created yet. if ( ! is_dir( $directory ) ) { return; } if ( $recursive ) { $directory = new \DirectoryIterator( $directory ); } else { $directory = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $directory ), \RecursiveIteratorIterator::CHILD_FIRST ); } if ( ! is_null( $regex ) ) { $iterator = new \RegexIterator( $directory, $regex, \RecursiveRegexIterator::GET_MATCH ); } else { $iterator = $directory; } foreach ( $iterator as $file ) { if ( $file->isFile() || $file->isLink() ) { @unlink( $file->getPathname() ); } elseif ( $file->isDir() && ! $file->isDot() && $recursive ) { @rmdir( $file->getPathname() ); } } } /** * Flushes cache from all available galleries * * @param array $galleries When provided only the requested galleries' cache is flushed */ public function flush_galleries( $galleries = [] ) { global $wpdb; if ( empty( $galleries ) ) { $galleries = GalleryMapper::get_instance()->find_all(); } foreach ( $galleries as $gallery ) { StorageManager::get_instance()->flush_cache( $gallery ); } // Remove images still in the DB whose gallery no longer exists. $wpdb->query( "DELETE FROM `{$wpdb->nggpictures}` WHERE `galleryid` NOT IN (SELECT `gid` FROM `{$wpdb->nggallery}`)" ); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Serializable.php�������������������������������������������������������������������������������0000644�����������������00000004357�15021223045�0010603 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; class Serializable { /** * Serializes the data * * @param mixed $value * @return string */ public static function serialize( $value ) { // Try encoding using JSON. It's usually Unicode safe but still, sometimes trips over things. $serialized = @\json_encode( $value ); if ( ! $serialized ) { $serialized = \preg_replace( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $value ); $serialized = @\json_encode( $serialized ); } // Using json_encode here because PHP's serialize is not Unicode safe. return \base64_encode( $serialized ); } /** * Unserializes data using our proprietary format * * @throws \Exception This method will not unserialize any objects * @param string $value * @return mixed */ public static function unserialize( $value ) { $retval = null; if ( \is_string( $value ) ) { $retval = \stripcslashes( $value ); if ( \strlen( $value ) > 1 ) { // We can't always rely on base64_decode() or json_decode() to return FALSE as their documentation // claims so check if $retval begins with a: as that indicates we have a serialized PHP object. if ( \strpos( $retval, 'a:' ) === 0 ) { if ( self::check_for_serialized_objects( $value ) ) { throw new \Exception( \__( 'NextGEN Gallery will not unserialize data with objects', 'nggallery' ) ); } // Record this for later. $er = \error_reporting( 0 ); // The second parameter was added by PHP 7.0. if ( \version_compare( \phpversion(), '7.0', '>=' ) ) { $retval = \unserialize( $value, [ 'allowed_classes' => false ] ); } else { $retval = \unserialize( $value ); } // Restore error reporting level. \error_reporting( $er ); } else { // We use json_decode() here because PHP's unserialize() is not Unicode safe. $retval = \json_decode( \base64_decode( $retval ), true ); } } } return $retval; } /** * Determines if a string may hold a serialized PHP object * * @param $string * @return bool */ public static function check_for_serialized_objects( $string ) { if ( ! \is_string( $string ) ) { return false; } $string = \trim( $string ); return (bool) \preg_match( '/(O|C):\+?[0-9]+:/is', $string ); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/URL.php����������������������������������������������������������������������������������������0000644�����������������00000002266�15021223045�0006634 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; class URL { public static function get_source( $source_name ) { // Nonce checks are not necessary: nothing is happening here, only the mapping of string to variable. // // phpcs:disable WordPress.Security.NonceVerification.Recommended // phpcs:disable WordPress.Security.NonceVerification.Missing if ( 'request' === $source_name ) { return $_REQUEST; } elseif ( 'get' === $source_name ) { return $_GET; } elseif ( 'post' === $source_name ) { return $_POST; } elseif ( 'server' === $source_name ) { return $_SERVER; } // phpcs:enable WordPress.Security.NonceVerification.Recommended // phpcs:enable WordPress.Security.NonceVerification.Missing } public static function param( string $name, string $source = 'request', string $validation_method = 'sanitize_text_field' ) { if ( ! self::has_param( $name ) ) { return null; } $source = self::get_source( $source ); return $validation_method( wp_unslash( $source[ $name ] ) ); } public static function has_param( string $name, string $source = 'request' ): bool { $source = self::get_source( $source ); return isset( $source[ $name ] ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Security.php�����������������������������������������������������������������������������������0000644�����������������00000003235�15021223045�0007776 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; class Security { public static function get_mapped_cap( $capability_name ) { switch ( $capability_name ) { case 'nextgen_edit_display_settings': case 'nextgen_edit_settings': { $capability_name = 'NextGEN Change options'; break; } case 'nextgen_edit_style': { $capability_name = 'NextGEN Change style'; break; } case 'nextgen_edit_displayed_gallery': { $capability_name = 'NextGEN Attach Interface'; break; } case 'nextgen_edit_gallery': { $capability_name = 'NextGEN Manage gallery'; break; } case 'nextgen_edit_gallery_unowned': { $capability_name = 'NextGEN Manage others gallery'; break; } case 'nextgen_upload_image': case 'nextgen_upload_images': { $capability_name = 'NextGEN Upload images'; break; } case 'nextgen_edit_album_settings': { $capability_name = 'NextGEN Edit album settings'; break; } case 'nextgen_edit_album': { $capability_name = 'NextGEN Edit album'; break; } } return $capability_name; } public static function create_nonce( $cap = -1 ) { return \wp_create_nonce( self::get_mapped_cap( $cap ) ); } public static function verify_nonce( $nonce, $cap = -1 ) { return \wp_verify_nonce( $nonce, self::get_mapped_cap( $cap ) ); } public static function is_allowed( $capability_name, $user = false ) { $capability_name = self::get_mapped_cap( $capability_name ); if ( ! $user && function_exists( 'wp_get_current_user' ) ) { $user = \wp_get_current_user(); } elseif ( is_numeric( $user ) ) { $user = new \WP_User( $user ); } return $user && $user->has_cap( $capability_name ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/ThirdPartyCompatibility.php��������������������������������������������������������������������0000644�����������������00000053123�15021223045�0013014 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\Display\Shortcodes as ShortcodesManager; use Imagely\NGG\DisplayedGallery\Renderer as DisplayedGalleryRenderer; use Imagely\NGG\Display\Shortcodes; use Imagely\NGG\DisplayedGallery\Renderer; use Imagely\NGG\IGW\ATPManager; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\URL; class ThirdPartyCompatibility { protected $wpseo_images = []; protected static $instance = null; public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new ThirdPartyCompatibility(); } return self::$instance; } public function __construct() { // The following constants were renamed for 2.0.41 and are kept here for legacy compatibility. $changed_constants = [ 'NEXTGEN_ADD_GALLERY_SLUG' => 'NGG_ADD_GALLERY_SLUG', 'NEXTGEN_BASIC_SINGLEPIC_MODULE_NAME' => 'NGG_BASIC_SINGLEPIC', 'NEXTGEN_BASIC_TAG_CLOUD_MODULE_NAME' => 'NGG_BASIC_TAGCLOUD', 'NEXTGEN_DISPLAY_PRIORITY_BASE' => 'NGG_DISPLAY_PRIORITY_BASE', 'NEXTGEN_DISPLAY_PRIORITY_STEP' => 'NGG_DISPLAY_PRIORITY_STEP', 'NEXTGEN_DISPLAY_SETTINGS_SLUG' => 'NGG_DISPLAY_SETTINGS_SLUG', 'NEXTGEN_GALLERY_ATTACH_TO_POST_SLUG' => 'NGG_ATTACH_TO_POST_SLUG', 'NEXTGEN_GALLERY_BASIC_SLIDESHOW' => 'NGG_BASIC_SLIDESHOW', 'NEXTGEN_GALLERY_BASIC_THUMBNAILS' => 'NGG_BASIC_THUMBNAILS', 'NEXTGEN_GALLERY_CHANGE_OPTIONS_CAP' => 'NGG_CHANGE_OPTIONS_CAP', 'NEXTGEN_GALLERY_I18N_DOMAIN' => 'NGG_I18N_DOMAIN', 'NEXTGEN_GALLERY_IMPORT_ROOT' => 'NGG_IMPORT_ROOT', 'NEXTGEN_GALLERY_MODULE_DIR' => 'NGG_MODULE_DIR', 'NEXTGEN_GALLERY_NEXTGEN_BASIC_COMPACT_ALBUM' => 'NGG_BASIC_COMPACT_ALBUM', 'NEXTGEN_GALLERY_NEXTGEN_BASIC_EXTENDED_ALBUM' => 'NGG_BASIC_EXTENDED_ALBUM', 'NEXTGEN_GALLERY_NEXTGEN_BASIC_IMAGEBROWSER' => 'NGG_BASIC_IMAGEBROWSER', 'NEXTGEN_GALLERY_NGGLEGACY_MOD_DIR' => 'NGG_LEGACY_MOD_DIR', 'NEXTGEN_GALLERY_NGGLEGACY_MOD_URL' => 'NGG_LEGACY_MOD_URL', 'NEXTGEN_GALLERY_PLUGIN' => 'NGG_PLUGIN', 'NEXTGEN_GALLERY_PLUGIN_BASENAME' => 'NGG_PLUGIN_BASENAME', 'NEXTGEN_GALLERY_PLUGIN_DIR' => 'NGG_PLUGIN_DIR', 'NEXTGEN_GALLERY_PLUGIN_STARTED_AT' => 'NGG_PLUGIN_STARTED_AT', 'NEXTGEN_GALLERY_PLUGIN_VERSION' => 'NGG_PLUGIN_VERSION', 'NEXTGEN_GALLERY_PRODUCT_DIR' => 'NGG_PRODUCT_DIR', 'NEXTGEN_GALLERY_PROTECT_IMAGE_MOD_STATIC_URL' => 'NGG_PROTUCT_IMAGE_MOD_STATIC_URL', 'NEXTGEN_GALLERY_PROTECT_IMAGE_MOD_URL' => 'NGG_PROTECT_IMAGE_MOD_URL', 'NEXTGEN_GALLERY_TESTS_DIR' => 'NGG_TESTS_DIR', 'NEXTGEN_LIGHTBOX_ADVANCED_OPTIONS_SLUG' => 'NGG_LIGHTBOX_ADVANCED_OPTIONS_SLUG', 'NEXTGEN_LIGHTBOX_OPTIONS_SLUG' => 'NGG_LIGHTBOX_OPTIONS_SLUG', 'NEXTGEN_OTHER_OPTIONS_SLUG' => 'NGG_OTHER_OPTIONS_SLUG', ]; foreach ( $changed_constants as $old => $new ) { if ( defined( $new ) && ! defined( $old ) ) { define( $old, constant( $new ) ); } } } public function register_hooks() { \add_action( 'init', [ $this, 'colorbox' ], PHP_INT_MAX ); \add_action( 'init', [ $this, 'flattr' ], PHP_INT_MAX ); \add_action( 'wp', [ $this, 'bjlazyload' ], PHP_INT_MAX ); \add_action( 'admin_init', [ $this, 'excellent_themes_admin' ], -10 ); \add_action( 'plugins_loaded', [ $this, 'wpml' ], PHP_INT_MAX ); \add_action( 'plugins_loaded', [ $this, 'wpml_translation_management' ], PHP_INT_MAX ); \add_filter( 'wpml_is_redirected', [ $this, 'wpml_is_redirected' ], -10, 3 ); \add_filter( 'headway_gzip', [ $this, 'headway_gzip' ], ( PHP_INT_MAX - 1 ) ); \add_filter( 'ckeditor_external_plugins', [ $this, 'ckeditor_plugins' ], 11 ); \add_filter( 'the_content', [ $this, 'check_weaverii' ], -( PHP_INT_MAX - 2 ) ); \add_action( 'wp', [ $this, 'check_for_jquery_lightbox' ] ); \add_filter( 'get_the_excerpt', [ $this, 'disable_galleries_in_excerpts' ], 1 ); \add_filter( 'get_the_excerpt', [ $this, 'enable_galleries_in_excerpts' ], PHP_INT_MAX - 1 ); \add_action( 'debug_bar_enqueue_scripts', [ $this, 'no_debug_bar' ] ); \add_filter( 'ngg_atp_show_display_type', [ $this, 'atp_check_pro_albums' ], 10, 2 ); \add_filter( 'wpseo_sitemap_urlimages', [ $this, 'add_wpseo_xml_sitemap_images' ], 10, 2 ); \add_filter( 'ngg_pre_delete_unused_term_id', [ $this, 'dont_auto_purge_wpml_terms' ] ); \add_filter( 'rank_math/sitemap/urlimages', [ $this, 'add_rankmath_seo_images' ], 10, 2 ); // Nimble Builder needs special consideration because of our shortcode manager's use of placeholders. \add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_nimble_builder_frontend_resources' ] ); \add_filter( 'ngg_shortcode_placeholder', [ $this, 'nimble_builder_shortcodes' ], 10, 4 ); \add_filter( 'wp_sweep_excluded_taxonomies', function ( $taxonomies ) { $taxonomies[] = 'ngg_tag'; return $taxonomies; } ); if ( $this->is_ngg_page() ) { \add_action( 'admin_enqueue_scripts', [ $this, 'dequeue_spider_calendar_resources' ] ); } // Like WPML, BuddyPress is incompatible with our routing hacks. if ( function_exists( 'buddypress' ) ) { Router::$use_canonical_redirect = false; Router::$use_old_slugs = false; } // WPML fix. if ( in_array( 'SitePress', get_declared_classes(), true ) ) { Router::$use_canonical_redirect = true; Router::$use_old_slugs = false; \add_action( 'template_redirect', [ $this, 'fix_wpml_canonical_redirect' ], 1 ); } add_action( 'the_post', [ $this, 'fix_page_parameter' ] ); } /** * Adds NextGEN images to RankMath when generating page & post sitemaps * * @param array $images * @param int $post_ID * @return array */ public function add_rankmath_seo_images( $images, $post_ID ) { $post = get_post( $post_ID ); preg_match_all( '/' . get_shortcode_regex() . '/', $post->post_content, $matches, PREG_SET_ORDER ); $renderer = DisplayedGalleryRenderer::get_instance(); $storage = StorageManager::get_instance(); $shortcodes = ShortcodesManager::get_instance()->get_shortcodes(); $retval = []; foreach ( $matches as $match ) { // Only process our shortcodes. if ( in_array( $match[2], $shortcodes ) ) { continue; } $params = shortcode_parse_atts( trim( $match[0], '[]' ) ); if ( in_array( $params[0], $shortcodes ) ) { unset( $params[0] ); } $displayed_gallery = $renderer->params_to_displayed_gallery( $params ); // There's no displayed gallery, so no reason to continue. if ( ! $displayed_gallery ) { continue; } foreach ( $displayed_gallery->get_entities() as $entity ) { // Do not start following albums' into their descent into madness. if ( isset( $entity->galdesc ) ) { continue; } $retval[] = [ 'src' => $storage->get_image_url( $entity ) ]; } } return array_merge( $images, $retval ); } /** * This code was originally added to correct a bug in Pro 1.0.10 and was meant to be temporary. However now the * albums pagination relies on this to function correctly, and fixing it properly would require more time than its worth. * * TODO: Remove this once the router and wordpress_routing modules are removed. */ public function fix_page_parameter() { global $post; if ( $post and isset( $post->post_content ) and ( strpos( $post->post_content, '<!--nextpage-->' ) === false ) and ( strpos( $_SERVER['REQUEST_URI'], '/page/' ) !== false ) ) { if ( preg_match( '#/page/(\\d+)#', $_SERVER['REQUEST_URI'], $match ) ) { $_REQUEST['page'] = $match[1]; } } } /** * @param string $placeholder * @param string $shortcode * @param array $params * @param string $inner_content * @return string */ public function nimble_builder_shortcodes( $placeholder, $shortcode, $params, $inner_content ) { if ( ! defined( 'NIMBLE_PLUGIN_FILE' ) ) { return $placeholder; } // Invoke our gallery rendering now. if ( \doing_filter( 'the_nimble_tinymce_module_content' ) ) { $placeholder = Shortcodes::get_instance()->render_shortcode( $shortcode, $params, $inner_content ); } return $placeholder; } /** * @param array $collection */ public function nimble_find_content( $collection ) { if ( ! is_array( $collection ) ) { return; } foreach ( $collection as $item ) { if ( isset( $item['value'] ) && ! empty( $item['value']['text_content'] ) ) { \Imagely\NGG\Display\DisplayManager::enqueue_frontend_resources_for_content( $item['value']['text_content'] ); } if ( ! empty( $item['collection'] ) ) { $this->nimble_find_content( $item['collection'] ); } } } public function enqueue_nimble_builder_frontend_resources() { if ( ! defined( 'NIMBLE_PLUGIN_FILE' ) ) { return; } if ( ! function_exists( '\Nimble\skp_get_skope_id' ) || ! function_exists( '\Nimble\sek_get_skoped_seks' ) || ! function_exists( '\Nimble\sek_sniff_and_decode_richtext' ) ) { return; } // Bail now if called before skope_id is set (before @hook 'wp'). $skope_id = \Nimble\skp_get_skope_id(); if ( empty( $skope_id ) || '_skope_not_set_' === $skope_id ) { return; } $global_sections = \Nimble\sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID ); $local_sections = \Nimble\sek_get_skoped_seks( $skope_id ); $raw_content = \Nimble\sek_sniff_and_decode_richtext( [ 'local_sections' => $local_sections, 'global_sections' => $global_sections, ] ); foreach ( $raw_content['local_sections'] as $section ) { $this->nimble_find_content( $section ); } foreach ( $raw_content['global_sections'] as $section ) { $this->nimble_find_content( $section ); } } public function is_ngg_page(): bool { return ( \is_admin() && isset( $_REQUEST['page'] ) && false !== strpos( $_REQUEST['page'], 'ngg' ) ); } public function dequeue_spider_calendar_resources() { \remove_filter( 'admin_head', 'spide_ShowTinyMCE' ); } /** * Filter support for WordPress SEO * * @param array $images Provided by WPSEO Filter * @param int $post_id ID Provided by WPSEO Filter * @return array $image List of a displayed galleries entities */ public function add_wpseo_xml_sitemap_images( $images, $post_id ) { $this->wpseo_images = $images; $post = \get_post( $post_id ); // Assign our own shortcode handle. \remove_all_shortcodes(); Shortcodes::add( 'ngg', [ $this, 'wpseo_shortcode_handler' ] ); Shortcodes::add( 'ngg_images', [ $this, 'wpseo_shortcode_handler' ] ); \do_shortcode( $post->post_content ); return $this->wpseo_images; } /** * Processes ngg_images shortcode when WordPress SEO is building sitemaps. Adds images belonging to a * displayed gallery to $this->wpseo_images for the assigned filter method to return. * * @param array $params Array of shortcode parameters * @param null $inner_content */ public function wpseo_shortcode_handler( $params, $inner_content = null ) { $renderer = Renderer::get_instance(); $displayed_gallery = $renderer->params_to_displayed_gallery( $params ); if ( $displayed_gallery ) { $gallery_storage = StorageManager::get_instance(); $settings = Settings::get_instance(); $source = $displayed_gallery->get_source(); if ( in_array( 'image', $source->returns ) ) { foreach ( $displayed_gallery->get_entities() as $image ) { $named_image_size = $settings->get( 'imgAutoResize' ) ? 'full' : 'thumb'; $sitemap_image = [ 'src' => $gallery_storage->get_image_url( $image, $named_image_size ), 'alt' => $image->alttext, 'title' => $image->description ? $image->description : $image->alttext, ]; $this->wpseo_images[] = $sitemap_image; } } } } /** * This style causes problems with Excellent Themes admin settings */ public function excellent_themes_admin() { if ( \is_admin() && ( isset( $_GET['page'] ) && 0 == strpos( $_GET['page'], 'et_' ) ) ) { \wp_deregister_style( 'ngg-jquery-ui' ); } } public function atp_check_pro_albums( $available, $display_type ) { if ( ! defined( 'NGG_PRO_ALBUMS' ) ) { return $available; } if ( in_array( $display_type->name, [ NGG_PRO_LIST_ALBUM, NGG_PRO_GRID_ALBUM ] ) && in_array( 'C_Component_Registry', get_declared_classes(), true ) && \C_Component_Registry::get_instance()->is_module_loaded( NGG_PRO_ALBUMS ) ) { $available = true; } return $available; } public function no_debug_bar() { if ( ATPManager::is_atp_url() ) { \wp_dequeue_script( 'debug-bar-console' ); } } // A lot of routing issues start occuring with WordPress SEO when the routing system is // initialized by the excerpt, and then again from the post content. public function disable_galleries_in_excerpts( $excerpt ) { if ( in_array( 'WPSEO_OpenGraph', get_declared_classes(), true ) ) { ATPManager::$substitute_placeholders = false; } return $excerpt; } public function enable_galleries_in_excerpts( $excerpt ) { if ( in_array( 'WPSEO_OpenGraph', get_declared_classes(), true ) ) { ATPManager::$substitute_placeholders = true; } return $excerpt; } public function fix_wpml_canonical_redirect() { Router::$use_canonical_redirect = false; Router::$use_old_slugs = false; } /** * NGG automatically purges unused terms when managing a gallery, but this also ensnares WPML translations * * @param $term_id * @return bool */ public function dont_auto_purge_wpml_terms( $term_id ) { $args = [ 'element_id' => $term_id, 'element_type' => 'ngg_tag', ]; $term_language_code = \apply_filters( 'wpml_element_language_code', null, $args ); if ( ! empty( $term_language_code ) ) { return false; } else { return $term_id; } } /** * Prevent WPML's parse_query() from conflicting with NGG's pagination & router module controlled endpoints * * @param string $redirect What WPML is send to wp_safe_redirect() * @param int $post_id * @param \WP_Query $q * @return bool|string FALSE prevents a redirect from occurring */ public function wpml_is_redirected( $redirect, $post_id, $q ) { $router = Router::get_instance(); if ( ! $router->serve_request() && $router->has_parameter_segments() ) { return false; } else { return $redirect; } } /** * CKEditor features a custom NextGEN shortcode generator that unfortunately relies on parts of the NextGEN * 1.9x API that has been deprecated in NextGEN 2.0 * * @param $plugins * @return mixed */ public function ckeditor_plugins( $plugins ) { if ( ! in_array( 'add_ckeditor_button', get_declared_classes(), true ) ) { return $plugins; } if ( ! empty( $plugins['nextgen'] ) ) { unset( $plugins['nextgen'] ); } return $plugins; } public function check_for_jquery_lightbox() { // Fix for jQuery Lightbox: http://wordpress.org/plugins/wp-jquery-lightbox/ // jQuery Lightbox tries to modify the content of a post, but it does so before we modify // the content, and therefore it's modifications have no effect on our galleries. if ( function_exists( 'jqlb_autoexpand_rel_wlightbox' ) ) { $settings = Settings::get_instance(); // First, we make it appear that NGG has no lightbox effect enabled. That way we don't any lightbox resources. $settings->delete( 'thumbEffect' ); // We would normally just let the third-party plugin do it's thing, but it's regex doesn't // seem to work on our <a> tags (perhaps because they span multiple of lines or have data attributes) // So instead, we just do what the third-party plugin wants - add the rel attribute. $settings->set( 'thumbCode', "rel='lightbox[%POST_ID%]'" ); } } /** * Weaver II's 'weaver_show_posts' shortcode creates a new wp-query, causing a second round of 'the_content' * filters to apply. This checks for WeaverII and enables all NextGEN shortcodes that would otherwise be left * disabled by our shortcode manager. See https://core.trac.wordpress.org/ticket/17817 for more. * * @param string $content * @return string $content */ public function check_weaverii( $content ) { if ( function_exists( 'weaverii_show_posts_shortcode' ) ) { Shortcodes::get_instance()->activate_all(); } return $content; } /** * WPML assigns an action to 'init' that *may* enqueue some admin-side JS. This JS relies on some inline JS * to be injected that isn't present in ATP so for ATP requests ONLY we disable their action that enqueues * their JS files. */ public function wpml() { if ( ! in_array( 'SitePress', get_declared_classes(), true ) ) { return; } if ( ! ATPManager::is_atp_url() ) { return; } global $wp_filter; if ( empty( $wp_filter['init'][2] ) && empty( $wp_filter['after_setup_theme'][1] ) ) { return; } foreach ( $wp_filter['init'][2] as $id => $filter ) { if ( ! strpos( $id, 'js_load' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'SitePress' ) { continue; } \remove_action( 'init', [ $object, 'js_load' ], 2 ); } foreach ( $wp_filter['after_setup_theme'][1] as $id => $filter ) { if ( $id !== 'wpml_installer_instance_delegator' ) { continue; } \remove_action( 'after_setup_theme', 'wpml_installer_instance_delegator', 1 ); } } /** * WPML Translation Management has a similar problem to plain ol' WPML */ public function wpml_translation_management() { if ( ! in_array( 'WPML_Translation_Management', get_declared_classes(), true ) ) { return; } if ( ! ATPManager::is_atp_url() ) { return; } global $wp_filter; if ( empty( $wp_filter['init'][10] ) ) { return; } foreach ( $wp_filter['init'][10] as $id => $filter ) { if ( ! strpos( $id, 'init' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'WPML_Translation_Management' ) { continue; } \remove_action( 'init', [ $object, 'init' ], 10 ); } } /** * Headway themes offer gzip compression, but it causes problems with NextGEN output. Disable that feature while * NextGEN is active. * * @param $option * @return bool */ public function headway_gzip( $option ) { if ( ! in_array( 'HeadwayOption', get_declared_classes(), true ) ) { return $option; } return false; } /** * Colorbox fires a filter (pri=100) to add class attributes to images via a the_content filter. We fire our * shortcodes at PHP_INT_MAX-1 to avoid encoding issues with some themes. Here we move the Colorbox filters * priority to PHP_INT_MAX so that they run after our shortcode text has been replaced with rendered galleries. */ public function colorbox() { if ( ! in_array( 'JQueryColorboxFrontend', get_declared_classes(), true ) ) { return; } global $wp_filter; if ( empty( $wp_filter['the_content'][100] ) ) { return; } foreach ( $wp_filter['the_content'][100] as $id => $filter ) { if ( ! strpos( $id, 'addColorboxGroupIdToImages' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'JQueryColorboxFrontend' ) { continue; } \remove_filter( 'the_content', [ $object, 'addColorboxGroupIdToImages' ], 100 ); \remove_filter( 'the_excerpt', [ $object, 'addColorboxGroupIdToImages' ], 100 ); \add_filter( 'the_content', [ $object, 'addColorboxGroupIdToImages' ], PHP_INT_MAX ); \add_filter( 'the_excerpt', [ $object, 'addColorboxGroupIdToImages' ], PHP_INT_MAX ); break; } } /** * Flattr fires a filter (pri=32767) on "the_content" that recurses. This causes problems, * see https://core.trac.wordpress.org/ticket/17817 for more information. Moving their filter to PHP_INT_MAX * is enough for us though */ public function flattr() { if ( ! in_array( 'Flattr', get_declared_classes(), true ) ) { return; } global $wp_filter; $level = 32767; if ( empty( $wp_filter['the_content'][ $level ] ) ) { return; } foreach ( $wp_filter['the_content'][ $level ] as $id => $filter ) { if ( ! strpos( $id, 'injectIntoTheContent' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'Flattr' ) { continue; } \remove_filter( 'the_content', [ $object, 'injectIntoTheContent' ], $level ); \add_filter( 'the_content', [ $object, 'injectIntoTheContent' ], PHP_INT_MAX ); break; } } /** * For the same reasons as Colorbox we move BJ-Lazy-load's filter() method to a later priority so it can access * our rendered galleries. */ public function bjlazyload() { if ( ! in_array( 'BJLL', get_declared_classes(), true ) ) { return; } global $wp_filter; if ( empty( $wp_filter['the_content'][200] ) ) { return; } foreach ( $wp_filter['the_content'][200] as $id => $filter ) { if ( ! strpos( $id, 'filter' ) ) { continue; } $object = $filter['function'][0]; if ( is_object( $object ) && get_class( $object ) != 'BJLL' ) { continue; } \remove_filter( 'the_content', [ $object, 'filter' ], 200 ); \add_filter( 'the_content', [ $object, 'filter' ], PHP_INT_MAX ); break; } \add_filter( 'the_content', [ $this, 'bjlazyload_filter' ], PHP_INT_MAX - 1 ); } /** * BJ-Lazy-load's regex is lazy and doesn't handle multiline search or instances where <img is immediately followed * by a newline. The following regex replaces newlines and strips unnecessary space. We fire this filter * before BJ-Lazy-Load's to make our galleries compatible with its expectations. * * @param string $content * @return string */ public function bjlazyload_filter( $content ) { return trim( preg_replace( '/\\s\\s+/', ' ', $content ) ); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Installer_Skin.php�����������������������������������������������������������������������������0000644�����������������00000004130�15021223045�0011103 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Skin class. * * @since 1.0.0 * * @package Envira_Gallery * @author Envira Team */ namespace Imagely\NGG\Util; // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Envira Lite Installer Skin * * @since 1.0.0 */ class Installer_Skin extends \WP_Upgrader_Skin { /** * Primary class constructor. * * @since 1.0.0 * * @param array $args Empty array of args (we will use defaults). */ public function __construct( $args = [] ) { parent::__construct(); } /** * Set the upgrader object and store it as a property in the parent class. * * @since 1.0.0 * * @param object $upgrader The upgrader object (passed by reference). */ public function set_upgrader( &$upgrader ) { if ( is_object( $upgrader ) ) { $this->upgrader =& $upgrader; } } /** * Set the upgrader result and store it as a property in the parent class. * * @since 1.0.0 * * @param object $result The result of the install process. */ public function set_result( $result ) { $this->result = $result; } /** * Empty out the header of its HTML content and only check to see if it has * been performed or not. * * @since 1.0.0 */ public function header() {} /** * Empty out the footer of its HTML contents. * * @since 1.0.0 */ public function footer() {} /** * Instead of outputting HTML for errors, json_encode the errors and send them * back to the Ajax script for processing. * * @since 1.0.0 * * @param array $errors Array of errors with the install process. */ public function error( $errors ) { if ( ! empty( $errors ) ) { echo wp_json_encode( [ 'error' => __( 'There was an error installing the addon. Please try again.', 'nggallery' ) ] ); die; } } /** * Empty out the feedback method to prevent outputting HTML strings as the install * is progressing. * * @since 1.0.0 * * @param string $string The feedback string. * @param array ...$args The args. */ public function feedback( $string, ...$args ) {} // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Transient.php����������������������������������������������������������������������������������0000644�����������������00000016464�15021223045�0010146 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; /** * Manages NextGEN transients and grouping of transients. */ class Transient { private $_groups = []; private static $_instance = null; protected $_tracker; /** * @return Transient */ public static function get_instance() { if ( ! self::$_instance ) { self::$_instance = new Transient(); } return self::$_instance; } public function __construct() { global $_wp_using_ext_object_cache; $this->_groups = get_option( 'ngg_transient_groups', [ '__counter' => 1 ] ); if ( $_wp_using_ext_object_cache ) { $this->_tracker = get_option( 'photocrati_cache_tracker', [] ); } register_shutdown_function( [ $this, '_update_tracker' ] ); } public function delete_tracked( $group = null ) { global $_wp_using_ext_object_cache; if ( $_wp_using_ext_object_cache ) { if ( $group ) { if ( is_array( $this->_tracker ) && isset( $this->_tracker[ $this->get_group_id( $group ) ] ) ) { foreach ( $this->_tracker[ $this->get_group_id( $group ) ] as $key ) { delete_transient( $this->get_group_id( $group ) . '__' . $key ); } unset( $this->_tracker[ $this->get_group_id( $group ) ] ); } } else { foreach ( $this->_groups as $group => $data ) { $this->delete_tracked( $group ); } } } } /** * Despite the underscore prefix this cannot be marked protected: it is used by register_shutdown_function() */ public function _update_tracker() { global $_wp_using_ext_object_cache; if ( $_wp_using_ext_object_cache ) { $current_value = get_option( 'photocrati_cache_tracker', [] ); if ( $current_value !== $this->_tracker ) { update_option( 'photocrati_cache_tracker', $this->_tracker, 'no' ); } } } public function add_group( $group_or_groups ) { $updated = false; $groups = is_array( $group_or_groups ) ? $group_or_groups : [ $group_or_groups ]; // Initialize the groups array if it doesn't exist or is not an array. // If the 'ngg_transient_groups' option is set and is not an array, this could cause fatal error. if( !is_array( $this->_groups ) ) { $this->_groups = []; } foreach ( $groups as $group ) { if ( ! isset( $this->_groups[ $group ] ) ) { $id = $this->_groups['__counter'] += 1; $this->_groups[ $group ] = [ 'id' => $id, 'enabled' => true, ]; $updated = true; } } if ( $updated ) { update_option( 'ngg_transient_groups', $this->_groups ); } } public function get_group_id( $group_name ) { $this->add_group( $group_name ); return $this->_groups[ $group_name ]['id']; } public function generate_key( $group, $params = [] ) { if ( is_object( $params ) ) { $params = (array) $params; } if ( is_array( $params ) ) { foreach ( $params as &$param ) { $param = @json_encode( $param ); } $params = implode( '', $params ); } return $this->get_group_id( $group ) . '__' . str_replace( '-', '_', crc32( $params ) ); } public function get( $key, $default = null, $lookup = null ) { $retval = $default; if ( is_null( $lookup ) && defined( 'PHOTOCRATI_CACHE' ) ) { $lookup = PHOTOCRATI_CACHE; } if ( $lookup ) { $retval = json_decode( get_transient( $key ) ); if ( is_object( $retval ) ) { $retval = (array) $retval; } if ( is_null( $retval ) ) { $retval = $default; } } return $retval; } protected function _track_key( $key ) { global $_wp_using_ext_object_cache; if ( $_wp_using_ext_object_cache ) { $parts = explode( '__', $key ); $group = $parts[0]; $id = $parts[1]; if ( ! isset( $this->_tracker[ $group ] ) ) { $this->_tracker[ $group ] = []; } if ( ! in_array( $id, $this->_tracker[ $group ] ) ) { $this->_tracker[ $group ][] = $id; } } } public function set( $key, $value, $ttl = 0 ) { $retval = false; $enabled = true; if ( defined( 'PHOTOCRATI_CACHE' ) ) { $enabled = PHOTOCRATI_CACHE; } if ( defined( 'PHOTOCRATI_CACHE_TTL' ) && ! $ttl ) { $ttl = PHOTOCRATI_CACHE_TTL; } if ( $enabled ) { $retval = set_transient( $key, json_encode( $value ), $ttl ); if ( $retval ) { $this->_track_key( $key ); } } return $retval; } public function delete( $key ) { return delete_transient( $key ); } /** * Clears all (or only expired) transients managed by this utility * * @param string $group Group name to purge * @param bool $expired Whether to clear all transients (FALSE) or to clear expired transients (TRUE) */ public function clear( $group = null, $expired = false ) { if ( $group === '__counter' ) { return; } if ( is_string( $group ) && ! empty( $group ) ) { global $wpdb; // A little query building is necessary here.. // Clear transients for "the" site or for the current multisite instance. $expired_sql = ''; $params = [ $wpdb->esc_like( '_transient_' ) . '%', '%' . $wpdb->esc_like( "{$this->get_group_id($group)}__" ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', ]; if ( $expired ) { $params[] = time(); $expired_sql = $expired ? 'AND b.option_value < %d' : ''; } $sql = "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b WHERE a.option_name LIKE %s AND a.option_name LIKE %s AND a.option_name NOT LIKE %s AND b.option_name = CONCAT('_transient_timeout_', SUBSTRING(a.option_name, 12)) {$expired_sql}"; // This is a false positive. // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $wpdb->prepare( $sql, $params ) ); // Clear transients for the main site of a multisite network. if ( is_main_site() && is_main_network() ) { $expired_sql = ''; $params = [ $wpdb->esc_like( '_site_transient_' ) . '%', '%' . $wpdb->esc_like( "{$this->get_group_id($group)}__" ) . '%', $wpdb->esc_like( '_site_transient_timeout_' ) . '%', ]; if ( $expired ) { $params[] = time(); $expired_sql = $expired ? 'AND b.option_value < %d' : ''; } $sql = "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b WHERE a.option_name LIKE %s AND a.option_name LIKE %s AND a.option_name NOT LIKE %s AND b.option_name = CONCAT('_site_transient_timeout_', SUBSTRING(a.option_name, 17)) {$expired_sql}"; // This is a false positive. // // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $wpdb->query( $wpdb->prepare( $sql, $params ) ); } if ( $expired ) { $this->delete_tracked( $group ); } } else { foreach ( $this->_groups as $name => $params ) { $this->clear( $name, $expired ); } } } public static function update( $key, $value, $ttl = null ) { return self::get_instance()->set( $key, $value, $ttl ); } public static function fetch( $key, $default = null ) { return self::get_instance()->get( $key, $default ); } public static function flush( $group = null ) { self::get_instance()->clear( $group ); } public static function flush_expired( $group = null ) { self::get_instance()->clear( $group, true ); } public static function create_key( $group, $params = [] ) { return self::get_instance()->generate_key( $group, $params ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/RoutingApp.php���������������������������������������������������������������������������������0000644�����������������00000112441�15021223045�0010257 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; use Imagely\NGG\Settings\Settings; class RoutingApp { public static $_instances = []; public $_request_uri = false; public $_settings = null; protected $_rewrite_patterns = []; protected $_routing_patterns = []; public $context = false; public function __construct( $context ) { $this->_settings = $this->get_routing_settings(); $this->context = $context; } public function get_routing_settings() { $settings = Settings::get_instance(); $object = new \stdClass(); $object->router_param_separator = $settings->get( 'router_param_separator', '--' ); $object->router_param_slug = $settings->get( 'router_param_slug', 'nggallery' ); $object->router_param_prefix = $settings->get( 'router_param_prefix', '' ); return $object; } public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new RoutingApp( $context ); } return self::$_instances[ $context ]; } /** * Creates a new route endpoint with the assigned handler * * @param string[] $routes URL to route, eg /page/{page}/ * @param array $handler Formatted array */ public function route( $routes, $handler ) { // ensure that the routing patterns array exists. if ( ! is_array( $this->_routing_patterns ) ) { $this->_routing_patterns = []; } if ( ! is_array( $routes ) ) { $routes = [ $routes ]; } // fetch all routing patterns. $patterns = $this->_routing_patterns; foreach ( $routes as $route ) { // add the routing pattern. $patterns[ $this->_route_to_regex( $route ) ] = $handler; } // update routing patterns. $this->_routing_patterns = $patterns; } /** * Handles internal url rewriting with optional HTTP redirection, * * @param string $src Original URL * @param string $dst Destination URL * @param bool $redirect FALSE for internal handling, otherwise the HTTP code to send * @param bool $stop */ public function rewrite( $src, $dst, $redirect = false, $stop = false ) { // ensure that rewrite patterns array exists. if ( ! is_array( $this->_rewrite_patterns ) ) { $this->_rewrite_patterns = []; } // fetch all rewrite patterns. $patterns = $this->_rewrite_patterns; // Assign rewrite definition. $definition = [ 'dst' => $dst, 'redirect' => $redirect, 'stop' => $stop, ]; // We treat wildcards much differently than normal rewrites. if ( preg_match( '/\\{[\\.\\\\*]/', $src ) ) { $pattern = str_replace( '{*}', '(.*?)', $src ); $pattern = str_replace( '{.*}', '(.*?)', $pattern ); $pattern = str_replace( '{\\w}', '([^/]*)', $pattern ); $pattern = str_replace( '{\\d}', '(\\d*)', $pattern ); $src = '#' . ( strpos( $src, '/' ) === 0 ? '^' : '' ) . $pattern . '/?$#'; $definition['wildcards'] = true; } else { // Normal rewrite. $src = $this->_route_to_regex( $src ); } // add the rewrite pattern. $patterns[ $src ] = $definition; // update rewrite patterns. $this->_rewrite_patterns = $patterns; } /** * Gets an instance of the router * * @return Router */ public function get_router() { return Router::get_instance(); } public function get_app_url( $request_uri = false, $with_qs = false ) { return $this->get_router()->get_url( $this->get_app_uri( $request_uri ), $with_qs ); } public function get_routed_url( $with_qs = true ) { return $this->get_app_url( false, $with_qs ); } public function get_app_uri( $request_uri = false ) { if ( ! $request_uri ) { $request_uri = $this->get_app_request_uri(); } return $this->join_paths( $this->context, $request_uri ); } public function get_app_request_uri() { $retval = false; if ( $this->_request_uri ) { $retval = $this->_request_uri; } elseif ( ( $retval = $this->does_app_serve_request() ) ) { if ( strpos( $retval, '/' ) !== 0 ) { $retval = '/' . $retval; } $this->set_app_request_uri( $retval ); } return $retval; } /** * Sets the application request uri * * @param string $uri */ public function set_app_request_uri( $uri ) { $this->_request_uri = $uri; } /** * Gets the application's routing regex pattern * * @return string */ public function get_app_routing_pattern() { return $this->_route_to_regex( $this->context ); } /** * Determines whether this app serves the request * * @return boolean|string */ public function does_app_serve_request() { $retval = false; $request_uri = $this->get_router()->get_request_uri( true ); // Is the context present in the uri? if ( ( $index = strpos( $request_uri, $this->context ) ) !== false ) { $starts_with_slash = strpos( $this->context, '/' ) === 0; if ( ( $starts_with_slash && $index === 0 ) or ( ! $starts_with_slash ) ) { $regex = implode( '', [ '#', ( $starts_with_slash ? '^' : '' ), preg_quote( $this->context, '#' ), '#', ] ); $retval = preg_replace( $regex, '', $request_uri ); if ( ! $retval ) { $retval = '/'; } if ( strpos( $retval, '/' ) !== 0 ) { $retval = '/' . $retval; } if ( substr( $retval, -1 ) != '/' ) { $retval = $retval . '/'; } } } return $retval; } /** * Performs the url rewriting routines. Returns the HTTP status code used to * redirect, if we're to do so. Otherwise FALSE * * @return int|bool */ public function do_rewrites( $request_uri = false ) { $redirect = false; static $stop_processing = false; // Get the request uri if not provided, if provided decode it. if ( ! $request_uri ) { $request_uri = $this->get_app_request_uri(); } else { $request_uri = urldecode( $request_uri ); } // ensure that rewrite patterns array exists. if ( ! is_array( $this->_rewrite_patterns ) ) { $this->_rewrite_patterns = []; } // Process each rewrite rule // start rewriting urls. if ( ! $stop_processing ) { foreach ( $this->_rewrite_patterns as $pattern => $details ) { // Remove this pattern from future processing for this request. unset( $this->_rewrite_patterns[ $pattern ] ); // Wildcards are processed much differently. if ( isset( $details['wildcards'] ) && $details['wildcards'] ) { if ( preg_match( $pattern, $request_uri, $matches ) ) { foreach ( $matches as $index => $match ) { if ( $index == 0 ) { $request_uri = str_replace( $match, $details['dst'], $request_uri ); } if ( $index > 0 ) { $request_uri = str_replace( "{{$index}}", $match, $request_uri ); } } // Set the redirect flag if we're to do so. if ( isset( $details['redirect'] ) && $details['redirect'] ) { $redirect = $details['redirect'] === true ? 302 : intval( $details['redirect'] ); break; } // Stop processing rewrite patterns? if ( $details['stop'] ) { $stop_processing = true; } } } // Normal rewrite pattern. elseif ( preg_match_all( $pattern, $request_uri, $matches, PREG_SET_ORDER ) ) { // Assign new request URI. $request_uri = $details['dst']; // Substitute placeholders. foreach ( $matches as $match ) { if ( $redirect ) { break; } foreach ( $match as $key => $val ) { // If we have a placeholder that needs swapped, swap // it now. if ( is_numeric( $key ) ) { continue; } $request_uri = str_replace( "{{$key}}", $val, $request_uri ); } // Set the redirect flag if we're to do so. if ( isset( $details['redirect'] ) && $details['redirect'] ) { $redirect = $details['redirect'] === true ? 302 : intval( $details['redirect'] ); break; } } } if ( $stop_processing ) { break; } } } // Cache all known data about the application request. $this->set_app_request_uri( $request_uri ); $this->get_router()->set_routed_app( $this ); return $redirect; } /** * Determines if the current routing app meets our requirements and serves them * * @return bool */ public function serve_request() { $served = false; // ensure that the routing patterns array exists. if ( ! is_array( $this->_routing_patterns ) ) { $this->_routing_patterns = []; } // if the application root matches, then we'll try to route the request. if ( ( $request_uri = $this->get_app_request_uri() ) ) { // Perform URL rewrites. $redirect = $this->do_rewrites( $request_uri ); // Are we to perform a redirect? if ( $redirect ) { $this->execute_route_handler( $this->parse_route_handler( $redirect ) ); } else { // Handle routed endpoints. foreach ( $this->_routing_patterns as $pattern => $handler ) { if ( preg_match( $pattern, $this->get_app_request_uri(), $matches ) ) { $served = true; // Add placeholder parameters. foreach ( $matches as $key => $value ) { if ( is_numeric( $key ) ) { continue; } $this->set_parameter_value( $key, $value, null ); } // If a handler is attached to the route, execute it. A // handler can be // - FALSE, meaning don't do any post-processing to the route // - A string, such as controller#action // - An array: array( // 'controller' => 'I_Test_Controller', // 'action' => 'index', // 'context' => 'all', (optional) // 'method' => array('GET') (optional) // ). if ( $handler && $handler = $this->parse_route_handler( $handler ) ) { // Is this handler for the current HTTP request method? if ( isset( $handler['method'] ) ) { if ( ! is_array( $handler['method'] ) ) { $handler['$method'] = [ $handler['method'] ]; } if ( in_array( $this->get_router()->get_request_method(), $handler['method'] ) ) { $this->execute_route_handler( $handler ); } } // This handler is for all request methods. else { $this->execute_route_handler( $handler ); } } elseif ( ! $handler ) { $this->passthru(); } } } } } return $served; } /** * Executes an action of a particular controller * * @param array $handler */ public function execute_route_handler( $handler ) { // qTranslate requires we disable "Hide Untranslated Content" during routed app requests like // photocrati-ajax, when uploading new images, or retrieving dynamically altered (watermarked) images. if ( ! empty( $GLOBALS['q_config'] ) && defined( 'QTRANS_INIT' ) ) { global $q_config; $q_config['hide_untranslated'] = 0; } // Get action. $action = $handler['action']; if ( class_exists( $handler['controller'] ) ) { $controller = new $handler['controller'](); } // TODO: Remove when Pro's minimum supported version supports v1 of the POPE removal compat. elseif ( class_exists( '\C_Component_Registry' ) ) { $controller = \C_Component_Registry::get_instance()->get_utility( $handler['controller'], $handler['context'] ); } // Call action. $controller->$action(); exit(); } /** * Parses the route handler * * @param mixed $handler * @return array */ public function parse_route_handler( $handler ) { if ( is_string( $handler ) ) { $handler = array_combine( [ 'controller', 'action' ], explode( '#', $handler ) ); } if ( ! isset( $handler['context'] ) ) { $handler['context'] = false; } if ( strpos( $handler['action'], '_action' ) === false ) { $handler['action'] .= '_action'; } return $handler; } /** * Converts the route to the regex * * @param string $route * @return string */ public function _route_to_regex( $route ) { // Get the settings manager. $settings = $this->_settings; $param_slug = $settings->router_param_slug; // convert route to RegEx pattern. $route_regex = preg_quote( str_replace( [ '{', '}' ], [ '~', '~' ], $route ), '#' ); // Wrap the route. $route_regex = '(' . $route_regex . ')'; // If the route starts with a slash, then it must appear at the beginning // of a request uri. if ( strpos( $route, '/' ) === 0 ) { $route_regex = '^' . $route_regex; } // If the route is not /, and perhaps /foo, then we need to optionally // look for a trailing slash as well. if ( $route != '/' ) { $route_regex .= '/?'; } // If parameters come after a slug, it might appear as well. if ( $param_slug ) { $route_regex .= '(' . preg_quote( $param_slug, '#' ) . '/)?'; } // Parameter might follow the request uri. $route_regex .= '(/?([^/]+\-\-)?[^/]+\-\-[^/]+/?){0,}'; // Create the regex. $route_regex = '#' . $route_regex . '/?$#i'; // convert placeholders to regex as well. return preg_replace( '/~([^~]+)~/i', ( $param_slug ? '(' . preg_quote( $param_slug, '#' ) . '\K)?' : '' ) . '(?P<\1>[^/]+)/?', $route_regex ); } /** * Gets a request parameter from either the request uri or querystring. * * This method takes into consideration the values of the router_param_prefix and router_param_separator settings * when searching for the parameter. * * Parameter can take on the following forms: * /key--value * /[MVC_PARAM_PREFIX]key--value * /[MVC_PARAM_PREFIX]-key--value * /[MVC_PARAM_PREFIX]_key--value * /id--key--value * /id--[MVC_PARAM_PREFIX]key--value * /id--[MVC_PARAM_PREFIX]-key--value * /id--[MVC_PARAM_PREFIX]_key--value * * @param string $key * @param mixed $id * @param mixed $default * @return mixed */ public function get_parameter( $key, $id = null, $default = null, $segment = false, $url = false ) { $retval = $default; $settings = $this->_settings; $quoted_key = preg_quote( $key, '#' ); $id = $id ? preg_quote( $id, '#' ) : '[^/]+'; $param_prefix = preg_quote( $settings->router_param_prefix, '#' ); $param_sep = preg_quote( $settings->router_param_separator, '#' ); $param_regex = "#/((?P<id>{$id}){$param_sep})?({$param_prefix}[-_]?)?{$quoted_key}{$param_sep}(?P<value>[^/\?]+)/?#i"; $found = false; $sources = $url ? [ 'custom' => $url ] : $this->get_parameter_sources(); foreach ( $sources as $source_name => $source ) { if ( preg_match( $param_regex, $source, $matches ) ) { if ( $segment ) { $retval = [ 'segment' => $matches[0], 'source' => $source_name, ]; } else { $retval = $this->recursive_stripslashes( $matches['value'] ); } $found = true; break; } } // Lastly, check the $_REQUEST. if ( ! $found && ! $url && isset( $_REQUEST[ $key ] ) ) { $found = true; $retval = $this->recursive_stripslashes( $_REQUEST[ $key ] ); } if ( ! $found && isset( $_SERVER['REQUEST_URI'] ) ) { $params = []; $parsed = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY ); if ( is_string( $parsed ) ) { parse_str( $parsed, $params ); } if ( isset( $params[ $key ] ) ) { $retval = $this->recursive_stripslashes( $params[ $key ] ); } } return $retval; } /** * Alias for remove_parameter() * * @param string $key * @param mixed $id * @return string */ public function remove_param( $key, $id = null, $url = false ) { return $this->remove_parameter( $key, $id, $url ); } /** * Adds a parameter to the application's request URI * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool|string $use_prefix (optional) * @return string */ public function add_parameter_to_app_request_uri( $key, $value, $id = null, $use_prefix = false ) { $settings = $this->_settings; $param_slug = $settings->router_param_slug; $uri = $this->get_app_request_uri(); $parts = [ $uri ]; if ( $param_slug && strpos( $uri, $param_slug ) === false ) { $parts[] = $param_slug; } $parts[] = $this->create_parameter_segment( $key, $value, $id, $use_prefix ); $this->set_app_request_uri( $this->join_paths( $parts ) ); return $this->get_app_request_uri(); } /** * Alias for set_parameter_value * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool $use_prefix (optional) * @param bool|string $url (optional) * @return string */ public function set_parameter( $key, $value, $id = null, $use_prefix = false, $url = false ) { return $this->set_parameter_value( $key, $value, $id, $use_prefix, $url ); } /** * Alias for set_parameter_value * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool $use_prefix (optional) * @param bool|string $url (optional) * @return string */ public function set_param( $key, $value, $id = null, $use_prefix = false, $url = false ) { return $this->set_parameter_value( $key, $value, $id, $use_prefix, $url ); } /** * Gets a parameter's matching URI segment * * @param string $key * @param mixed $id * @param mixed $url * @return mixed */ public function get_parameter_segment( $key, $id = null, $url = false ) { return $this->get_parameter( $key, $id, null, true, $url ); } /** * Gets sources used for parsing and extracting parameters * * @return array */ public function get_parameter_sources() { return [ 'querystring' => $this->get_formatted_querystring(), 'request_uri' => $this->get_app_request_uri(), ]; } public function get_formatted_querystring() { $retval = '/' . $this->get_router()->get_querystring(); $settings = $this->_settings; $retval = str_replace( [ '&', '=' ], [ '/', $settings->router_param_separator ], $retval ); return $retval; } public function has_parameter_segments() { $retval = false; $settings = $this->_settings; $request_uri = $this->get_app_request_uri(); $sep = preg_quote( $settings->router_param_separator, '#' ); // If we detect the MVC_PARAM_SLUG, then we assume that we have parameters. if ( $settings->router_param_slug && strpos( $request_uri, '/' . $settings->router_param_slug . '/' ) !== false ) { $retval = true; } // If the above didn't pass, then we try finding parameters in our // desired format. if ( ! $retval ) { $regex = implode( '', [ '#', $settings->router_param_slug ? '/' . preg_quote( $settings->router_param_slug, '#' ) . '/?' : '', "(/?([^/]+{$sep})?[^/]+{$sep}[^/]+/?){0,}", '$#', ] ); $retval = preg_match( $regex, $request_uri ); } return $retval; } /** * Recursively calls stripslashes() on strings, arrays, and objects * * @param mixed $value Value to be processed * @return mixed Resulting value */ public function recursive_stripslashes( $value ) { if ( is_string( $value ) ) { $value = stripslashes( $value ); } elseif ( is_array( $value ) ) { foreach ( $value as &$tmp ) { $tmp = $this->recursive_stripslashes( $tmp ); } } elseif ( is_object( $value ) ) { foreach ( get_object_vars( $value ) as $key => $data ) { $value->{$key} = $this->recursive_stripslashes( $data ); } } return $value; } public function passthru() { $router = Router::get_instance(); $_SERVER['NGG_ORIG_REQUEST_URI'] = $_SERVER['REQUEST_URI']; $base_parts = parse_url( $router->get_base_url( 'root' ) ); $new_request_uri = $router->join_paths( ( ! empty( $base_parts['path'] ) ? $base_parts['path'] : '' ), $this->strip_param_segments( $router->get_request_uri() ) ); $new_request_uri = str_replace( 'index.php/index.php', 'index.php', $new_request_uri ); // Handle possible incompatibility with 3rd party plugins manipulating the query as well: WPML in particular // can lead to our $new_request_uri here becoming index.php/en/index.php: remove this double index.php. $uri_array = explode( '/', $new_request_uri ); if ( ! empty( $uri_array ) && count( $uri_array ) >= 2 && reset( $uri_array ) == 'index.php' && end( $uri_array ) == 'index.php' ) { array_shift( $uri_array ); $new_request_uri = implode( '/', $uri_array ); } $_SERVER['UNENCODED_URL'] = $_SERVER['HTTP_X_ORIGINAL_URL'] = $_SERVER['REQUEST_URI'] = '/' . trailingslashit( $new_request_uri ); if ( isset( $_SERVER['PATH_INFO'] ) ) { $_SERVER['ORIG_PATH_INFO'] = $_SERVER['PATH_INFO']; unset( $_SERVER['PATH_INFO'] ); } } public function parse_url( $url ) { $parts = parse_url( $url ); if ( ! isset( $parts['path'] ) ) { $parts['path'] = '/'; } if ( ! isset( $parts['query'] ) ) { $parts['query'] = ''; } return $parts; } /** * Adds the post permalink to the url, if it isn't already present. * * The generated_url could look like: * http://localhost/dir/nggallery/show/slideshow * * @param $generated_url * @return mixed */ public function add_post_permalink_to_url( $generated_url ) { if ( ! apply_filters( 'ngg_wprouting_add_post_permalink', true ) ) { return $generated_url; } global $multipage, $page; $base_url = $this->get_router()->get_base_url( 'home' ); $settings = Settings::get_instance(); if ( strlen( $generated_url ) < 2 ) { $generated_url = $base_url; } $original_url = $generated_url; $generated_parts = explode( $settings->get( 'router_param_slug', 'nggallery' ), $generated_url ); $generated_url = $generated_parts[0]; $ngg_parameters = '/'; if ( isset( $generated_parts[1] ) ) { $parts = explode( '?', $generated_parts[1] ); $ngg_parameters = array_shift( $parts ); } $post_permalink = get_permalink( isset( $_REQUEST['p'] ) ? $_REQUEST['p'] : 0 ); if ( $post_permalink == '/' ) { $post_permalink = $base_url; } // Trailing slash all of the urls. $original_url = trailingslashit( $original_url ); $post_permalink = trailingslashit( $post_permalink ); $generated_url = trailingslashit( $generated_url ); // Ensure that /page/2/ links to /page/2/nggallery/page/4 rather than /nggallery/page/4/ when our paginated // galleries are displayed on posts paginated through the page break block. if ( $multipage && $page >= 2 ) { $post_permalink = $post_permalink . $page; } // We need to determine if the generated url and the post permalink TRULY differ. If they // differ, then we'll return post_permalink + nggallery parameters appended. Otherwise, we'll // just return the generated url. $generated_url = str_replace( $base_url, home_url(), $generated_url ); $generated_parts = $this->parse_url( $generated_url ); $post_parts = $this->parse_url( $post_permalink ); $generated_parts['path'] = trailingslashit( $generated_parts['path'] ); if ( isset( $generated_parts['query'] ) ) { $generated_parts['query'] = untrailingslashit( $generated_parts['query'] ); } $post_parts['path'] = trailingslashit( $post_parts['path'] ); if ( isset( $post_parts['query'] ) ) { $post_parts['query'] = untrailingslashit( $post_parts['query'] ); } $generated_url = $this->construct_url_from_parts( $generated_parts ); $post_permalink = $this->construct_url_from_parts( $post_parts ); // No change required... if ( $generated_url == $post_permalink ) { $generated_url = $original_url; // Ensure that the generated url has the real base url for default permalinks. if ( strpos( $generated_url, home_url() ) !== false && strpos( $generated_url, $base_url ) === false ) { $generated_url = str_replace( home_url(), $base_url, $generated_url ); } } else { // The post permalink differs from the generated url. $post_permalink = str_replace( home_url(), $base_url, $post_permalink ); $post_parts = $this->parse_url( $post_permalink ); $post_parts['path'] = $this->join_paths( $post_parts['path'], $settings->get( 'router_param_slug', 'nggallery' ), $ngg_parameters ); $post_parts['path'] = str_replace( 'index.php/index.php', 'index.php', $post_parts['path'] ); // incase permalink_structure contains index.php. if ( ! empty( $generated_parts['query'] ) && empty( $post_parts['query'] ) ) { $post_parts['query'] = $generated_parts['query']; } $generated_url = $this->construct_url_from_parts( $post_parts ); } return $generated_url; } public function join_paths() { $args = func_get_args(); $parts = $this->_flatten_array( $args ); foreach ( $parts as &$part ) { $part = trim( str_replace( '\\', '/', $part ), '/' ); } return implode( '/', $parts ); } /** * Removes a segment from a url * * @param string $segment * @param string $url * @return string */ public function remove_url_segment( $segment, $url ) { $retval = $url; $parts = parse_url( $url ); // If the url has a path, then we can remove a segment. if ( isset( $parts['path'] ) && $segment != '/' ) { if ( substr( $segment, -1 ) == '/' ) { $segment = substr( $segment, -1 ); } $segment = preg_quote( $segment, '#' ); if ( preg_match( "#{$segment}#", $parts['path'], $matches ) ) { $parts['path'] = str_replace( '//', '/', str_replace( $matches[0], '', $parts['path'] ) ); $retval = $this->construct_url_from_parts( $parts ); } } return $retval; } /** * Flattens an array of arrays to a single array * * @param array $array * @param array $parent (optional) * @param bool $exclude_duplicates (optional - defaults to TRUE) * @return array */ public function _flatten_array( $array, $parent = null, $exclude_duplicates = true ) { if ( is_array( $array ) ) { // We're to add each element to the parent array. if ( $parent ) { foreach ( $array as $index => $element ) { foreach ( $this->_flatten_array( $array ) as $sub_element ) { if ( $exclude_duplicates ) { if ( ! in_array( $sub_element, $parent ) ) { $parent[] = $sub_element; } } else { $parent[] = $sub_element; } } } $array = $parent; } // We're starting the process.. else { $index = 0; while ( isset( $array[ $index ] ) ) { $element = $array[ $index ]; if ( is_array( $element ) ) { $array = $this->_flatten_array( $element, $array ); unset( $array[ $index ] ); } $index += 1; } $array = array_values( $array ); } } else { $array = [ $array ]; } return $array; } /** * Constructs a url from individual parts, created by parse_url * * @param array $parts * @return string */ public function construct_url_from_parts( $parts ) { // let relative paths be relative, and full paths full. $prefix = ''; if ( ! empty( $parts['scheme'] ) && ! empty( $parts['host'] ) ) { $prefix = $parts['scheme'] . '://' . $parts['host']; if ( ! empty( $parts['port'] ) ) { $prefix .= ':' . $parts['port']; } } $retval = $this->join_paths( $prefix, isset( $parts['path'] ) ? str_replace( '//', '/', trailingslashit( $parts['path'] ) ) : '' ); if ( isset( $parts['query'] ) && $parts['query'] ) { $retval .= untrailingslashit( "?{$parts['query']}" ); } return $retval; } /** * Returns the request uri with the parameter segments stripped * * @param string $request_uri * @return string */ public function strip_param_segments( $request_uri, $remove_slug = true ) { $retval = $request_uri ? $request_uri : '/'; $settings = Settings::get_instance(); $sep = preg_quote( $settings->get( 'router_param_separator', '--' ), '#' ); $param_regex = "#((?P<id>\w+){$sep})?(?<key>\w+){$sep}(?P<value>.+)/?$#"; $slug = $settings->get( 'router_param_slug', 'nggallery' ) && $remove_slug ? '/' . preg_quote( $settings->get( 'router_param_slug', 'nggallery' ), '#' ) : ''; $slug_regex = '#' . $slug . '/?$#'; // Remove all parameters. while ( @preg_match( $param_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // Remove the slug or trailing slash. if ( @preg_match( $slug_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // If there's a slug, we can assume everything after is a parameter, // even if it's not in our desired format. $retval = preg_replace( '#' . $slug . '.*$#', '', $retval ); if ( ! $retval ) { $retval = '/'; } return $retval; } /** * Creates a parameter segment * * @param string $key * @param mixed $value * @param mixed $id * @return string */ public function create_parameter_segment( $key, $value, $id = null, $use_prefix = false ) { if ( $key === 'nggpage' ) { return 'page/' . $value; } elseif ( $key === 'album' ) { return $value; } elseif ( $key === 'gallery' ) { return $value; } elseif ( $key === 'pid' ) { return "image/{$value}"; } elseif ( $key === 'gallerytag' ) { return 'tags/' . $value; } if ( $key == 'show' ) { if ( $value === NGG_BASIC_SLIDESHOW ) { $value = 'slideshow'; } elseif ( $value == NGG_BASIC_THUMBNAILS ) { $value = 'thumbnails'; } elseif ( $value == NGG_BASIC_IMAGEBROWSER ) { $value = 'imagebrowser'; } return $value; } $settings = $this->_settings; if ( $use_prefix ) { $key = $settings->router_param_prefix . $key; } if ( $value === true ) { $value = 1; } elseif ( $value === false ) { $value = 0; // null and false values. } $retval = $key . $settings->router_param_separator . $value; if ( $id ) { $retval = $id . $settings->router_param_separator . $retval; } return $retval; } /** * Removes a parameter from the querystring and application request URI and returns the full application URL * * @param string $key * @param mixed $id * @return string|array|float|int */ public function remove_parameter( $key, $id = null, $url = false ) { $retval = $url; $settings = $this->_settings; $param_sep = $settings->router_param_separator; $param_prefix = $settings->router_param_prefix ? preg_quote( $settings->router_param_prefix, '#' ) : ''; $param_slug = $settings->router_param_slug ? preg_quote( $settings->router_param_slug, '#' ) : false; // Is the parameter already part of the request? If so, modify that parameter. if ( ( $segment = $this->get_parameter_segment( $key, $id, $url ) ) && is_array( $segment ) ) { extract( $segment ); if ( $source == 'querystring' ) { $preg_id = $id ? '\d+' : preg_quote( $id, '#' ); $preg_key = preg_quote( $key, '#' ); $regex = implode( '', [ '#', $id ? "{$preg_id}{$param_sep}" : '', "(({$param_prefix}{$param_sep})?)?{$preg_key}({$param_sep}|=)[^\/&]+&?#i", ] ); $qs = preg_replace( $regex, '', $this->get_router()->get_querystring() ); $this->get_router()->set_querystring( $qs ); $retval = $this->get_routed_url(); } elseif ( $source == 'request_uri' ) { $uri = $this->get_app_request_uri(); $uri = $this->join_paths( explode( $segment, $uri ) ); if ( $settings->router_param_slug && preg_match( "#{$param_slug}/?$#i", $uri, $match ) ) { $retval = $this->remove_url_segment( $match[0], $retval ); } $this->set_app_request_uri( $uri ); $retval = $this->get_routed_url(); } else { $retval = $this->join_paths( explode( $segment, $url ) ); if ( $settings->router_param_slug && preg_match( "#/{$param_slug}$#i", $retval, $match ) ) { $retval = $this->remove_url_segment( $match[0], $retval ); } } } if ( is_string( $retval ) ) { $retval = rtrim( $retval, ' ?&' ); } $retval = ( is_null( $retval ) or is_numeric( $retval ) or is_array( $retval ) ) ? $retval : Router::esc_url( $retval ); $retval = $this->add_post_permalink_to_url( $retval ); $retval = $this->_set_tag_cloud_parameters( $retval, $key, $id ); if ( preg_match( "#(/{$param_slug}/.*)album--#", $retval, $matches ) ) { $retval = str_replace( $matches[0], $matches[1], $retval ); } if ( preg_match( "#(/{$param_slug}/.*)gallery--#", $retval, $matches ) ) { $retval = str_replace( $matches[0], $matches[1], $retval ); } $retval = $this->_set_ngglegacy_page_parameter( $retval, $key ); // For some reason, we're not removing our parameters the way we should. Our routing system seems to be // a bit broken and so I'm adding an exception here. // TODO: Our parameter manipulations need to be flawless. Look into route cause. if ( $key === 'show' ) { $regex = '#/' . $param_slug . '.*(/?(slideshow|thumbnails|imagebrowser)/?)#'; if ( preg_match( $regex, $retval, $matches ) ) { $retval = str_replace( $matches[1], '', $retval ); } } return $retval; } public function _set_tag_cloud_parameters( $retval, $key, $id = null ) { // Get the settings manager. $settings = Settings::get_instance(); // Create the regex pattern. $sep = preg_quote( $settings->get( 'router_param_separator', '--' ), '#' ); if ( $id ) { $id = preg_quote( $id, '#' ) . $sep; } $prefix = preg_quote( $settings->get( 'router_param_prefix', '' ), '#' ); $regex = implode( '', [ '#//?', $id ? "({$id})?" : "(\w+{$sep})?", "($prefix)?gallerytag{$sep}([\w\-_]+)/?#", ] ); // Replace any page parameters with the ngglegacy equivalent. if ( preg_match( $regex, $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], "/tags/{$matches[3]}/", $retval ), '/' ); } return $retval; } public function _set_ngglegacy_page_parameter( $retval, $key, $value = null, $id = null, $use_prefix = null ) { // Get the settings manager. $settings = Settings::get_instance(); // Create regex pattern. $param_slug = preg_quote( $settings->get( 'router_param_slug', 'nggallery' ), '#' ); if ( $key == 'nggpage' ) { $regex = "#(/{$param_slug}/.*)(/?page/\\d+/?)(.*)#"; if ( preg_match( $regex, $retval, $matches ) ) { $new_segment = $value ? "/page/{$value}" : ''; $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . $new_segment . ltrim( $matches[3], '/' ), $retval ), '/' ); } } // Convert the nggpage parameter to a slug. if ( preg_match( "#(/{$param_slug}/.*)nggpage--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/page/' . ltrim( $matches[2], '/' ), $retval ), '/' ); } // Convert the show parameter to a slug. if ( preg_match( "#(/{$param_slug}/.*)show--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/' . $matches[2], $retval ), '/' ); $retval = str_replace( NGG_BASIC_SLIDESHOW, 'slideshow', $retval ); $retval = str_replace( NGG_BASIC_THUMBNAILS, 'thumbnails', $retval ); $retval = str_replace( NGG_BASIC_IMAGEBROWSER, 'imagebrowser', $retval ); } return $retval; } public function _set_search_page_parameter( $retval, $key, $value = null, $id = null, $use_prefix = null ) { $settings = Settings::get_instance(); $param_slug = preg_quote( $settings->router_param_slug, '#' ); // Convert the nggsearch parameter to a slug. if ( preg_match( "#(/{$param_slug}/.*)nggsearch--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/search/' . ltrim( $matches[2], '/' ), $retval ), '/' ); } if ( preg_match( "#(/{$param_slug}/.*)tagfilter--(.*)#", $retval, $matches ) ) { $retval = rtrim( str_replace( $matches[0], rtrim( $matches[1], '/' ) . '/tagfilter/' . ltrim( $matches[2], '/' ), $retval ), '/' ); } return $retval; } /** * Sets the value of a particular parameter * * @param string $key * @param mixed $value * @param mixed $id (optional) * @param bool $use_prefix (optional) * @param bool|string $url (optional) * @return string */ public function set_parameter_value( $key, $value, $id = null, $use_prefix = false, $url = false ) { // Get the settings manager. $settings = $this->_settings; $param_slug = $settings->router_param_slug; // it's difficult to make NextGEN's router work with spaces in parameter names without just encoding them // directly first; replace nggsearch's parameter's spaces with %20. $url = preg_replace_callback( "#(/{$param_slug}/.*)nggsearch--(.*)#", function ( $matches ) { return str_replace( ' ', '%20', $matches[0] ); }, $url ); // Remove the parameter from both the querystring and request uri. $retval = $this->remove_parameter( $key, $id, $url ); // We're modifying a url passed in. if ( $url ) { $parts = parse_url( $retval ); if ( ! isset( $parts['path'] ) ) { $parts['path'] = ''; } $parts['path'] = $this->join_paths( $parts['path'], $param_slug && strpos( $parts['path'], $param_slug ) === false ? $param_slug : '', $this->create_parameter_segment( $key, $value, $id, $use_prefix ) ); $parts['path'] = str_replace( '//', '/', $parts['path'] ); $retval = $this->construct_url_from_parts( $parts ); } // We're modifying the current request. else { // This parameter is being appended to the current request uri. $this->add_parameter_to_app_request_uri( $key, $value, $id, $use_prefix ); // Return the new full url. $retval = $this->get_routed_url(); } $retval = ( is_null( $retval ) || is_numeric( $retval ) || is_array( $retval ) ) ? $retval : Router::esc_url( $retval ); $retval = $this->_set_tag_cloud_parameters( $retval, $key, $id ); $retval = $this->_set_ngglegacy_page_parameter( $retval, $key, $value, $id, $use_prefix ); $retval = $this->_set_search_page_parameter( $retval, $key, $value, $id, $use_prefix ); return $retval; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Installer.php����������������������������������������������������������������������������������0000644�����������������00000016436�15021223045�0010133 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Settings\GlobalSettings; class Installer { protected static $_installers = []; /** * Each product and module will register its own handler (a class, with an install() and uninstall() method) * to be used for install/uninstall routines * * @param string $name * @param string|object $handler */ public static function add_handler( $name, $handler ) { self::$_installers[ $name ] = $handler; } /** * Gets an instance of an installation handler * * @param $name * @return mixed */ public static function get_handler_instance( $name ) { if ( isset( self::$_installers[ $name ] ) ) { $klass = self::$_installers[ $name ]; return new $klass(); } else { return null; } } /** * @return array */ protected static function get_all_handlers() { return self::$_installers; } /** * Uninstalls a product * * @param string $product * @param bool $hard * @return bool */ public static function uninstall( $product, $hard = false ) { $handler = self::get_handler_instance( $product ); if ( $handler && \method_exists( $handler, 'uninstall' ) ) { return $handler->uninstall( $hard ); } if ( $handler && $hard ) { Settings::get_instance()->destroy(); GlobalSettings::get_instance()->destroy(); } return true; } public static function can_do_upgrade() { $proceed = false; // Proceed if no other process has started the installer routines. if ( ! ( $doing_upgrade = \get_option( 'ngg_doing_upgrade', false ) ) ) { \update_option( 'ngg_doing_upgrade', \time() ); $proceed = true; } // Or, force proceeding if we have a stale ngg_doing_upgrade record. elseif ( $doing_upgrade === true or \time() - $doing_upgrade > 120 ) { \update_option( 'ngg_doing_upgrade', \time() ); $proceed = true; } return $proceed; } public static function done_upgrade() { \delete_option( 'ngg_doing_upgrade' ); } public static function update( $reset = false ) { $local_settings = Settings::get_instance(); $global_settings = GlobalSettings::get_instance(); $do_upgrade = false; // TODO: remove this when POPE v1 compatibility is reached in Pro. if ( \C_NextGEN_Bootstrap::get_pro_api_version() < 4.0 ) { // Get last module list and current module list. Compare... $last_module_list = self::_get_last_module_list( $reset ); $current_module_list = self::_generate_module_info(); $diff = \array_diff( $current_module_list, $last_module_list ); $do_upgrade = ( \count( $diff ) > 0 || \count( $last_module_list ) != \count( $current_module_list ) ); } $ngg_version_setting = $local_settings->get( 'ngg_plugin_version', 0 ); if ( ! $ngg_version_setting || $ngg_version_setting !== NGG_PLUGIN_VERSION ) { $do_upgrade = true; } // Allow NextGEN extensions to trigger this process. $do_upgrade = \apply_filters( 'ngg_do_install_or_setup_process', $do_upgrade ); $can_upgrade = $do_upgrade && self::can_do_upgrade(); if ( $can_upgrade && $do_upgrade ) { // Clear APC cache. if ( \function_exists( 'apc_clear_cache' ) ) { @\apc_clear_cache( 'opcode' ); \apc_clear_cache(); } // Attempt to reset the opcache. NextGEN 3.50+ and Pro 3.30+ moved, renamed, and deleted several files // and purging the opcache should help prevent fatal errors due to cached instructions. if ( \function_exists( 'opcache_reset' ) ) { \opcache_reset(); } // Clear all of our transients. \wp_cache_flush(); Transient::flush(); // Remove all NGG created cron jobs. self::refresh_cron(); // Other Pope applications might be loaded, and therefore all singletons should be destroyed, so that they // can be adapted as necessary. For now, we'll just assume that the factory is the only singleton that will // be used by other Pope applications. if ( class_exists( '\C_Component_Factory' ) ) { \C_Component_Factory::$_instances = []; } foreach ( self::get_all_handlers() as $handler_name => $handler_class ) { $handler = new $handler_class(); if ( \method_exists( $handler, 'install' ) ) { $handler->install( $reset ); } } // Record the current version; changes to this and setting are how updates are triggered. $local_settings->set( 'ngg_plugin_version', NGG_PLUGIN_VERSION ); $global_settings->save(); $local_settings->save(); self::set_role_caps(); \do_action( 'ngg_did_install_or_setup_process' ); } // Update the module list, and remove the update flag. if ( $can_upgrade ) { if ( isset( $current_module_list ) ) { \update_option( 'pope_module_list', $current_module_list ); } self::done_upgrade(); } } public static function _get_last_module_list( $reset = false ) { if ( $reset ) { return []; } // First try getting the list from a single WP option, "pope_module_list". $retval = \get_option( 'pope_module_list', [] ); if ( ! $retval ) { $local_settings = Settings::get_instance(); $retval = $local_settings->get( 'pope_module_list', [] ); $local_settings->delete( 'pope_module_list' ); } return $retval; } protected static function _generate_module_info() { $retval = []; $registry = \C_Component_Registry::get_instance(); $products = [ 'photocrati-nextgen' ]; foreach ( $registry->get_product_list() as $product_id ) { if ( $product_id != 'photocrati-nextgen' ) { $products[] = $product_id; } } foreach ( $products as $product_id ) { foreach ( $registry->get_module_list( $product_id ) as $module_id ) { if ( ( $module = $registry->get_module( $module_id ) ) ) { $module_version = $module->module_version; $module_string = "{$module_id}|{$module_version}"; if ( ! \in_array( $module_string, $retval ) ) { $retval[] = $module_string; } } } } return $retval; } public static function refresh_cron() { if ( ! \extension_loaded( 'suhosin' ) ) { @\ini_set( 'memory_limit', -1 ); } // Remove all cron jobs created by NextGEN Gallery. $cron = \_get_cron_array(); if ( \is_array( $cron ) ) { foreach ( $cron as $timestamp => $job ) { if ( \is_array( $job ) ) { unset( $cron[ $timestamp ]['ngg_delete_expired_transients'] ); if ( empty( $cron[ $timestamp ] ) ) { unset( $cron[ $timestamp ] ); } } } } \_set_cron_array( $cron ); } public static function set_role_caps() { // Set the capabilities for the administrator. $role = \get_role( 'administrator' ); if ( ! $role ) { if ( ! class_exists( 'WP_Roles' ) ) { include_once ABSPATH . '/wp-includes/class-wp-roles.php'; } $roles = new \WP_Roles(); $roles->init_roles(); } // We need this role, no other chance. $role = \get_role( 'administrator' ); if ( ! $role ) { \update_option( 'ngg_init_check', __( 'Sorry, NextGEN Gallery works only with a role called administrator', 'nggallery' ) ); return; } delete_option( 'ngg_init_check' ); $capabilities = [ 'NextGEN Attach Interface', 'NextGEN Change options', 'NextGEN Change style', 'NextGEN Edit album', 'NextGEN Gallery overview', 'NextGEN Manage gallery', 'NextGEN Manage others gallery', 'NextGEN Manage tags', 'NextGEN Upload images', 'NextGEN Use TinyMCE', ]; foreach ( $capabilities as $capability ) { $role->add_cap( $capability ); } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Router.php�������������������������������������������������������������������������������������0000644�����������������00000044725�15021223045�0007460 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; use Imagely\NGG\Settings\Settings; use Imagely\NGG\Util\Transient; class Router { public static $_instances = []; public static $_lookups = []; public $context; public $_request_method = ''; public $_routed_app; public $_apps = []; public $_default_app = null; public static $use_canonical_redirect = true; public static $use_old_slugs = true; public function __construct( $context = false ) { if ( ! $context || $context === 'all' ) { $this->context = '/'; } $this->_request_method = ! empty( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : null; self::$_lookups = Transient::fetch( $this->_get_cache_key(), [] ); // TODO: only register this once. register_shutdown_function( [ $this, 'cache_lookups' ] ); } /** * @param string|false $context (optional) * @return Router */ public static function get_instance( $context = false ) { if ( ! isset( self::$_instances[ $context ] ) ) { self::$_instances[ $context ] = new Router( $context ); } return self::$_instances[ $context ]; } public function register_hooks() { \add_action( 'template_redirect', [ $this, 'restore_request_uri' ], 1 ); // These two things cause conflicts in NGG. So we temporarily disable them and then reactivate them, if they // were used, in the restore_request_uri() method. if ( \has_action( 'template_redirect', 'wp_old_slug_redirect' ) ) { \remove_action( 'template_redirect', 'wp_old_slug_redirect' ); } if ( \has_action( 'template_redirect', 'redirect_canonical' ) ) { \remove_action( 'template_redirect', 'redirect_canonical' ); } \add_action( 'the_post', [ $this, 'fix_page_parameter' ] ); } /** * When WordPress sees a url like http://foobar.com/nggallery/page/2/, it thinks that it is an * invalid url. Therefore, we modify the request uri before WordPress parses the request, and then * restore the request uri afterwards */ public function restore_request_uri() { if ( isset( $_SERVER['NGG_ORIG_REQUEST_URI'] ) ) { $request_uri = $_SERVER['NGG_ORIG_REQUEST_URI']; $_SERVER['UNENCODED_URL'] = $_SERVER['HTTP_X_ORIGINAL_URL'] = $_SERVER['REQUEST_URI'] = $request_uri; if ( isset( $_SERVER['ORIG_PATH_INFO'] ) ) { $_SERVER['PATH_INFO'] = $_SERVER['ORIG_PATH_INFO']; } } else { // This is the proper behavior, but it causes problems with WPML. if ( self::$use_old_slugs ) { \wp_old_slug_redirect(); } if ( self::$use_canonical_redirect ) { \redirect_canonical(); } } } public function join_paths() { $args = func_get_args(); $parts = $this->_flatten_array( $args ); foreach ( $parts as &$part ) { $part = trim( str_replace( '\\', '/', $part ), '/' ); } return implode( '/', $parts ); } /** * Removes a segment from a url * * @param string $segment * @param string $url * @return string */ public function remove_url_segment( $segment, $url ) { $retval = $url; $parts = parse_url( $url ); // If the url has a path, then we can remove a segment. if ( isset( $parts['path'] ) && $segment != '/' ) { if ( substr( $segment, -1 ) == '/' ) { $segment = substr( $segment, -1 ); } $segment = preg_quote( $segment, '#' ); if ( preg_match( "#{$segment}#", $parts['path'], $matches ) ) { $parts['path'] = str_replace( '//', '/', str_replace( $matches[0], '', $parts['path'] ) ); $retval = $this->construct_url_from_parts( $parts ); } } return $retval; } /** * Flattens an array of arrays to a single array * * @param array $array * @param array $parent (optional) * @param bool $exclude_duplicates (optional - defaults to TRUE) * @return array */ public function _flatten_array( $array, $parent = null, $exclude_duplicates = true ) { if ( is_array( $array ) ) { // We're to add each element to the parent array. if ( $parent ) { foreach ( $array as $index => $element ) { foreach ( $this->_flatten_array( $array ) as $sub_element ) { if ( $exclude_duplicates ) { if ( ! in_array( $sub_element, $parent ) ) { $parent[] = $sub_element; } } else { $parent[] = $sub_element; } } } $array = $parent; } else { // We're starting the process.. $index = 0; while ( isset( $array[ $index ] ) ) { $element = $array[ $index ]; if ( is_array( $element ) ) { $array = $this->_flatten_array( $element, $array ); unset( $array[ $index ] ); } $index += 1; } $array = array_values( $array ); } } else { $array = [ $array ]; } return $array; } public function join_querystrings() { $retval = []; $params = func_get_args(); $parts = $this->_flatten_array( $params ); foreach ( $parts as $part ) { $part = explode( '&', $part ); foreach ( $part as $segment ) { $segment = explode( '=', $segment ); $key = $segment[0]; $value = isset( $segment[1] ) ? $segment[1] : ''; $retval[ $key ] = $value; } } return $this->assoc_array_to_querystring( $retval ); } public function assoc_array_to_querystring( $arr ) { $retval = []; foreach ( $arr as $key => $val ) { if ( strlen( $key ) ) { $retval[] = strlen( $val ) ? "{$key}={$val}" : $key; } } return implode( '&', $retval ); } /** * Constructs an url from individual parts, created by parse_url * * @param array $parts * @return string */ public function construct_url_from_parts( $parts ) { // let relative paths be relative, and full paths full. $prefix = ''; if ( ! empty( $parts['scheme'] ) && ! empty( $parts['host'] ) ) { $prefix = $parts['scheme'] . '://' . $parts['host']; if ( ! empty( $parts['port'] ) ) { $prefix .= ':' . $parts['port']; } } $retval = $this->join_paths( $prefix, isset( $parts['path'] ) ? str_replace( '//', '/', trailingslashit( $parts['path'] ) ) : '' ); if ( isset( $parts['query'] ) && $parts['query'] ) { $retval .= untrailingslashit( "?{$parts['query']}" ); } return $retval; } /** * Returns the request uri with the parameter segments stripped * * @param string $request_uri * @return string */ public function strip_param_segments( $request_uri, $remove_slug = true ) { $retval = $request_uri ? $request_uri : '/'; $settings = Settings::get_instance(); $sep = preg_quote( $settings->get( 'router_param_separator', '--' ), '#' ); $param_regex = "#((?P<id>\w+){$sep})?(?<key>\w+){$sep}(?P<value>.+)/?$#"; $slug = $settings->get( 'router_param_slug', 'nggallery' ) && $remove_slug ? '/' . preg_quote( $settings->get( 'router_param_slug', 'nggallery' ), '#' ) : ''; $slug_regex = '#' . $slug . '/?$#'; // Remove all parameters. while ( @preg_match( $param_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // Remove the slug or trailing slash. if ( @preg_match( $slug_regex, $retval, $matches ) ) { $match_regex = '#' . preg_quote( array_shift( $matches ), '#' ) . '$#'; $retval = preg_replace( $match_regex, '', $retval ); } // If there's a slug, we can assume everything after is a parameter, // even if it's not in our desired format. $retval = preg_replace( '#' . $slug . '.*$#', '', $retval ); if ( ! $retval ) { $retval = '/'; } return $retval; } public function set_routed_app( $app ) { $this->_routed_app = $app; } /** * @return RoutingApp */ public function get_routed_app() { return $this->_routed_app ? $this->_routed_app : $this->get_default_app(); } /** * @return RoutingApp */ public function get_default_app() { if ( is_null( $this->_default_app ) ) { $this->_default_app = $this->create_app(); } return $this->_default_app; } public function route( $patterns, $handler = false ) { $this->get_default_app()->route( $patterns, $handler ); } public function rewrite( $src, $dst, $redirect = false ) { $this->get_default_app()->rewrite( $src, $dst, $redirect ); } public function get_parameter( $key, $prefix = null, $default = null ) { return $this->get_routed_app()->get_parameter( $key, $prefix, $default ); } public function param( $key, $prefix = null, $default = null ) { return $this->get_parameter( $key, $prefix, $default ); } public function has_parameter_segments() { return $this->get_routed_app()->has_parameter_segments(); } public function passthru() { $this->get_default_app()->passthru(); } public function get_url( $uri = '/', $with_qs = true, $site_url = false ) { static $cache = []; $key = implode( '|', [ $uri, $with_qs, $site_url ] ); if ( isset( $cache[ $key ] ) ) { return $cache[ $key ]; } else { $retval = $this->join_paths( $this->get_base_url( $site_url ), $uri ); if ( $with_qs ) { $parts = parse_url( $retval ); if ( ! isset( $parts['query'] ) ) { $parts['query'] = $this->get_querystring(); } else { $parts['query'] = $this->join_querystrings( $parts['query'], $this->get_querystring() ); } $retval = $this->construct_url_from_parts( $parts ); } $retval = str_replace( '\\', '/', $retval ); // Determine whether the url is a directory or file on the filesystem // If so, then we do NOT need /index.php as part of the url. $base_url = $this->get_base_url(); $filename = str_replace( $base_url, \Imagely\NGG\Util\Filesystem::get_instance()->get_document_root(), $retval ); if ( $retval && $retval != $base_url && @file_exists( $filename ) ) { // Remove index.php from the url. $retval = $this->remove_url_segment( '/index.php', $retval ); // Static urls don't end with a slash. $retval = untrailingslashit( $retval ); } $cache[ $key ] = $retval; return $retval; } } /** * Returns a static url * * @param string $path * @param string|false $module (optional) * @return string */ public function get_static_url( $path, $module = false ) { return \Imagely\NGG\Display\StaticPopeAssets::get_url( $path, $module ); } /** * Gets the routed url * * @return string */ public function get_routed_url() { $retval = $this->get_url( $this->get_request_uri() ); if ( ( $app = $this->get_routed_app() ) ) { $retval = $this->get_url( $app->get_app_uri() ); } return $retval; } /** * Gets the base url for the router * * @param bool $type * @return string */ public function get_base_url( $type = false ) { if ( $this->has_cached_base_url( $type ) ) { return $this->get_cached_base_url( $type ); } return $this->get_computed_base_url( $type ); } /** * Determines if the current request is over HTTPs or not */ public function is_https() { return ( ( ! empty( $_SERVER['HTTPS'] ) && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) || ( ! empty( $_SERVER['HTTP_USESSL'] ) && strtolower( $_SERVER['HTTP_USESSL'] ) !== 'off' ) || ( ! empty( $_SERVER['REDIRECT_HTTPS'] ) && strtolower( $_SERVER['REDIRECT_HTTPS'] ) !== 'off' ) || ( ! empty( $_SERVER['SERVER_PORT'] ) && $_SERVER['SERVER_PORT'] == 443 ) ); } /** * Serve request using defined Routing Apps */ public function serve_request() { $served = false; // iterate over all apps, and serve the route. /** @var \Imagely\NGG\Util\RoutingApp $app */ foreach ( $this->get_apps() as $app ) { if ( ( $served = $app->serve_request( $this->context ) ) ) { break; } } return $served; } /** * Gets the querystring of the current request * * @return null|bool */ public function get_querystring() { return isset( $_SERVER['QUERY_STRING'] ) ? $_SERVER['QUERY_STRING'] : null; } public function set_querystring( $value ) { $_SERVER['QUERY_STRING'] = $value; } /** * Gets the request for the router * * @param bool $with_params (optional) Default = true * @return string */ public function get_request_uri( $with_params = true ) { if ( ! empty( $_SERVER['NGG_ORIG_REQUEST_URI'] ) ) { $retval = $_SERVER['NGG_ORIG_REQUEST_URI']; } elseif ( ! empty( $_SERVER['PATH_INFO'] ) ) { $retval = $_SERVER['PATH_INFO']; } else { $retval = $_SERVER['REQUEST_URI']; } // Remove the querystring. if ( ( $index = strpos( $retval, '?' ) ) !== false ) { $retval = substr( $retval, 0, $index ); } // Remove the router's context. $retval = preg_replace( '#^' . preg_quote( $this->context, '#' ) . '#', '', $retval ); // Remove the params. if ( ! $with_params ) { $retval = $this->strip_param_segments( $retval ); } // Ensure that request uri starts with a slash. if ( strpos( $retval, '/' ) !== 0 ) { $retval = "/{$retval}"; } return $retval; } /** * Gets the method of the HTTP request * * @return string */ public function get_request_method() { return $this->_request_method; } /** * @param string $name * @return RoutingApp */ public function create_app( $name = '/' ) { $app = new RoutingApp( $name ); $this->_apps[] = $app; return $app; } /** * Gets a list of apps registered for the router * * @return array */ public function get_apps() { usort( $this->_apps, [ &$this, '_sort_apps' ] ); return array_reverse( $this->_apps ); } /** * Sorts apps.This is needed because we want the most specific app to be executed first * * @return int */ public function _sort_apps( RoutingApp $a, RoutingApp $b ) { return strnatcmp( $a->context, $b->context ); } public function _get_cache_key() { return Transient::create_key( 'WordPress-Router', 'get_base_url' ); } public function cache_lookups() { Transient::update( $this->_get_cache_key(), self::$_lookups ); } public function has_cached_base_url( $type = false ) { return isset( self::$_lookups[ $type ] ); } public function get_cached_base_url( $type = false ) { return self::$_lookups[ $type ]; } public function get_computed_base_url( $site_url = false ) { $retval = null; $add_index_dot_php = true; if ( in_array( $site_url, [ true, 'site' ], true ) ) { $retval = site_url(); } elseif ( in_array( $site_url, [ false, 'home' ], true ) ) { $retval = home_url(); } elseif ( in_array( $site_url, [ 'plugins', 'plugin' ], true ) ) { $retval = plugins_url(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'plugins_mu', 'plugin_mu' ], true ) ) { $retval = WPMU_PLUGIN_URL; $retval = set_url_scheme( $retval ); $retval = apply_filters( 'plugins_url', $retval, '', '' ); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'templates', 'template', 'themes', 'theme' ], true ) ) { $retval = get_template_directory_uri(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'styles', 'style', 'stylesheets', 'stylesheet' ], true ) ) { $retval = get_stylesheet_directory_uri(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'content' ], true ) ) { $retval = content_url(); $add_index_dot_php = false; } elseif ( in_array( $site_url, [ 'root' ], true ) ) { $retval = get_option( 'home' ); if ( is_ssl() ) { $scheme = 'https'; } else { $scheme = parse_url( $retval, PHP_URL_SCHEME ); } $retval = set_url_scheme( $retval, $scheme ); } elseif ( in_array( $site_url, [ 'gallery', 'galleries' ], true ) ) { $root_type = NGG_GALLERY_ROOT_TYPE; $add_index_dot_php = false; if ( $root_type === 'content' ) { $retval = content_url(); } else { $retval = site_url(); } } else { $retval = site_url(); } if ( $add_index_dot_php ) { $retval = $this->_add_index_dot_php_to_url( $retval ); } if ( $this->is_https() ) { $retval = preg_replace( '/^http:\\/\\//i', 'https://', $retval, 1 ); } return $retval; } public function _add_index_dot_php_to_url( $url ) { if ( strpos( $url, '/index.php' ) === false ) { $pattern = get_option( 'permalink_structure' ); if ( ! $pattern or strpos( $pattern, '/index.php' ) !== false ) { $url = $this->join_paths( $url, '/index.php' ); } } return $url; } /** * This code was originally added to correct a bug in Pro 1.0.10 and was meant to be temporary. However now the * albums' pagination relies on this to function correctly, and fixing it properly would require more time than * it is worth. */ public function fix_page_parameter() { global $post; if ( $post && is_object( $post ) && is_string( $post->post_content ) && ( strpos( $post->post_content, '<!--nextpage-->' ) === false ) && ( strpos( $_SERVER['REQUEST_URI'], '/page/' ) !== false ) && preg_match( '#/page/(\\d+)#', $_SERVER['REQUEST_URI'], $match ) ) { $_REQUEST['page'] = $match[1]; } } /** * Checks and cleans a URL. This function is forked from WordPress. * * A number of characters are removed from the URL. If the URL is for displaying (the default behaviour) ampersands * are also replaced. The 'clean_url' filter is applied to the returned cleaned URL. * * @param string $url The URL to be cleaned. * @param array $protocols Optional. An array of acceptable protocols. * @param string $context Use esc_url_raw() for database usage. * @return string The cleaned $url after the 'clean_url' filter is applied. */ public static function esc_url( $url, $protocols = null, $context = 'display' ) { $original_url = $url; if ( '' == $url ) { return $url; } $url = preg_replace( '|[^a-z0-9 \\-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url ); $strip = [ '%0d', '%0a', '%0D', '%0A' ]; $url = \_deep_replace( $strip, $url ); $url = str_replace( ';//', '://', $url ); // If the URL doesn't appear to contain a scheme, we presume it needs https:// prepended (unless a relative // link starting with /, # or ? or a php file). if ( strpos( $url, ':' ) === false && ! in_array( $url[0], [ '/', '#', '?' ] ) && ! preg_match( '/^[a-z0-9-]+?\.php/i', $url ) ) { $url = \is_ssl() ? 'https://' : 'http://' . $url; } // Replace ampersands and single quotes only when displaying. if ( 'display' == $context ) { $url = \wp_kses_normalize_entities( $url ); $url = str_replace( '&', '&', $url ); $url = str_replace( "'", ''', $url ); $url = str_replace( ' ', '%20', $url ); } if ( '/' === $url[0] ) { $good_protocol_url = $url; } else { if ( ! is_array( $protocols ) ) { $protocols = \wp_allowed_protocols(); } $good_protocol_url = \wp_kses_bad_protocol( $url, $protocols ); if ( strtolower( $good_protocol_url ) != strtolower( $url ) ) { return ''; } } return \apply_filters( 'clean_url', $good_protocol_url, $original_url, $context ); } } �������������������������������������������Util/UsageTracking.php������������������������������������������������������������������������������0000644�����������������00000014147�15021223045�0010722 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * This file contains the UsageTracking class * * @package NextGEN Gallery */ namespace Imagely\NGG\Util; use Imagely\NGG\Admin\Onboarding_Wizard; /** * Class UsageTracking * * This class is responsible for tracking usage of the NextGen plugin and sending check-in data. */ class UsageTracking { /** * The endpoint to send the checkin data to. * * @var string */ protected $endpoint = ''; /** * The user agent to send with the request. * * @var string */ protected $user_agent = ''; /** * Constructor. */ public function __construct() { $this->user_agent = 'NextGen/' . NGG_PLUGIN_VERSION . '; ' . get_bloginfo( 'url' ); $this->endpoint = 'https://evusage.enviragallery.com/v1/nextgen-checkin/'; } /** * Register hooks. * * @since 3.59.5 * * @return void */ public function hooks() { $onboarding_data = get_option( 'ngg_onboarding_data', [] ); $enabled = $onboarding_data['_usage_tracking'] ?? false; $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN ); // Check the license type. $type = ( new Onboarding_Wizard() )->get_license_type(); if ( ! $enabled || 'lite' !== $type ) { return; // Return early if usage tracking is disabled or the license type is not lite. } add_action( 'admin_init', [ $this, 'schedule_send' ] ); add_filter( 'cron_schedules', [ $this, 'add_schedules' ], 99 ); add_action( 'nextgen_usage_tracking_cron', [ $this, 'send_checkin' ] ); } /** * Get the settings to send. * * @since 3.59.5 * @return array */ protected function get_settings() { $settings = get_option( 'ngg_options', [] ); $settings_to_send = []; foreach ( $settings as $key => $value ) { if ( empty( $value ) || ( false !== strpos( $key, 'stripe' ) ) ) { continue; } $settings_to_send[ $key ] = $value; } return $settings_to_send; } /** * Get the data to send * * @since 3.59.5 * * @return array */ private function get_data() { $data = []; // Retrieve current theme info. $theme_data = wp_get_theme(); $sites_count = 1; if ( is_multisite() ) { if ( function_exists( 'get_blog_count' ) ) { $sites_count = get_blog_count(); } else { $sites_count = 'Not Set'; } } $settings = $this->get_settings(); $data['nextgen_version'] = NGG_PLUGIN_VERSION; $data['ng_type'] = 'lite'; $data['php_version'] = phpversion(); $data['wp_version'] = get_bloginfo( 'version' ); $data['server'] = $_SERVER['SERVER_SOFTWARE'] ?? 'CLI'; // phpcs:ignore $data['over_time'] = get_option( 'nextgen_over_time', [] ); $data['multisite'] = is_multisite(); $data['url'] = home_url(); $data['themename'] = $theme_data->get( 'Name' ); $data['themeversion'] = $theme_data->get( 'Version' ); $data['email'] = get_bloginfo( 'admin_email' ); $data['settings'] = $settings; $data['pro'] = false; $data['sites'] = $sites_count; $data['usagetracking'] = false; $data['usercount'] = function_exists( 'get_user_count' ) ? get_user_count() : 'Not Set'; $data['timezoneoffset'] = wp_date( 'P' ); // Not used on sol. $data['tracking_mode'] = ''; $data['events_mode'] = ''; $data['usesauth'] = ''; $data['autoupdate'] = false; // Retrieve current plugin information. if ( ! function_exists( 'get_plugins' ) ) { include_once ABSPATH . '/wp-admin/includes/plugin.php'; } $plugins = array_keys( get_plugins() ); $active_plugins = get_option( 'active_plugins', [] ); foreach ( $plugins as $key => $plugin ) { if ( in_array( $plugin, $active_plugins, true ) ) { // Remove active plugins from list so we can show active and inactive separately. unset( $plugins[ $key ] ); } } $data['active_plugins'] = $active_plugins; $data['inactive_plugins'] = $plugins; $data['locale'] = get_locale(); return $data; } /** * Send the checkin * * @since 3.59.5 * * @return bool */ public function send_checkin( $ignore_last_checkin = false ) { $ignore_last_checkin = $ignore_last_checkin || defined( DOING_CRON ) && DOING_CRON; $home_url = trailingslashit( home_url() ); if ( strpos( $home_url, 'imagely.com' ) !== false ) { return false; } // Send a maximum of once per week. $last_send = get_option( 'nextgen_usage_tracking_last_checkin' ); if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) && ! $ignore_last_checkin ) { return false; } $request = wp_remote_post( $this->endpoint, [ 'method' => 'POST', 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.1', 'blocking' => false, 'body' => $this->get_data(), 'user-agent' => $this->user_agent, ] ); // If we have completed successfully, recheck in 1 week. update_option( 'nextgen_usage_tracking_last_checkin', time() ); return true; } /** * Schedule the checkin * * @since 3.59.5 * @return void */ public function schedule_send() { if ( wp_next_scheduled( 'nextgen_usage_tracking_cron' ) ) { return; } $tracking = []; $tracking['day'] = wp_rand( 0, 6 ); $tracking['hour'] = wp_rand( 0, 23 ); $tracking['minute'] = wp_rand( 0, 59 ); $tracking['second'] = wp_rand( 0, 59 ); $tracking['offset'] = ( $tracking['day'] * DAY_IN_SECONDS ); $tracking['offset'] += ( $tracking['hour'] * HOUR_IN_SECONDS ); $tracking['offset'] += ( $tracking['minute'] * MINUTE_IN_SECONDS ); $tracking['offset'] += $tracking['second']; $tracking['initsend'] = strtotime( 'next sunday' ) + $tracking['offset']; wp_schedule_event( $tracking['initsend'], 'weekly', 'nextgen_usage_tracking_cron' ); update_option( 'nextgen_usage_tracking_config', wp_json_encode( $tracking ) ); } /** * Add weekly schedule * * @since 3.59.5 * * @param array $schedules Array of schedules. * * @return array */ public function add_schedules( $schedules = [] ) { if ( isset( $schedules['weekly'] ) ) { return $schedules; } $schedules['weekly'] = [ 'interval' => 604800, 'display' => __( 'Once Weekly', 'nextgen-gallery' ), ]; return $schedules; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Util/Sanitization.php�������������������������������������������������������������������������������0000644�����������������00000001223�15021223045�0010636 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Util; class Sanitization { /** * Recursively calls stripslashes() on strings, arrays, and objects * * @param mixed $value Value to be processed * @return mixed Resulting value */ public static function recursive_stripslashes( $value ) { if ( is_string( $value ) ) { $value = stripslashes( $value ); } elseif ( is_array( $value ) ) { foreach ( $value as &$tmp ) { $tmp = self::recursive_stripslashes( $tmp ); } } elseif ( is_object( $value ) ) { foreach ( get_object_vars( $value ) as $key => $data ) { $value->{$key} = self::recursive_stripslashes( $data ); } } return $value; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������REST/Manager.php������������������������������������������������������������������������������������0000644�����������������00000000436�15021223045�0007401 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\REST; use Imagely\NGG\REST\Admin\AttachToPost; use Imagely\NGG\REST\Admin\Block; class Manager { public static function rest_api_init() { $block = new Block(); $block->register_routes(); $atp = new AttachToPost(); $atp->register_routes(); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������REST/Admin/Block.php��������������������������������������������������������������������������������0000644�����������������00000004362�15021223045�0010113 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API for the NextGEN Gallery Block * * @package NextGEN Gallery */ namespace Imagely\NGG\REST\Admin; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; /** * Class Block represents the REST API for the NextGEN Gallery Block */ class Block extends \WP_REST_Controller { /** * Block constructor. */ public function __construct() { $this->namespace = 'ngg/v1'; $this->rest_base = 'admin/block/image'; } /** * Register the routes for the objects of the controller. */ public function register_routes() { \register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<image_id>.*)/', [ 'args' => [ 'image_id' => [ 'description' => \__( 'Image ID', 'nggallery' ), 'type' => 'integer', 'required' => true, ], ], [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [ $this, 'get_item' ], 'permission_callback' => [ $this, 'get_item_permissions_check' ], ], ] ); } /** * Check if a given request has access to get information about a specific item. * * @param \WP_REST_Request $request Full data about the request. * * @return bool */ public function get_item_permissions_check( $request ): bool { // Verify the nonce. $nonce = $request->get_header('X-WP-Nonce'); if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) { return false; } // Check if the user has the capability to edit posts. return current_user_can( 'edit_posts' ); } /** Get the specific image. * * @param \WP_REST_Request $request Full data about the request. * @return \WP_Error|\WP_REST_Response */ public function get_item( $request ) { $id = $request->get_param( 'image_id' ); $image = ImageMapper::get_instance()->find( $id ); if ( ! $image ) { return new \WP_Error( 'invalid_image_id', 'Invalid image ID', [ 'status' => 404 ] ); } $storage = StorageManager::get_instance(); $image->thumbnail_url = $storage->get_image_url( $image, 'thumb' ); $image->image_url = $storage->get_image_url( $image, 'full' ); return new \WP_REST_Response( [ 'success' => true, 'image' => $image, ] ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������REST/Admin/AttachToPost.php�������������������������������������������������������������������������0000644�����������������00000007646�15021223045�0011446 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\REST\Admin; use Imagely\NGG\DataMappers\Album as AlbumMapper; use Imagely\NGG\DataMappers\Gallery as GalleryMapper; use Imagely\NGG\DataMappers\Image as ImageMapper; use Imagely\NGG\DataStorage\Manager as StorageManager; use Imagely\NGG\DataTypes\DisplayedGallery; class AttachToPost extends \WP_REST_Controller { public function __construct() { $this->namespace = 'ngg/v1'; $this->rest_base = 'admin/attach_to_post/'; } public function register_routes() { \register_rest_route( $this->namespace, '/' . $this->rest_base . 'galleries', [ [ 'methods' => \WP_REST_Server::ALLMETHODS, 'callback' => [ $this, 'get_galleries' ], 'permission_callback' => [ $this, 'get_items_permissions_check' ], ], ] ); \register_rest_route( $this->namespace, '/' . $this->rest_base . 'albums', [ [ 'methods' => \WP_REST_Server::ALLMETHODS, 'callback' => [ $this, 'get_albums' ], 'permission_callback' => [ $this, 'get_items_permissions_check' ], ], ] ); \register_rest_route( $this->namespace, '/' . $this->rest_base . 'tags', [ [ 'methods' => \WP_REST_Server::ALLMETHODS, 'callback' => [ $this, 'get_tags' ], 'permission_callback' => [ $this, 'get_items_permissions_check' ], ], ] ); \register_rest_route( $this->namespace, '/' . $this->rest_base . 'images', [ [ 'methods' => \WP_REST_Server::ALLMETHODS, 'callback' => [ $this, 'get_images' ], 'permission_callback' => [ $this, 'get_items_permissions_check' ], ], ] ); } public function get_items_permissions_check( $request ) { return current_user_can( 'NextGEN Attach Interface' ); } public function get_galleries( $request ) { return new \WP_REST_Response( [ 'items' => GalleryMapper::get_instance()->find_all(), ] ); } public function get_albums( $request ) { return new \WP_REST_Response( [ 'items' => AlbumMapper::get_instance()->find_all(), ] ); } public function get_tags( $request ) { $response = []; $response['items'] = []; $params = [ 'fields' => 'names' ]; foreach ( \get_terms( 'ngg_tag', $params ) as $term ) { $response['items'][] = [ 'id' => $term, 'title' => $term, 'name' => $term, ]; } return new \WP_REST_Response( $response ); } public function get_images( $request ) { global $wpdb; $response = []; $params = $request->get_param( 'displayed_gallery' ); $storage = StorageManager::get_instance(); $image_mapper = ImageMapper::get_instance(); $displayed_gallery = new DisplayedGallery(); foreach ( $params as $key => $value ) { $key = $wpdb->_escape( $key ); if ( ! in_array( $key, [ 'container_ids', 'entity_ids', 'sortorder' ] ) ) { $value = esc_sql( $value ); } $displayed_gallery->$key = $value; } $response['items'] = $displayed_gallery->get_entities( false, false, false, 'both' ); foreach ( $response['items'] as &$entity ) { $image = $entity; if ( in_array( $displayed_gallery->source, [ 'album','albums' ] ) ) { // Set the alttext of the preview image to the name of the gallery or album if ( ( $image = $image_mapper->find( $entity->previewpic ) ) ) { if ( $entity->is_album ) { $image->alttext = sprintf( \__( 'Album: %s', 'nggallery' ), $entity->name ); } else { $image->alttext = sprintf( \__( 'Gallery: %s', 'nggallery' ), $entity->title ); } } // Prefix the id of an album with 'a' if ( $entity->is_album ) { $id = $entity->{$entity->id_field}; $entity->{$entity->id_field} = 'a' . $id; } } // Get the thumbnail $entity->thumb_url = $storage->get_image_url( $image, 'thumb', true ); $entity->thumb_html = $storage->get_image_html( $image, 'thumb' ); } return new \WP_REST_Response( $response ); } } ������������������������������������������������������������������������������������������Admin/RequirementsManager.php�����������������������������������������������������������������������0000644�����������������00000010541�15021223045�0012256 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Admin; use Imagely\NGG\Admin\Notifications\Manager as NotificationsManager; class RequirementsManager { private static $instance = null; protected $requirements = []; protected $groups = []; protected $notifications = []; public function __construct() { $this->set_initial_groups(); } /** * @return RequirementsManager */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new RequirementsManager(); } return self::$instance; } protected function set_initial_groups() { // Requirements can be added with any group key desired but only registered groups will be displayed. $this->groups = apply_filters( 'ngg_admin_requirements_manager_groups', [ 'phpext' => esc_html__( 'NextGen Gallery requires the following PHP extensions to function correctly. Please contact your hosting provider or systems admin and ask them for assistance:', 'nggallery' ), 'phpver' => esc_html__( 'NextGen Gallery has degraded functionality because of your PHP version. Please contact your hosting provider or systems admin and ask them for assistance:', 'nggallery' ), 'dirperms' => esc_html__( 'NextGen Gallery has found an issue trying to access the following files or directories. Please ensure the following locations have the correct permissions:', 'nggallery' ), ] ); } public static function register_requirements() { $manager = self::get_instance(); $manager->add( 'nextgen_data_sanitation', 'phpext', function () { return class_exists( 'DOMDocument' ); }, [ 'message' => esc_html__( 'XML is strongly encouraged for safely editing image data', 'nggallery' ) ] ); $manager->add( 'nextgen_data_gd_requirement', 'phpext', function () { return function_exists( 'gd_info' ); }, [ 'message' => esc_html__( 'GD is required for generating image thumbnails, resizing images, and generating watermarks', 'nggallery' ), 'dismissable' => false, ] ); $manager->add( 'nextgen_data_ctypes_requirement', 'phpext', function () { return function_exists( 'ctype_lower' ); }, [ 'message' => esc_html__( 'ctype methods are required for securing user submitted data', 'nggallery' ), 'dismissable' => false, ] ); } /** * @param string $name Unique notification ID * @param string $group Choose one of phpext | phpver | dirperms * @param callable $callback Method that determines whether the notification should display * @param array $data Possible keys: className, message, dismissable */ public function add( $name, $group, $callback, $data ) { $this->requirements[ $group ][ $name ] = new RequirementsNotice( $name, $callback, $data ); } /** * @param string $name */ public function remove( $name ) { unset( $this->notifications[ $name ] ); } public function create_notification() { foreach ( $this->groups as $groupID => $groupLabel ) { if ( empty( $this->requirements[ $groupID ] ) ) { continue; } $dismissable = true; $notices = []; foreach ( $this->requirements[ $groupID ] as $key => $requirement ) { $passOrFail = $requirement->run_callback(); if ( ! $passOrFail ) { // If any of the notices can't be dismissed then all notices in that group can't be dismissed. if ( ! $requirement->is_dismissable() ) { // Add important notices to the beginning of the list. $dismissable = false; array_unshift( $notices, $requirement ); } else { $notices[] = $requirement; } } } // Don't display empty group notices. if ( empty( $notices ) ) { continue; } // Generate the combined message for this group. $message = '<p>' . $this->groups[ $groupID ] . '</p><ul>'; foreach ( $notices as $requirement ) { // Make non-dismissable notifications bold. $string = $requirement->is_dismissable() ? $requirement->get_message() : '<strong>' . $requirement->get_message() . '</strong>'; $message .= '<li>' . $string . '</li>'; } $message .= '</ul>'; // Generate the notice object. $name = 'ngg_requirement_notice_' . $groupID . '_' . md5( $message ); $notice = new RequirementsNotice( $name, '__return_true', [ 'dismissable' => $dismissable, 'message' => $message, ] ); NotificationsManager::get_instance()->add( $name, $notice ); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������Admin/FormManager.php�������������������������������������������������������������������������������0000644�����������������00000004453�15021223045�0010503 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php namespace Imagely\NGG\Admin; class FormManager { protected static $instance = null; protected $forms = []; /** * @return FormManager */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new FormManager(); } return self::$instance; } /** * Moves the registration of the first form so that it follows the second form. * * @param string $type Which form grouping to manipulate. * @param string $form_name The name of the form to move. * @param string $form_to_follow_name The form that $form_name will follow. * @return void */ public function move_form_to_follow_other_form( string $type, string $form_name, string $form_to_follow_name ) { if ( ! is_array( $this->forms[ $type ] ) ) { return; } $index_one = array_search( $form_name, $this->forms[ $type ], true ); $index_two = array_search( $form_to_follow_name, $this->forms[ $type ], true ); if ( ! $index_one || ! $index_two ) { return; } $value = $this->forms[ $type ][ $index_one ]; unset( $this->forms[ $type ][ $index_one ] ); array_splice( $this->forms[ $type ], $index_two + 1, 0, $value ); } /** * @param string $type * @param array|string $form_names * @return int Results of get_form_count($type) */ public function add_form( $type, $form_names ) { if ( ! isset( $this->forms[ $type ] ) ) { $this->forms[ $type ] = []; } if ( ! is_array( $form_names ) ) { $form_names = [ $form_names ]; } foreach ( $form_names as $form ) { $this->forms[ $type ][] = $form; } return $this->get_form_count( $type ); } /** * @param string $type * @param bool $instantiate (optional). * @return array */ public function get_forms( $type, $instantiate = false ) { $retval = []; if ( isset( $this->forms[ $type ] ) ) { if ( ! $instantiate ) { $retval = $this->forms[ $type ]; } else { foreach ( $this->forms[ $type ] as $context ) { if ( class_exists( '\C_Component_Registry' ) ) { $retval[] = \C_Component_Registry::get_instance()->get_utility( 'I_Form', $context ); } } } } return $retval; } /** * @param string $type Form type. * @return int */ public function get_form_count( $type ) { return ( isset( $this->forms[ $type ] ) ) ? count( $this->forms[ $type ] ) : 0; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Admin/About.php�������������������������������������������������������������������������������������0000644�����������������00000105562�15021223045�0007362 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Welcome class. * * @since 1.8.1 * * @package Imagely_Gallery * @author Imagely Gallery Team */ namespace Imagely\NGG\Admin; // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Welcome Class * * @since 1.7.0 * * @package Imagely_Gallery * @author Imagely Gallery Team <support@imagely.com> */ class About { /** * Imagely Welcome Pages. * * @var array */ public $pages = [ 'nextgen-about-us', ]; /** * Holds the submenu pagehook. * * @since 1.7.0 * * @var string` */ public $hook; /** * Helper method for installed plugins * * @since 1.7.0 * * @var array */ public $installed_plugins; /** * Class Hooks * * @since 1.8.7 * * @return void */ public function hooks() { // Add custom addons submenu. add_action( 'admin_menu', [ $this, 'admin_menu' ], 15 ); // Add scripts and styles. add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_styles' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] ); // Misc. add_action( 'admin_print_scripts', [ $this, 'disable_admin_notices' ] ); // Ajax. add_action( 'wp_ajax_nextgen_install_am_plugin', [ $this, 'install_am_plugin' ] ); add_action( 'wp_ajax_nextgen_deactivate_am_plugin', [ $this, 'deactivate_am_plugin' ] ); add_action( 'wp_ajax_nextgen_activate_am_plugin', [ $this, 'activate_am_plugin' ] ); } /** * Register and enqueue addons page specific JS. * * @since 1.5.0 */ public function enqueue_admin_scripts() { global $current_screen; if ( ! empty( $current_screen->base ) && strpos( $current_screen->base, 'nextgen-gallery_page' ) !== false ) { wp_register_script( NGG_PLUGIN_SLUG . '-about-script', plugins_url( 'assets/js/min/about-min.js', NGG_PLUGIN_FILE ), [ 'jquery' ], NGG_PLUGIN_VERSION, true ); wp_enqueue_script( NGG_PLUGIN_SLUG . '-about-script' ); wp_localize_script( NGG_PLUGIN_SLUG . '-about-script', 'nextgen_about', [ 'ajax' => admin_url( 'admin-ajax.php' ), 'activate_nonce' => wp_create_nonce( 'nextgen-activate-partner' ), 'deactivate_nonce' => wp_create_nonce( 'nextgen-deactivate-partner' ), 'install_nonce' => wp_create_nonce( 'nextgen-install-partner' ), 'active' => __( 'Status: Active', 'nggallery' ), 'activate' => __( 'Activate', 'nggallery' ), 'activating' => __( 'Activating...', 'nggallery' ), 'deactivate' => __( 'Deactivate', 'nggallery' ), 'deactivating' => __( 'Deactivating...', 'nggallery' ), 'inactive' => __( 'Status: Inactive', 'nggallery' ), 'install' => __( 'Install', 'nggallery' ), 'installing' => __( 'Installing...', 'nggallery' ), 'proceed' => __( 'Proceed', 'nggallery' ), ] ); } } /** * Register and enqueue addons page specific CSS. * * @since 1.8.1 * * @return void */ public function enqueue_admin_styles() { global $current_screen; if ( ! empty( $current_screen->base ) && strpos( $current_screen->base, 'nextgen-gallery-about-us' ) !== false ) { wp_register_style( NGG_PLUGIN_SLUG . '-about-style', plugins_url( 'assets/css/about.css', NGG_PLUGIN_FILE ), [], NGG_PLUGIN_VERSION ); wp_enqueue_style( NGG_PLUGIN_SLUG . '-about-style' ); } // Run a hook to load in custom styles. do_action( 'nextgen_about_styles' ); } /** * Making page as clean as possible * * @since 1.8.1 * * @return void */ public function disable_admin_notices() { global $wp_filter; global $current_screen; if ( ! empty( $current_screen->base ) && strpos( $current_screen->base, 'nextgen-gallery_page' ) !== false ) { if ( isset( $wp_filter['user_admin_notices'] ) ) { unset( $wp_filter['user_admin_notices'] ); } if ( isset( $wp_filter['admin_notices'] ) ) { unset( $wp_filter['admin_notices'] ); } if ( isset( $wp_filter['all_admin_notices'] ) ) { unset( $wp_filter['all_admin_notices'] ); } } } /** * Helper Method to get AM Plugins * * @since 1.8.7 * * @return array */ public function get_am_plugins() { $images_url = trailingslashit( NGG_PLUGIN_URI . 'assets/images/about' ); $plugins = [ 'optinmonster' => [ 'icon' => $images_url . 'plugin-om.png', 'name' => esc_html__( 'OptinMonster', 'nggallery' ), 'description' => esc_html__( 'Instantly get more subscribers, leads, and sales with the #1 conversion optimization toolkit. Create high converting popups, announcement bars, spin a wheel, and more with smart targeting and personalization.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/optinmonster/', 'url' => 'https://downloads.wordpress.org/plugin/optinmonster.zip', 'basename' => 'optinmonster/optin-monster-wp-api.php', ], 'google-analytics-for-wordpress' => [ 'icon' => $images_url . 'plugin-mi.png', 'name' => esc_html__( 'MonsterInsights', 'nggallery' ), 'description' => esc_html__( 'The leading WordPress analytics plugin that shows you how people find and use your website, so you can make data driven decisions to grow your business. Properly set up Google Analytics without writing code.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/google-analytics-for-wordpress/', 'url' => 'https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.zip', 'basename' => 'google-analytics-for-wordpress/googleanalytics.php', 'pro' => [ 'plug' => 'google-analytics-premium/googleanalytics-premium.php', 'icon' => $images_url . 'plugin-mi.png', 'name' => esc_html__( 'MonsterInsights Pro', 'nggallery' ), 'description' => esc_html__( 'The leading WordPress analytics plugin that shows you how people find and use your website, so you can make data driven decisions to grow your business. Properly set up Google Analytics without writing code.', 'nggallery' ), 'url' => 'https://www.monsterinsights.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'wp-mail-smtp/wp_mail_smtp.php' => [ 'icon' => $images_url . 'plugin-smtp.png', 'name' => esc_html__( 'WP Mail SMTP', 'nggallery' ), 'description' => esc_html__( "Improve your WordPress email deliverability and make sure that your website emails reach user's inbox with the #1 SMTP plugin for WordPress. Over 3 million websites use it to fix WordPress email issues.", 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/wp-mail-smtp/', 'url' => 'https://downloads.wordpress.org/plugin/wp-mail-smtp.zip', 'basename' => 'wp-mail-smtp/wp_mail_smtp.php', 'pro' => [ 'plug' => 'wp-mail-smtp-pro/wp_mail_smtp.php', 'icon' => $images_url . 'plugin-smtp.png', 'name' => esc_html__( 'WP Mail SMTP Pro', 'nggallery' ), 'description' => esc_html__( "Improve your WordPress email deliverability and make sure that your website emails reach user's inbox with the #1 SMTP plugin for WordPress. Over 3 million websites use it to fix WordPress email issues.", 'nggallery' ), 'url' => 'https://wpmailsmtp.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'all-in-one-seo-pack/all_in_one_seo_pack.php' => [ 'icon' => $images_url . 'plugin-aioseo.png', 'name' => esc_html__( 'AIOSEO', 'nggallery' ), 'description' => esc_html__( "The original WordPress SEO plugin and toolkit that improves your website's search rankings. Comes with all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more.", 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/all-in-one-seo-pack/', 'url' => 'https://downloads.wordpress.org/plugin/all-in-one-seo-pack.zip', 'basename' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', 'pro' => [ 'plug' => 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', 'icon' => $images_url . 'plugin-aioseo.png', 'name' => esc_html__( 'AIOSEO Pro', 'nggallery' ), 'description' => esc_html__( "The original WordPress SEO plugin and toolkit that improves your website's search rankings. Comes with all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more.", 'nggallery' ), 'url' => 'https://aioseo.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'coming-soon/coming-soon.php' => [ 'icon' => $images_url . 'plugin-seedprod.png', 'name' => esc_html__( 'SeedProd', 'nggallery' ), 'description' => esc_html__( 'The fastest drag & drop landing page builder for WordPress. Create custom landing pages without writing code, connect them with your CRM, collect subscribers, and grow your audience. Trusted by 1 million sites.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/coming-soon/', 'url' => 'https://downloads.wordpress.org/plugin/coming-soon.zip', 'basename' => 'coming-soon/coming-soon.php', 'pro' => [ 'plug' => 'seedprod-coming-soon-pro-5/seedprod-coming-soon-pro-5.php', 'icon' => $images_url . 'plugin-seedprod.png', 'name' => esc_html__( 'SeedProd Pro', 'nggallery' ), 'description' => esc_html__( 'The fastest drag & drop landing page builder for WordPress. Create custom landing pages without writing code, connect them with your CRM, collect subscribers, and grow your audience. Trusted by 1 million sites.', 'nggallery' ), 'url' => 'https://www.seedprod.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'rafflepress/rafflepress.php' => [ 'icon' => $images_url . 'plugin-rp.png', 'name' => esc_html__( 'RafflePress', 'nggallery' ), 'description' => esc_html__( 'Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with the most powerful giveaways & contests plugin for WordPress.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/rafflepress/', 'url' => 'https://downloads.wordpress.org/plugin/rafflepress.zip', 'basename' => 'rafflepress/rafflepress.php', 'pro' => [ 'plug' => 'rafflepress-pro/rafflepress-pro.php', 'icon' => $images_url . 'plugin-rp.png', 'name' => esc_html__( 'RafflePress Pro', 'nggallery' ), 'description' => esc_html__( 'Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with the most powerful giveaways & contests plugin for WordPress.', 'nggallery' ), 'url' => 'https://rafflepress.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'pushengage/main.php' => [ 'icon' => $images_url . 'plugin-pushengage.png', 'name' => esc_html__( 'PushEngage', 'nggallery' ), 'description' => esc_html__( 'Connect with your visitors after they leave your website with the leading web push notification software. Over 10,000+ businesses worldwide use PushEngage to send 15 billion notifications each month.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/pushengage/', 'url' => 'https://downloads.wordpress.org/plugin/pushengage.zip', 'basename' => 'pushengage/main.php', ], 'instagram-feed/instagram-feed.php' => [ 'icon' => $images_url . 'plugin-sb-instagram.png', 'name' => esc_html__( 'Smash Balloon Instagram Feeds', 'nggallery' ), 'description' => esc_html__( 'Easily display Instagram content on your WordPress site without writing any code. Comes with multiple templates, ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/instagram-feed/', 'url' => 'https://downloads.wordpress.org/plugin/instagram-feed.zip', 'basename' => 'instagram-feed/instagram-feed.php', 'pro' => [ 'plug' => 'instagram-feed-pro/instagram-feed.php', 'icon' => $images_url . 'plugin-sb-instagram.png', 'name' => esc_html__( 'Smash Balloon Instagram Feeds Pro', 'nggallery' ), 'description' => esc_html__( 'Easily display Instagram content on your WordPress site without writing any code. Comes with multiple templates, ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites.', 'nggallery' ), 'url' => 'https://smashballoon.com/instagram-feed/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'custom-facebook-feed/custom-facebook-feed.php' => [ 'icon' => $images_url . 'plugin-sb-fb.png', 'name' => esc_html__( 'Smash Balloon Facebook Feeds', 'nggallery' ), 'description' => esc_html__( 'Easily display Facebook content on your WordPress site without writing any code. Comes with multiple templates, ability to embed albums, group content, reviews, live videos, comments, and reactions.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/custom-facebook-feed/', 'url' => 'https://downloads.wordpress.org/plugin/custom-facebook-feed.zip', 'basename' => 'custom-facebook-feed/custom-facebook-feed.php', 'pro' => [ 'plug' => 'custom-facebook-feed-pro/custom-facebook-feed.php', 'icon' => $images_url . 'plugin-sb-fb.png', 'name' => esc_html__( 'Smash Balloon Facebook Feeds Pro', 'nggallery' ), 'description' => esc_html__( 'Easily display Facebook content on your WordPress site without writing any code. Comes with multiple templates, ability to embed albums, group content, reviews, live videos, comments, and reactions.', 'nggallery' ), 'url' => 'https://smashballoon.com/custom-facebook-feed/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'feeds-for-youtube/youtube-feed.php' => [ 'icon' => $images_url . 'plugin-sb-youtube.png', 'name' => esc_html__( 'Smash Balloon YouTube Feeds', 'nggallery' ), 'description' => esc_html__( 'Easily display YouTube videos on your WordPress site without writing any code. Comes with multiple layouts, ability to embed live streams, video filtering, ability to combine multiple channel videos, and more.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/feeds-for-youtube/', 'url' => 'https://downloads.wordpress.org/plugin/feeds-for-youtube.zip', 'basename' => 'feeds-for-youtube/youtube-feed.php', 'pro' => [ 'plug' => 'youtube-feed-pro/youtube-feed.php', 'icon' => $images_url . 'plugin-sb-youtube.png', 'name' => esc_html__( 'Smash Balloon YouTube Feeds Pro', 'nggallery' ), 'description' => esc_html__( 'Easily display YouTube videos on your WordPress site without writing any code. Comes with multiple layouts, ability to embed live streams, video filtering, ability to combine multiple channel videos, and more.', 'nggallery' ), 'url' => 'https://smashballoon.com/youtube-feed/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'custom-twitter-feeds/custom-twitter-feed.php' => [ 'icon' => $images_url . 'plugin-sb-twitter.png', 'name' => esc_html__( 'Smash Balloon Twitter Feeds', 'nggallery' ), 'description' => esc_html__( 'Easily display Twitter content in WordPress without writing any code. Comes with multiple layouts, ability to combine multiple Twitter feeds, Twitter card support, tweet moderation, and more.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/custom-twitter-feeds/', 'url' => 'https://downloads.wordpress.org/plugin/custom-twitter-feeds.zip', 'basename' => 'custom-twitter-feeds/custom-twitter-feed.php', 'pro' => [ 'plug' => 'custom-twitter-feeds-pro/custom-twitter-feed.php', 'icon' => $images_url . 'plugin-sb-twitter.png', 'name' => esc_html__( 'Smash Balloon Twitter Feeds Pro', 'nggallery' ), 'description' => esc_html__( 'Easily display Twitter content in WordPress without writing any code. Comes with multiple layouts, ability to combine multiple Twitter feeds, Twitter card support, tweet moderation, and more.', 'nggallery' ), 'url' => 'https://smashballoon.com/custom-twitter-feeds/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'trustpulse-api/trustpulse.php' => [ 'icon' => $images_url . 'plugin-trustpulse.png', 'name' => esc_html__( 'TrustPulse', 'nggallery' ), 'description' => esc_html__( 'Boost your sales and conversions by up to 15% with real-time social proof notifications. TrustPulse helps you show live user activity and purchases to help convince other users to purchase.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/trustpulse-api/', 'url' => 'https://downloads.wordpress.org/plugin/trustpulse-api.zip', 'basename' => 'trustpulse-api/trustpulse.php', ], 'searchwp/index.php' => [ 'icon' => $images_url . 'plugin-searchwp.png', 'name' => esc_html__( 'SearchWP', 'nggallery' ), 'description' => esc_html__( 'The most advanced WordPress search plugin. Customize your WordPress search algorithm, reorder search results, track search metrics, and everything you need to leverage search to grow your business.', 'nggallery' ), 'wporg' => false, 'url' => 'https://searchwp.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], 'affiliate-wp/affiliate-wp.php' => [ 'icon' => $images_url . 'plugin-affwp.png', 'name' => esc_html__( 'AffiliateWP', 'nggallery' ), 'description' => esc_html__( 'The #1 affiliate management plugin for WordPress. Easily create an affiliate program for your eCommerce store or membership site within minutes and start growing your sales with the power of referral marketing.', 'nggallery' ), 'wporg' => false, 'url' => 'https://affiliatewp.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], 'stripe/stripe-checkout.php' => [ 'icon' => $images_url . 'plugin-wp-simple-pay.png', 'name' => esc_html__( 'WP Simple Pay', 'nggallery' ), 'description' => esc_html__( 'The #1 Stripe payments plugin for WordPress. Start accepting one-time and recurring payments on your WordPress site without setting up a shopping cart. No code required.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/stripe/', 'url' => 'https://downloads.wordpress.org/plugin/stripe.zip', 'basename' => 'stripe/stripe-checkout.php', 'pro' => [ 'plug' => 'wp-simple-pay-pro-3/simple-pay.php', 'icon' => $images_url . 'plugin-wp-simple-pay.png', 'name' => esc_html__( 'WP Simple Pay Pro', 'nggallery' ), 'description' => esc_html__( 'The #1 Stripe payments plugin for WordPress. Start accepting one-time and recurring payments on your WordPress site without setting up a shopping cart. No code required.', 'nggallery' ), 'url' => 'https://wpsimplepay.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'easy-digital-downloads/easy-digital-downloads.php' => [ 'icon' => $images_url . 'plugin-edd.png', 'name' => esc_html__( 'Easy Digital Downloads', 'nggallery' ), 'description' => esc_html__( 'The best WordPress eCommerce plugin for selling digital downloads. Start selling eBooks, software, music, digital art, and more within minutes. Accept payments, manage subscriptions, advanced access control, and more.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/easy-digital-downloads/', 'url' => 'https://downloads.wordpress.org/plugin/easy-digital-downloads.zip', 'basename' => 'easy-digital-downloads/easy-digital-downloads.php', ], 'sugar-calendar-lite/sugar-calendar-lite.php' => [ 'icon' => $images_url . 'plugin-sugarcalendar.png', 'name' => esc_html__( 'Sugar Calendar', 'nggallery' ), 'description' => esc_html__( 'A simple & powerful event calendar plugin for WordPress that comes with all the event management features including payments, scheduling, timezones, ticketing, recurring events, and more.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/sugar-calendar-lite/', 'url' => 'https://downloads.wordpress.org/plugin/sugar-calendar-lite.zip', 'basename' => 'sugar-calendar-lite/sugar-calendar-lite.php', 'pro' => [ 'plug' => 'sugar-calendar/sugar-calendar.php', 'icon' => $images_url . 'plugin-sugarcalendar.png', 'name' => esc_html__( 'Sugar Calendar Pro', 'nggallery' ), 'description' => esc_html__( 'A simple & powerful event calendar plugin for WordPress that comes with all the event management features including payments, scheduling, timezones, ticketing, recurring events, and more.', 'nggallery' ), 'url' => 'https://sugarcalendar.com/?utm_source=imagelylite&utm_medium=link&utm_campaign=About%20Imagely', 'act' => 'go-to-url', ], ], 'charitable/charitable.php' => [ 'icon' => $images_url . 'plugin-charitable.png', 'name' => esc_html__( 'WP Charitable', 'nggallery' ), 'description' => esc_html__( 'Top-rated WordPress donation and fundraising plugin. Over 10,000+ non-profit organizations and website owners use Charitable to create fundraising campaigns and raise more money online.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/charitable/', 'url' => 'https://downloads.wordpress.org/plugin/charitable.zip', 'basename' => 'charitable/charitable.php', ], 'insert-headers-and-footers/ihaf.php' => [ 'icon' => $images_url . 'plugin-wpcode.png', 'name' => esc_html__( 'WPCode', 'nggallery' ), 'description' => esc_html__( 'Future proof your WordPress customizations with the most popular code snippet management plugin for WordPress. Trusted by over 1,500,000+ websites for easily adding code to WordPress right from the admin area.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/insert-headers-and-footers/', 'url' => 'https://downloads.wordpress.org/plugin/insert-headers-and-footers.zip', 'basename' => 'insert-headers-and-footers/ihaf.php', ], 'duplicator/duplicator.php' => [ 'icon' => $images_url . 'plugin-duplicator.png', 'name' => esc_html__( 'Duplicator', 'nggallery' ), 'description' => esc_html__( 'Leading WordPress backup & site migration plugin. Over 1,500,000+ smart website owners use Duplicator to make reliable and secure WordPress backups to protect their websites. It also makes website migration really easy.', 'nggallery' ), 'wporg' => 'https://wordpress.org/plugins/duplicator/', 'url' => 'https://downloads.wordpress.org/plugin/duplicator.zip', 'basename' => 'duplicator/duplicator.php', ], 'soliloquy' => [ 'icon' => $images_url . 'soliloquy.png', 'name' => esc_html__( 'Slider by Soliloquy – Responsive Image Slider for WordPress', 'nggallery' ), 'description' => esc_html__( 'The best WordPress slider plugin. Drag & Drop responsive slider builder that helps you create a beautiful image slideshows with just a few clicks.', 'nggallery' ), 'url' => 'https://downloads.wordpress.org/plugin/soliloquy-lite.zip', 'basename' => 'soliloquy-lite/soliloquy-lite.php', ], ]; return $plugins; } /** * Register the Welcome submenu item for Imagely. * * @since 1.8.1 * * @return void */ public function admin_menu() { global $submenu; $whitelabel = apply_filters( 'nextgen_whitelabel', false ) ? '' : esc_html__( 'NextGen Gallery ', 'nggallery' ); // Register the submenus. add_submenu_page( NGGFOLDER, $whitelabel . esc_html__( 'About Us', 'nggallery' ), '<span style="color:#FFA500"> ' . esc_html__( 'About Us', 'nggallery' ) . '</span>', apply_filters( 'nextgen_menu_cap', 'manage_options' ), NGG_PLUGIN_SLUG . '-about-us', [ $this, 'about_page' ] ); } /** * Output tab navigation * * @since 2.2.0 * * @param string $tab Tab to highlight as active. */ public static function tab_navigation( $tab = 'whats_new' ) { ?> <ul class="nextgen-nav-tab-wrapper"> <li> <a class="nextgen-nav-tab <?php if ( isset( $_GET['page'] ) && 'nextgen-gallery-about-us' === sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?> nextgen-nav-tab-active<?php endif; ?>" href=" <?php echo esc_url( admin_url( add_query_arg( [ 'page' => 'nextgen-gallery-about-us', ], 'admin.php' ) ) ); ?> "> <?php esc_html_e( 'About Us', 'nggallery' ); ?> </a> </li> </ul> <?php } /** * Output the about screen. * * @since 1.8.5 */ public function about_page() { self::tab_navigation( __METHOD__ ); ?> <div class="nextgen-welcome-wrap nextgen-about"> <div class="nextgen-panel nextgen-lite-about-panel"> <div class="content"> <h3><?php esc_html_e( 'Hello and welcome to NextGEN Gallery, the most beginner-friendly WordPress Gallery Plugin. At NextGEN Gallery, we build software that helps you create beautiful galleries in minutes.', 'nggallery' ); ?></h3> <p><?php esc_html_e( 'Over the years, we found that most WordPress gallery plugins were bloated, buggy, slow, and very hard to use. So, we started with a simple goal: build a WordPress gallery system that’s both easy and powerful.', 'nggallery' ); ?></p> <p><?php esc_html_e( 'Our goal is to provide the easiest way to create beautiful galleries.', 'nggallery' ); ?></p> <p><?php esc_html_e( 'NextGEN Gallery is brought to you by the same team that’s behind the largest WordPress resource site, WPBeginner, the most popular lead-generation software, OptinMonster, the best WordPress analytics plugin, MonsterInsights, and more!', 'nggallery' ); ?></p> <p><?php esc_html_e( 'Yup, we know a thing or two about building awesome products that customers love.', 'nggallery' ); ?></p> </div> <div class="image"> <img alt="<?php esc_attr_e( 'Team', 'nggallery' ); ?>" src="<?php echo esc_url( trailingslashit( NGG_PLUGIN_URI ) . 'assets/images/about/team.jpg' ); ?> "> </div> </div> <div class="nextgen-am-plugins-wrap"> <?php foreach ( $this->get_am_plugins() as $partner ) : $this->get_plugin_card( $partner ); endforeach; ?> </div> </div> <!-- wrap --> <?php } /** * Helper method to get plugin card * * @param mixed $plugin False or plugin data array. * @return void */ public function get_plugin_card( $plugin = false ) { if ( ! $plugin ) { return; } $this->installed_plugins = get_plugins(); if ( ( isset( $plugin['basename'] ) && ! isset( $this->installed_plugins[ $plugin['basename'] ] ) ) || isset( $plugin['act'] ) ) { ?> <div class="nextgen-am-plugins"> <div class="nextgen-am-plugins-main"> <div> <img alt="<?php esc_attr_e( 'Icon', 'nggallery' ); ?>" src="<?php echo esc_attr( $plugin['icon'] ); ?>" width="64px" /> </div> <div> <h3><?php echo esc_html( $plugin['name'] ); ?></h3> <p class="nextgen-am-plugins-excerpt"><?php echo esc_html( $plugin['description'] ); ?></p> </div> </div> <div class="nextgen-am-plugins-footer"> <div class="nextgen-am-plugins-status">Status: <span>Not Installed</span></div> <div class="nextgen-am-plugins-install-wrap"> <span class="spinner nextgen-am-plugins-spinner"></span> <?php if ( isset( $plugin['basename'] ) ) : ?> <a href="#" class="button nextgen-primary-button nextgen-am-plugins-install" data-url="<?php echo esc_url( $plugin['url'] ); ?>" data-basename="<?php echo esc_attr( $plugin['basename'] ); ?>">Install Plugin</a> <?php else : ?> <a href="<?php echo esc_url( $plugin['url'] ); ?>" target="_blank" class="button nextgen-primary-button" data-url="<?php echo esc_url( $plugin['url'] ); ?>" >Install Plugin</a> <?php endif; ?> </div> </div> </div> <?php } elseif ( isset( $plugin['basename'] ) && is_plugin_active( $plugin['basename'] ) ) { ?> <div class="nextgen-am-plugins"> <div class="nextgen-am-plugins-main"> <div> <img alt="<?php esc_attr_e( 'Icon', 'nggallery' ); ?>" src="<?php echo esc_attr( $plugin['icon'] ); ?>" width="64px" /> </div> <div> <h3><?php echo esc_html( $plugin['name'] ); ?></h3> <p class="nextgen-am-plugins-excerpt"><?php echo esc_html( $plugin['description'] ); ?></p> </div> </div> <div class="nextgen-am-plugins-footer"> <div class="nextgen-am-plugins-status">Status: <span>Active</span></div> <div class="nextgen-am-plugins-install-wrap"> <span class="spinner nextgen-am-plugins-spinner"></span> <?php if ( isset( $plugin['basename'] ) ) : ?> <a href="#" target="_blank" class="button nextgen-secondary-button nextgen-am-plugins-deactivate" data-url="<?php echo esc_url( $plugin['url'] ); ?>" data-basename="<?php echo esc_attr( $plugin['basename'] ); ?>">Deactivate</a> <?php else : ?> <a href="<?php echo esc_url( $plugin['url'] ); ?>" target="_blank" class="button nextgen-secondary nextgen-am-plugins-deactivate" data-url="<?php echo esc_url( $plugin['url'] ); ?>">Activate</a> <?php endif; ?> </div> </div> </div> <?php } else { ?> <div class="nextgen-am-plugins"> <div class="nextgen-am-plugins-main"> <div> <img alt="<?php esc_attr_e( 'Icon', 'nggallery' ); ?>" src="<?php echo esc_attr( $plugin['icon'] ); ?>" width="64px" /> </div> <div> <h3><?php echo esc_html( $plugin['name'] ); ?></h3> <p class="nextgen-am-plugins-excerpt"><?php echo esc_html( $plugin['description'] ); ?></p> </div> </div> <div class="nextgen-am-plugins-footer"> <div class="nextgen-am-plugins-status">Status: <span>Inactive</span></div> <div class="nextgen-am-plugins-install-wrap"> <span class="spinner nextgen-am-plugins-spinner"></span> <?php if ( isset( $plugin['basename'] ) ) : ?> <a href="#" target="_blank" class="button nextgen-primary-button nextgen-am-plugins-activate" data-url="<?php echo esc_url( $plugin['url'] ); ?>" data-basename="<?php echo esc_attr( $plugin['basename'] ); ?>">Activate</a> <?php else : ?> <a href="<?php echo esc_url( $plugin['url'] ); ?>" target="_blank" class="button nextgen-primary-button nextgen-am-plugins-activate" data-url="<?php echo esc_url( $plugin['url'] ); ?>">Activate</a> <?php endif; ?> </div> </div> </div> <?php } } /** * Helper method to activate partner * * @since 1.90 * * @return void */ public function activate_am_plugin() { // Run a security check first. check_admin_referer( 'nextgen-activate-partner', 'nonce' ); if ( ! current_user_can( 'activate_plugins' ) ) { wp_send_json_error( [ 'message' => esc_html__( 'You are not allowed to activate plugins.', 'nggallery' ) ] ); } // Activate the addon. if ( isset( $_POST['basename'] ) ) { $activate = activate_plugin( sanitize_text_field( wp_unslash( $_POST['basename'] ) ) ); if ( is_wp_error( $activate ) ) { echo wp_json_encode( [ 'error' => $activate->get_error_message() ] ); die; } } echo wp_json_encode( true ); die; } /** * Helper method to deactivate partner * * @since 1.90 * * @return void */ public function deactivate_am_plugin() { // Run a security check first. check_admin_referer( 'nextgen-deactivate-partner', 'nonce' ); if ( ! current_user_can( 'activate_plugins' ) ) { wp_send_json_error( [ 'message' => esc_html__( 'You are not allowed to deactivate plugins.', 'nggallery' ) ] ); } // Deactivate the addon. if ( isset( $_POST['basename'] ) ) { deactivate_plugins( sanitize_text_field( wp_unslash( $_POST['basename'] ) ) ); } echo wp_json_encode( true ); die; } /** * Helper method to install partner * * @since 1.90 * * @return void */ public function install_am_plugin() { check_admin_referer( 'nextgen-install-partner', 'nonce' ); if ( ! current_user_can( 'install_plugins' ) ) { wp_send_json_error( [ 'message' => esc_html__( 'You are not allowed to install plugins.', 'nggallery' ) ] ); } // Install the addon. if ( isset( $_POST['download_url'] ) ) { $download_url = esc_url_raw( wp_unslash( $_POST['download_url'] ) ); global $hook_suffix; // Set the current screen to avoid undefined notices. set_current_screen(); $method = ''; $url = esc_url_raw( admin_url( 'admin.php?page=nextgen-gallery-about-us' ) ); // Start output bufferring to catch the filesystem form if credentials are needed. ob_start(); $creds = request_filesystem_credentials( $url, $method, false, false, null ); if ( false === $creds ) { $form = ob_get_clean(); echo wp_json_encode( [ 'form' => $form ] ); die; } // If we are not authenticated, make it happen now. if ( ! WP_Filesystem( $creds ) ) { ob_start(); request_filesystem_credentials( $url, $method, true, false, null ); $form = ob_get_clean(); echo wp_json_encode( [ 'form' => $form ] ); die; } // We do not need any extra credentials if we have gotten this far, so let's install the plugin. require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // Create the plugin upgrader with our custom skin. $skin = new \Imagely\NGG\Util\Installer_Skin(); $installer = new \Plugin_Upgrader( $skin ); $installer->install( $download_url ); // Flush the cache and return the newly installed plugin basename. wp_cache_flush(); if ( $installer->plugin_info() ) { $plugin_basename = $installer->plugin_info(); $active = activate_plugin( $plugin_basename, false, false, true ); wp_send_json_success( [ 'plugin' => $plugin_basename ] ); die(); } } // Send back a response. echo wp_json_encode( true ); die; } } ����������������������������������������������������������������������������������������������������������������������������������������������Admin/Onboarding_Wizard.php�������������������������������������������������������������������������0000644�����������������00000060464�15021223045�0011713 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * Onboarding class. * * @since 3.59.4 * * @package NextGEN Gallery * * @author Imagely */ namespace Imagely\NGG\Admin; // Exit if accessed directly. use Braintree\Http; use Imagely\NGG\Util\Installer_Skin; use Imagely\NGG\Util\UsageTracking; if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Class that holds our setup wizard. * * @since 3.59.4 */ class Onboarding_Wizard { /** * Holds base singleton. * * @since 3.59.4 * * @var object */ public $base = null; /** * Class constructor. * * @since 3.59.4 */ public function __construct() { if ( ! is_admin() || wp_doing_cron() || wp_doing_ajax() ) { return; } // Load the base class object. } /** * Setup our hooks. */ public function hooks() { add_action( 'admin_menu', [ $this, 'add_dashboard_page' ] ); add_action( 'admin_head', [ $this, 'hide_dashboard_page_from_menu' ] ); add_action( 'admin_init', [ $this, 'maybeload_onboarding_wizard' ] ); // Ajax actions. add_action( 'wp_ajax_save_onboarding_data', [ $this, 'save_onboarding_data' ], 10, 1 ); add_action( 'wp_ajax_install_recommended_plugins', [ $this, 'install_recommended_plugins' ], 10, 1 ); add_action( 'wp_ajax_save_selected_addons', [ $this, 'save_selected_addons' ], 10, 1 ); add_action( 'wp_ajax_ngg_plugin_verify_license_key', [ $this, 'ngg_plugin_verify_license_key' ], 10, 1 ); } /** * Adds a dashboard page for our setup wizard. * * @since 3.59.4 * * @return void */ public function add_dashboard_page() { add_dashboard_page( '', '', 'manage_options', 'nextgen-gallery-setup-wizard', '' ); } /** * Hide the dashboard page from the menu. * * @since 3.59.4 * * @return void */ public function hide_dashboard_page_from_menu() { remove_submenu_page( 'index.php', 'nextgen-gallery-setup-wizard' ); } /** * Checks to see if we should load the setup wizard. * * @since 3.59.4 * * @return void */ public function maybeload_onboarding_wizard() { // Don't load the interface if doing an ajax call. if ( wp_doing_ajax() || wp_doing_cron() ) { return; } // Check for wizard-specific parameter // Allow plugins to disable the setup wizard // Check if current user is allowed to save settings. // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended if ( ! isset( $_GET['page'] ) || 'nextgen-gallery-setup-wizard' !== sanitize_text_field( wp_unslash( $_GET['page'] ) ) || ! current_user_can( 'manage_options' ) ) { return; } // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended set_current_screen(); // Remove an action in the Gutenberg plugin ( not core Gutenberg ) which throws an error. remove_action( 'admin_print_styles', 'gutenberg_block_editor_admin_print_styles' ); // If we are redirecting, clear the transient so it only happens once. $this->load_onboarding_wizard(); } /** * Load the Onboarding Wizard template. * * @since 3.59.4 * * @return void */ private function load_onboarding_wizard() { $this->enqueue_scripts(); $this->onboarding_wizard_header(); $this->onboarding_wizard_content(); $this->onboarding_wizard_footer(); exit; } /** * Enqueue scripts for the setup wizard. * * @since 3.59.4 * * @return void */ private function enqueue_scripts() { // We don't want any plugin adding notices to our screens. Let's clear them out here. remove_all_actions( 'admin_notices' ); remove_all_actions( 'all_admin_notices' ); $router = \Imagely\NGG\Util\Router::get_instance(); // TODO: Add minified js file and check nonces. wp_register_script( 'nextgen-gallery-onboarding-wizard', plugins_url( 'assets/js/dist/onboarding-wizard.js', NGG_PLUGIN_FILE ), [ 'jquery' ], NGG_PLUGIN_VERSION, true ); wp_localize_script( 'nextgen-gallery-onboarding-wizard', 'nggOnboardingWizard', [ 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'nextgen-galleryOnboardingCheck' ), 'connect_nonce' => wp_create_nonce( 'nextgen-gallery-key-nonce' ), 'plugins_list' => $this->get_installed_plugins(), ] ); wp_register_style( 'nextgen-gallery-onboarding-wizard', plugins_url( 'assets/css/onboarding-wizard.css', NGG_PLUGIN_FILE ), [], NGG_PLUGIN_VERSION ); wp_enqueue_style( 'nextgen-gallery-onboarding-wizard' ); wp_enqueue_style( 'common' ); wp_enqueue_media(); } /** * Setup the wizard header. * * @since 3.59.4 * * @return void */ private function onboarding_wizard_header() { ?> <!DOCTYPE html> <html <?php language_attributes(); ?> dir="ltr"> <head> <meta charset="<?php bloginfo( 'charset' ); ?>"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> <?php // translators: %s is the plugin name. printf( esc_html__( '%1$s › Onboarding Wizard', 'nextgen-gallery-gallery' ), esc_html( 'NextGEN Gallery' ) ); ?> 'all-in-one-seo-pack/all_in_one_seo_pack.php', 'wpforms-lite' => 'wpforms-lite/wpforms.php', 'google-analytics-for-wordpress' => 'google-analytics-for-wordpress/googleanalytics.php', 'duplicator' => 'duplicator/duplicator.php', 'wp-mail-smtp' => 'wp-mail-smtp/wp_mail_smtp.php', ]; return $plugins; } /** * Check if a recommended plugin is installed. * * @param string $recommended The plugin slug. * * @return string */ public function is_recommended_plugin_installed( string $recommended ): string { // Check if these plugins are installed already or not. $all_plugins = get_plugins(); $plugins = $this->get_recommended_plugins(); $plugin = ''; $plus = 'nextgen-gallery-plus/ngg-plus.php'; $pro = 'nextgen-gallery-pro/nggallery-pro.php'; $starter = 'nextgen-gallery-pro/ngg-starter.php'; // Switch case to check pro, plus and starter plugins. switch ( $recommended ) { // if $recommended contains plus, then set $plugin to plus. case strpos( $recommended, '-plus' ) !== false: $plugin = $plus; break; // if $recommended contains pro, then set $plugin to pro. case strpos( $recommended, 'gallery-pro' ) !== false: $plugin = $pro; break; // if $recommended contains starter, then set $plugin to starter. case strpos( $recommended, '-starter' ) !== false: $plugin = $starter; break; } // Check if $recommended is a NextGEN Gallery plugin. if ( array_key_exists( $recommended, $plugins ) && '' === $plugin ) { // check if key exists in the array. $plugin = $plugins[ $recommended ]; } if ( in_array( $plugin, array_keys( $all_plugins ), true ) ) { return 'no-clicks disabled'; } return ''; } /** * Get saved onboarding data. * * @param string $key The key to get the data. * * @return mixed */ public function get_onboarding_data( string $key ) { if ( ! empty( $key ) ) { $onboarding_data = get_option( 'ngg_onboarding_data' ); if ( ! empty( $onboarding_data ) && isset( $onboarding_data[ $key ] ) ) { return $onboarding_data[ $key ]; } } return ''; } /** * Save the onboarding data. * * @return void */ public function save_onboarding_data() { // check for nonce nextgen-galleryOnboardingCheck. if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'nextgen-galleryOnboardingCheck' ) ) { wp_send_json_error( 'Invalid nonce' ); wp_die(); } // check if the current user can manage options. if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You do not have permission to save data' ); wp_die(); } if ( ! empty( $_POST['eow'] ) ) { // Sanitize data and merge to existing data. $onboarding_data = get_option( 'ngg_onboarding_data', [] ); $onboarding_data = $this->sanitize_and_assign( '_usage_tracking', 'sanitize_text_field', $onboarding_data ); $onboarding_data = $this->sanitize_and_assign( '_email_address', 'sanitize_email', $onboarding_data ); $onboarding_data = $this->sanitize_and_assign( '_email_opt_in', 'sanitize_text_field', $onboarding_data ); $onboarding_data = $this->sanitize_and_assign( '_user_type', 'sanitize_text_field', $onboarding_data ); $onboarding_data = $this->sanitize_and_assign( '_others', 'sanitize_text_field', $onboarding_data ); $stats_sent = $onboarding_data['usage_stats_init'] ?? false; $usage_tracking = filter_var( $onboarding_data['_usage_tracking'], FILTER_VALIDATE_BOOLEAN ); if ( $usage_tracking && ! $stats_sent ) { // Send usage tracking on onboarding settings save. ( new UsageTracking() )->send_checkin( true ); $onboarding_data['usage_stats_init'] = true; } update_option( 'ngg_onboarding_data', $onboarding_data ); // Send data to Drip. $this->save_to_drip( $onboarding_data ); wp_send_json_success( 'Data saved successfully' ); wp_die(); } wp_send_json_error( 'Something went wrong. Please try again.' ); wp_die(); } /** * Sanitize and assign the data. * * @param string $key The key to get the data. * @param string $sanitize_function The sanitize function. * @param array $onboarding_data The onboarding data. * * @return array */ public function sanitize_and_assign( string $key, string $sanitize_function, array $onboarding_data ): array { if ( ! function_exists( $sanitize_function ) ) { _doing_it_wrong( __METHOD__, 'Invalid sanitize function', '3.59.4' ); return $onboarding_data; } // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( isset( $_POST['eow'][ $key ] ) ) { // Nonce is verified in the parent function. // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $onboarding_data[ $key ] = $sanitize_function( wp_unslash( $_POST['eow'][ $key ] ) ); } else { unset( $onboarding_data[ $key ] ); } return $onboarding_data; } /** * Save the onboarding data to Drip. * * @param array $onboarding_data The onboarding data. * * @return void */ public function save_to_drip( array $onboarding_data ) { $url = 'https://imagely.com/wp-json/imagely/v1/get_opt_in_data'; $email = sanitize_email( $onboarding_data['_email_address'] ); if ( empty( $email ) ) { return; } $tags = []; $position = ''; $tags[] = 'im-' . $this->get_license_type(); if ( isset( $onboarding_data['_user_type'] ) ) { $position = $onboarding_data['_user_type']; } $body_data = [ 'imagely-drip-email' => base64_encode( $email ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode 'imagely-drip-tags' => $tags, 'imagely-drip-position' => $position, ]; $body = wp_json_encode( $body_data ); $args = [ 'method' => 'POST', 'headers' => [ 'Content-Type' => 'application/json', 'user-agent' => 'ENVIRA/IMAGELY/' . NGG_PLUGIN_VERSION . '; ' . get_bloginfo( 'url' ), ], 'body' => $body, 'timeout' => '5', // Timeout in seconds. 'redirection' => '5', 'httpversion' => '1.0', 'blocking' => true, 'data_format' => 'body', ]; $response = wp_safe_remote_post( $url, $args ); } /** * Save selected addons to database. */ public function save_selected_addons() { // check for nonce nextgen-galleryOnboardingCheck. if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'nextgen-galleryOnboardingCheck' ) ) { wp_send_json_error( 'Invalid nonce' ); wp_die(); } // check if the current user can manage options. if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You do not have permission to save data' ); wp_die(); } if ( ! empty( $_POST['addons'] ) ) { $addons = explode( ',', sanitize_text_field( wp_unslash( $_POST['addons'] ) ) ); // Sanitize data and merge to existing data. $onboarding_data = get_option( 'ngg_onboarding_data' ); if ( empty( $onboarding_data ) ) { $onboarding_data = []; } // Save addons as _addons key. $onboarding_data['_addons'] = $addons; $updated = update_option( 'ngg_onboarding_data', $onboarding_data ); wp_send_json_success( 'Addons saved successfully' ); wp_die(); } wp_send_json_error( 'Something went wrong. Please try again.' ); wp_die(); } /** * Get the license type for the current plugin. * * @since 3.59.4 * * @return string */ public function get_license_type() { if ( defined( 'NGG_PRO_PLUGIN_BASENAME' ) ) { return 'pro'; } elseif ( defined( 'NGG_PLUS_PLUGIN_BASENAME' ) ) { return 'plus'; } elseif ( defined( 'NGG_STARTER_PLUGIN_BASENAME' ) ) { return 'starter'; } return 'lite'; } /** * Install the recommended plugins and add-ons. * * @return void */ public function install_recommended_plugins() { // check for nonce nextgen-galleryOnboardingCheck. if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'nextgen-galleryOnboardingCheck' ) ) { wp_send_json_error( 'Invalid nonce' ); wp_die(); } // check if the current user can manage options. if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'You do not have permission to install plugins' ); wp_die(); } if ( ! empty( $_POST['plugins'] ) ) { // Sanitize data, plugins is a string delimited by comma. $plugins = explode( ',', sanitize_text_field( wp_unslash( $_POST['plugins'] ) ) ); // Install the plugins. foreach ( $plugins as $plugin ) { if ( '' !== $this->is_recommended_plugin_installed( $plugin ) ) { continue; // Skip the plugin if it is already installed. } // Generate the plugin URL by slug. $url = 'https://downloads.wordpress.org/plugin/' . $plugin . '.zip'; $this->install_helper( $url ); } } wp_send_json_success( 'Installed the recommended plugins successfully.' ); wp_die(); } /** * Helper function to install the free plugins. * * @param string $download_url The download URL. * * @return void */ public function install_helper( string $download_url ) { if ( empty( $download_url ) ) { return; } global $hook_suffix; // Set the current screen to avoid undefined notices. set_current_screen(); $method = ''; $url = esc_url( admin_url( 'index.php?page=nextgen-gallery-setup-wizard' ) ); // Start output buffering to catch the filesystem form if credentials are needed. ob_start(); $creds = request_filesystem_credentials( $url, $method, false, false, null ); if ( false === $creds ) { $form = ob_get_clean(); echo wp_json_encode( [ 'form' => $form ] ); die; } // If we are not authenticated, make it happen now. if ( ! WP_Filesystem( $creds ) ) { ob_start(); request_filesystem_credentials( $url, $method, true, false, null ); $form = ob_get_clean(); echo wp_json_encode( [ 'form' => $form ] ); die; } // We do not need any extra credentials if we have gotten this far, so let's install the plugin. require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // Create the plugin upgrader with our custom skin. $skin = new \Imagely\NGG\Util\Installer_Skin(); $installer = new \Plugin_Upgrader( $skin ); $status = $installer->install( $download_url ); if ( is_wp_error( $status ) ) { wp_send_json_error( $status->get_error_message() ); } // Flush the cache and return. wp_cache_flush(); } /** * Verify the license key. * * @since 3.59.4 * * @return void * * Copy of maybe_verify_key in License class. * Modified to return wp_send_json_success and wp_send_json_error. */ public function ngg_plugin_verify_license_key() { if ( ! isset( $_POST['nextgen-gallery-license-key'], $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'nextgen-galleryOnboardingCheck' ) ) { wp_send_json_error( 'Invalid Request', \WP_Http::FORBIDDEN ); wp_die(); } $url = 'https://members.photocrati.com/wp-json/licensing/v1/register_site'; $license_key = isset( $_POST['nextgen-gallery-license-key'] ) ? sanitize_text_field( wp_unslash( $_POST['nextgen-gallery-license-key'] ) ) : null; if ( empty( $license_key ) ) { wp_send_json_error( 'License key is required' ); wp_die(); } $query_args = [ 'license_key' => $license_key, 'site_url' => site_url(), ]; $args = [ 'method' => 'POST', 'timeout' => 45, 'redirection' => 5, 'httpversion' => '1.0', 'body' => $query_args, 'user-agent' => 'ImagelyUpdates/' . NGG_PLUGIN_VERSION . '; ' . get_bloginfo( 'url' ), 'blocking' => true, ]; $response = wp_safe_remote_post( $url, $args ); if ( is_wp_error( $response ) ) { $error_message = $response->get_error_message(); wp_send_json_error( $error_message ); wp_die(); } else { $http_code = wp_remote_retrieve_response_code( $response ); $result = json_decode( wp_remote_retrieve_body( $response ) ); // check if the response has error and bail out. // check if the response has error and bail out. if ( isset( $result->error ) && '' !== $result->error ) { wp_send_json_error( $this->get_error_message( $result->error ) ); wp_die(); } $valid = in_array( $result->status ?? '', ['active', 'inactive','disabled'], true ) ?? false; // Check if status is active/inactive not expired or disabled. if ( 200 === $http_code && $valid ) { $product = $result->level ?? false; if ( ! $product ) { wp_send_json_error( 'Product not found.' ); wp_die(); } // Check if the product is already installed. $current_level = $this->get_license_type(); if ( $current_level === $product ) { // If the product is already installed, return success. wp_send_json_success( 'Congratulations! This site is now receiving automatic updates.' ); wp_die(); } // Check if limit is reached. if ( '' === $result->is_at_limit ) { wp_send_json_error( 'Sorry, you have reached the limit of sites for this license key.' ); wp_die(); } $url = $this->download_pro( $license_key, $product ); if ( isset( $url ) ) { $this->install_helper( $url ); } wp_send_json_success( 'Congratulations! This site is now receiving automatic updates.' ); wp_die(); } else { // if license is expired, throw error. if ( 'expired' === $result->status ) { wp_send_json_error( $this->get_error_message( 'license_expired' ) ); wp_die(); } // if license is invalid, throw error. wp_send_json_error( $this->get_error_message( null ) ); wp_die(); } } } /** * Download the pro version of the plugin. * * @param string $key The license key. * @param string $product The product name. * * @return boolean|string */ public function download_pro( string $key, string $product ) { // Check if the product already exist in the installed plugins. if( 'no-clicks disabled' === $this->is_recommended_plugin_installed( 'nextgen-gallery-' . $product ) ){ return false; } $url = 'https://members.photocrati.com/wp-json/licensing/v1/get_update?product=nextgen-gallery-' . $product . '&license_key=' . $key . '&site_url=' . site_url(); $args = [ 'method' => 'GET', 'timeout' => 45, 'redirection' => 5, 'httpversion' => '1.0', 'user-agent' => 'ImagelyUpdates/' . NGG_PLUGIN_VERSION . '; ' . get_bloginfo( 'url' ), 'blocking' => true, ]; $response = wp_safe_remote_get( $url, $args ); if ( ! is_wp_error( $response ) ) { $http_code = wp_remote_retrieve_response_code( $response ); $body = wp_remote_retrieve_body( $response ); if ( 200 === $http_code ) { return json_decode( $body )->download_url ?? ''; } else { return false; } } } /** * Get a list of installed recommended plugins and addons. * * @return array */ public function get_installed_plugins(): array { $plugins = $this->get_recommended_plugins(); // Check if these plugins are installed already or not. $all_plugins = get_plugins(); $installed = []; foreach ( $plugins as $plugin ) { if ( in_array( $plugin, array_keys( $all_plugins ), true ) ) { // Get array key of $plugins. $installed[] = array_search( $plugin, $plugins, true ); } } return $installed; } /** * Get error messages. * * @since 3.59.4 * * @param string|null $code The error message. * * @return string */ public function get_error_message( ?string $code ): string { if ( ! isset( $code ) ) { return 'Something went wrong, please try again later.'; } $message = ''; switch ( $code ) { case 'empty_site_url': $message = __( 'The site URL is missing. Please provide a valid URL.', 'nextgen-gallery' ); break; case 'license_not_found': $message = __( 'The license key was not found. Please verify and try again.', 'nextgen-gallery' ); break; case 'license_status_expired': case 'license_expired': $message = __( 'The license key has expired. Please renew your license.', 'nextgen-gallery' ); break; case 'license_status_disabled': case 'license_disabled': $message = __( 'The license key has not been activated yet. Please contact support.', 'nextgen-gallery' ); break; case 'license_status_revoked': case 'license_revoked': $message = __( 'The license key has been revoked. Please contact support.', 'nextgen-gallery' ); break; case 'license_limit_installations': $message = __( 'The license key has reached the maximum number of installations.', 'nextgen-gallery' ); break; default: $message = __( 'An unknown error occurred. Please try again.', 'nextgen-gallery' ); break; } return $message; } } Admin/Ecommerce_Preview.php000064400000002220150212230450011673 0ustar00_name = $name; $this->_data = $data; $this->_callback = $callback; } /** * @return bool */ public function is_renderable() { return true; } /** * @return bool */ public function is_dismissable() { return isset( $this->_data['dismissable'] ) ? $this->_data['dismissable'] : true; } /** * @return string */ public function render() { return $this->_data['message']; } /** * @return string */ public function get_mvc_template() { return 'photocrati-nextgen_admin#requirement_notice'; } /** * @return string */ public function get_name() { return $this->_name; } /** * @return bool */ public function run_callback() { if ( is_callable( $this->_callback ) ) { return call_user_func( $this->_callback ); } else { return false; } } /** * @return string */ public function get_css_class() { $prefix = 'notice notice-'; if ( $this->is_dismissable() ) { return $prefix . 'warning'; } else { return $prefix . 'error'; } } public function get_message() { return empty( $this->_data['message'] ) ? '' : $this->_data['message']; } } Admin/Notifications/Manager.php000064400000015207150212230450012467 0ustar00_dismiss_url = site_url( '/?ngg_dismiss_notice=1' ); } public function has_displayed_notice() { return $this->_displayed_notice; } public function add( $name, $handler ) { $this->_notifications[ $name ] = $handler; } public function remove( $name ) { unset( $this->_notifications[ $name ] ); } public function render() { $output = []; foreach ( array_keys( $this->_notifications ) as $notice ) { if ( ( $html = $this->render_notice( $notice ) ) ) { $output[] = $html; } } echo implode( "\n", $output ); } public function is_dismissed( $name ) { $retval = false; $settings = Settings::get_instance(); $dismissed = $settings->get( 'dismissed_notifications', [] ); if ( isset( $dismissed[ $name ] ) ) { if ( ( $id = get_current_user_id() ) ) { if ( in_array( $id, $dismissed[ $name ] ) ) { $retval = true; } elseif ( in_array( 'unknown', $dismissed[ $name ] ) ) { $retval = true; } } } return $retval; } public function dismiss( $name, $dismiss_code = 1 ) { $response = []; if ( ( $handler = $this->get_handler_instance( $name ) ) ) { $has_method = method_exists( $handler, 'is_dismissable' ); if ( ( $has_method && $handler->is_dismissable() ) || ! $has_method ) { if ( method_exists( $handler, 'dismiss' ) ) { $response = $handler->dismiss( $dismiss_code ); $response['handled'] = true; } if ( is_bool( $response ) ) { $response = [ 'dismiss' => $response ]; } // Set default key/values if ( ! isset( $response['handled'] ) ) { $response['handled'] = false; } if ( ! isset( $response['dismiss'] ) ) { $response['dismiss'] = true; } if ( ! isset( $response['persist'] ) ) { $response['persist'] = $response['dismiss']; } if ( ! isset( $response['success'] ) ) { $response['success'] = $response['dismiss']; } if ( ! isset( $response['code'] ) ) { $response['code'] = $dismiss_code; } if ( $response['dismiss'] ) { $settings = Settings::get_instance(); $dismissed = $settings->get( 'dismissed_notifications', [] ); if ( ! isset( $dismissed[ $name ] ) ) { $dismissed[ $name ] = []; } $user_id = get_current_user_id(); $dismissed[ $name ][] = ( $user_id ? $user_id : 'unknown' ); $settings->set( 'dismissed_notifications', $dismissed ); if ( $response['persist'] ) { $settings->save(); } } } else { $response['error'] = __( 'Notice is not dismissible', 'nggallery' ); } } else { $response['error'] = __( 'No handler defined for this notice', 'nggallery' ); } return $response; } public function get_handler_instance( $name ) { $retval = null; if ( isset( $this->_notifications[ $name ] ) ) { $handler = $this->_notifications[ $name ]; if ( is_object( $handler ) ) { $retval = $handler; } elseif ( is_array( $handler ) ) { $retval = new Wrapper( $name, $handler ); } elseif ( class_exists( $handler ) ) { $retval = call_user_func( [ $handler, 'get_instance' ], $name ); } } return $retval; } public function enqueue_scripts() { if ( $this->has_displayed_notice() ) { $router = \Imagely\NGG\Util\Router::get_instance(); wp_enqueue_script( 'ngg_admin_notices', $router->get_static_url( 'photocrati-nextgen_admin#admin_notices.js' ), [], NGG_SCRIPT_VERSION, true ); wp_localize_script( 'ngg_admin_notices', 'ngg_notification_dismiss_settings', [ 'url' => $this->_dismiss_url, 'nonce' => \wp_create_nonce( 'ngg_dismiss_notification' ), ] ); } } public function serve_ajax_request() { if ( isset( $_REQUEST['ngg_dismiss_notice'] ) ) { $retval = [ 'failure' => true ]; if ( ! headers_sent() ) { header( 'Content-Type: application/json' ); } ob_start(); if ( ! isset( $_REQUEST['nonce'] ) || ! \wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ), 'ngg_dismiss_notification' ) ) { $retval['msg'] = __( 'Invalid security token', 'nggallery' ); } else { if ( ! isset( $_REQUEST['code'] ) ) { $_REQUEST['code'] = 1; } if ( isset( $_REQUEST['name'] ) ) { $retval = $this->dismiss( sanitize_text_field( wp_unslash( $_REQUEST['name'] ) ), intval( sanitize_text_field( wp_unslash( $_REQUEST['code'] ) ) ) ); } else { $retval['msg'] = __( 'Not a valid notice name', 'nggallery' ); } } ob_end_clean(); echo json_encode( $retval ); exit(); } } public function render_notice( $name ) { $retval = ''; if ( ( $handler = $this->get_handler_instance( $name ) ) && ! $this->is_dismissed( $name ) ) { // Does the handler want to render? $has_method = method_exists( $handler, 'is_renderable' ); if ( ( $has_method && $handler->is_renderable() ) || ! $has_method ) { $show_dismiss_button = false; if ( method_exists( $handler, 'show_dismiss_button' ) ) { $show_dismiss_button = $handler->show_dismiss_button(); } elseif ( method_exists( $handler, 'is_dismissable' ) ) { $show_dismiss_button = $handler->is_dismissable(); } $template = method_exists( $handler, 'get_mvc_template' ) ? $handler->get_mvc_template() : 'photocrati-nextgen_admin#admin_notice'; // The 'inline' class is necessary to prevent our notices from being moved in the DOM // see https://core.trac.wordpress.org/ticket/34570 for reference $css_class = 'inline '; $css_class .= ( method_exists( $handler, 'get_css_class' ) ? $handler->get_css_class() : 'updated' ); $view = new \C_MVC_View( $template, [ 'css_class' => $css_class, 'is_dismissable' => ( method_exists( $handler, 'is_dismissable' ) ? $handler->is_dismissable() : false ), 'html' => ( method_exists( $handler, 'render' ) ? $handler->render() : '' ), 'show_dismiss_button' => $show_dismiss_button, 'notice_name' => $name, ] ); $retval = $view->render( true ); if ( method_exists( $handler, 'enqueue_backend_resources' ) ) { $handler->enqueue_backend_resources(); } $this->_displayed_notice = true; } } return $retval; } } Admin/Notifications/Wrapper.php000064400000000570150212230450012532 0ustar00_name = $name; $this->_data = $data; } public function is_renderable() { return true; } public function is_dismissable() { return true; } public function render() { return $this->_data['message']; } } Admin/Notifications/Review.php000064400000007762150212230450012365 0ustar00_data['name'] = $params['name']; $this->_data['range'] = $params['range']; $this->_data['follows'] = $params['follows']; } public function get_name() { return $this->_data['name']; } public function get_gallery_count() { // Get the total # of galleries if we don't have them $settings = Settings::get_instance(); $count = $settings->get( 'gallery_count', false ); if ( ! $count ) { $count = \M_NextGen_Admin::update_gallery_count_setting(); } return $count; } public function get_range() { return $this->_data['range']; } public function is_renderable() { return ( $this->is_on_dashboard() || $this->is_on_ngg_admin_page() ) && $this->is_at_gallery_count() && $this->is_previous_notice_dismissed() && $this->gallery_created_flag_check(); } public function gallery_created_flag_check() { $settings = Settings::get_instance(); return $settings->get( 'gallery_created_after_reviews_introduced' ); } public function is_at_gallery_count() { $retval = false; $range = $this->_data['range']; $count = $this->get_gallery_count(); $manager = Manager::get_instance(); // Determine if we match the current range if ( $count >= $range['min'] && $count <= $range['max'] ) { $retval = true; } // If the current number of galleries exceeds the parent notice's maximum we should dismiss the parent if ( ! empty( $this->_data['follows'] ) ) { $follows = $this->_data['follows']; $parent_range = $follows->get_range(); if ( $count > $parent_range['max'] && ! $manager->is_dismissed( $follows->get_name() ) ) { $manager->dismiss( $follows->get_name(), 2 ); } } return $retval; } public function is_previous_notice_dismissed( $level = false ) { $retval = false; $manager = Manager::get_instance(); if ( empty( $level ) ) { $level = $this; } if ( ! empty( $level->_data['follows'] ) ) { $parent = $level->_data['follows']; $retval = $manager->is_dismissed( $parent->get_name() ); if ( ! $retval && ! empty( $parent->_data['follows'] ) ) { $retval = $this->is_previous_notice_dismissed( $parent ); } } else { $retval = true; } return $retval; } public function is_on_dashboard(): bool { if ( ! isset( $_SERVER['REQUEST_URI'] ) ) { return false; } return preg_match( '#/wp-admin/?(index\.php)?$#', $_SERVER['REQUEST_URI'] ) == true; } public function is_on_ngg_admin_page(): bool { if ( ! isset( $_SERVER['REQUEST_URI'] ) ) { return false; } // Do not show this notification inside of the ATP popup. // // Nonce verification is not necessary here, and should be performed by methods invoking this method. // // phpcs:disable WordPress.Security.NonceVerification.Recommended return ( preg_match( '/wp-admin.*(ngg|nextgen).*/', $_SERVER['REQUEST_URI'] ) || ( isset( $_REQUEST['page'] ) && preg_match( '/ngg|nextgen/', sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) ) ) ) && ( false === strpos( strtolower( $_SERVER['REQUEST_URI'] ), '&attach_to_post' ) ); // phpcs:enable WordPress.Security.NonceVerification.Recommended } public function render() { $view = new View( 'Admin/ReviewNotice', [ 'number' => $this->get_gallery_count() ], 'photocrati-nextgen_admin#review_notice' ); return $view->render( true ); } public function dismiss( $code ) { $retval = [ 'dismiss' => true, 'persist' => true, 'success' => true, 'code' => $code, 'dismiss_code' => $code, ]; $manager = Manager::get_instance(); if ( $code == 1 || $code == 3 ) { $retval['review_level_1'] = $manager->dismiss( 'review_level_1', 2 ); $retval['review_level_2'] = $manager->dismiss( 'review_level_2', 2 ); $retval['review_level_3'] = $manager->dismiss( 'review_level_3', 2 ); } return $retval; } } Admin/Views/header.php000064400000005242150212230450010627 0ustar00get_count(); $dismissed_count = $notifications->get_dismissed_count(); $data_count = ''; if ( $notifications_count > 0 ) { $data_count = sprintf( 'data-count="%d"', absint( $notifications_count ) ); } $is_pro = nextgen_is_plus_or_pro_enabled(); ?>

', '' ); ?>

Admin/Views/footer.php000064400000007554150212230450010705 0ustar00
Admin/Views/onboarding-wizard/welcome.php000064400000002460150212230450014451 0ustar00 ←  Admin/Views/onboarding-wizard/step-3.php000064400000030276150212230450014137 0ustar00
Admin/Views/onboarding-wizard/step-4.php000064400000015301150212230450014130 0ustar00 Admin/Views/onboarding-wizard/step-5.php000064400000012545150212230450014140 0ustar00 Admin/Views/onboarding-wizard/step-1.php000064400000021727150212230450014136 0ustar00 Admin/Views/onboarding-wizard/step-2.php000064400000037164150212230450014141 0ustar00 Admin/Views/notifications.php000064400000004704150212230450012252 0ustar00

' . absint( $notifications->get_count() ) . '' ); ?>

' . absint( $notifications->get_dismissed_count() ) . '' ); ?>

    get_active_notifications(); foreach ( $active_notifications as $active ) { $notifications->get_notification_markup( $active ); } ?>
    get_dismissed_notifications(); foreach ( $dismissed_notifications as $dismissed ) { $notifications->get_notification_markup( $dismissed ); } ?>
Admin/Views/ecommerce.php000064400000155217150212230450011346 0ustar00

', '', '', '' ); ?>

Ecommerce Options

Good work. Keep making the web beautiful.

General Options

USD
 

SALES TAX NOTE: Sales tax is complex. CLICK HERE to learn more about sales tax and how NextGEN Pro calculates it. Because we use a third party service (TaxJar), an active Pro license is required to enable sales tax.

 
 

E-mail

 

Payment Gateway

 
 
 
 
 
 
 

Print Lab Integration

DO I NEED THIS? A credit card is needed only if you want to use automated print fulfillment.

WILL YOU CHARGE ME? You will not be charged now. Your card will only be charged if someone submits a print lab order on your site. At that point, you will be billed for print and shipping costs from the print lab. You would pay those costs yourself if you worked directly with the lab. We're just automating the process for you.

IS THIS SECURE? Assuming you've enabled SSL on your website, then yes. This form sends your card information directly to Stripe, one of the world's leading payment processors. It is stored securely at Stripe, not locally by WordPress or NextGEN Gallery. Note: Without SSL, this form is not 100% secure. You should also enable SSL before receiving payments from your own visitors.

AGREEMENT: By submitting your card here, you authorise Imagely to bill your card for the cost of print lab orders.

No card on file.

Proofing

 

Admin/AMNotifications.php000064400000045471150212230450011341 0ustar00option && $cache ) { return $this->option; } $option = get_option( self::$option_name, [] ); $this->option = [ 'update' => ! empty( $option['update'] ) ? $option['update'] : 0, 'events' => ! empty( $option['events'] ) ? $option['events'] : [], 'feed' => ! empty( $option['feed'] ) ? $option['feed'] : [], 'dismissed' => ! empty( $option['dismissed'] ) ? $option['dismissed'] : [], ]; return $this->option; } /** * Fetch notifications from feed. * * @since 1.8.7 * * @return array */ public function fetch_feed() { $res = wp_remote_get( self::SOURCE_URL ); if ( is_wp_error( $res ) ) { return []; } $body = wp_remote_retrieve_body( $res ); if ( empty( $body ) ) { return []; } return $this->verify( json_decode( $body, true ) ); } /** * Verify notification data before it is saved. * * @since 1.8.7 * * @param array $notifications Array of notifications items to verify. * @return array */ public function verify( $notifications ) { $data = []; if ( ! is_array( $notifications ) || empty( $notifications ) ) { return $data; } $option = $this->get_option(); foreach ( $notifications as $notification ) { // The message and license should never be empty, if they are, ignore. if ( empty( $notification['content'] ) && empty( $notification['type'] ) ) { continue; } // Ignore if notification is not ready to display(based on start time). if ( ! empty( $notification['start'] ) && time() < strtotime( $notification['start'] ) ) { continue; } // Ignore if expired. if ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) { continue; } // Check that the license type matches. if ( ! in_array( $this->get_license_type(), (array) $notification['type'], true ) ) { continue; } // Ignore if notification has already been dismissed. $notification_already_dismissed = false; if ( is_array( $option['dismissed'] ) && ! empty( $option['dismissed'] ) ) { foreach ( $option['dismissed'] as $dismiss_notification ) { if ( $notification['id'] === $dismiss_notification['id'] ) { $notification_already_dismissed = true; break; } } } if ( true === $notification_already_dismissed ) { continue; } $data[] = $notification; } return $data; } /** * Verify saved notification data for active notifications. * * @since 1.8.7 * * @param array $notifications Array of notifications items to verify. * @return array */ public function verify_active( $notifications ) { if ( ! is_array( $notifications ) || empty( $notifications ) ) { return []; } // Remove notifications that are not active, or if the license type not exists. foreach ( $notifications as $key => $notification ) { if ( ( ! empty( $notification['start'] ) && time() < strtotime( $notification['start'] ) ) || ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) ) { unset( $notifications[ $key ] ); } } return $notifications; } /** * Get notification data. * * @since 1.8.7 * * @return array */ public function get() { if ( ! $this->has_access() ) { return []; } $option = $this->get_option(); // Update notifications using async task. if ( empty( $option['update'] ) || time() > $option['update'] + DAY_IN_SECONDS ) { if ( false === wp_next_scheduled( 'nextgen_admin_notifications_update' ) ) { wp_schedule_single_event( time(), 'nextgen_admin_notifications_update' ); } } $events = ! empty( $option['events'] ) ? $this->verify_active( $option['events'] ) : []; $feed = ! empty( $option['feed'] ) ? $this->verify_active( $option['feed'] ) : []; $notifications = []; $notifications['active'] = array_merge( $events, $feed ); $notifications['active'] = $this->get_notifications_with_human_readeable_start_time( $notifications['active'] ); $notifications['active'] = $this->get_notifications_with_formatted_content( $notifications['active'] ); $notifications['dismissed'] = ! empty( $option['dismissed'] ) ? $option['dismissed'] : []; $notifications['dismissed'] = $this->get_notifications_with_human_readeable_start_time( $notifications['dismissed'] ); $notifications['dismissed'] = $this->get_notifications_with_formatted_content( $notifications['dismissed'] ); return $notifications; } /** * Improve format of the content of notifications before display. By default, it just runs wpautop. * * @since 1.8.7 * * @param array $notifications The notifications to be parsed. * @return array */ public function get_notifications_with_formatted_content( $notifications ) { if ( ! is_array( $notifications ) || empty( $notifications ) ) { return $notifications; } foreach ( $notifications as $key => $notification ) { if ( ! empty( $notification['content'] ) ) { $notifications[ $key ]['content'] = wpautop( $notification['content'] ); $notifications[ $key ]['content'] = apply_filters( 'nextgen_notification_content_display', $notifications[ $key ]['content'] ); } } return $notifications; } /** * Get notifications start time with human time difference * * @since 1.8.7 * * @param array $notifications The array of notifications to convert. * @return array */ public function get_notifications_with_human_readeable_start_time( $notifications ) { if ( ! is_array( $notifications ) || empty( $notifications ) ) { return []; } foreach ( $notifications as $key => $notification ) { if ( empty( $notification['start'] ) ) { continue; } // Translators: Human-Readable time to display. $modified_start_time = sprintf( __( '%1$s ago', 'nggallery' ), human_time_diff( strtotime( $notification['start'] ), time() ) ); $notifications[ $key ]['start'] = $modified_start_time; } return $notifications; } /** * Get active notifications. * * @since 1.8.7 * * @return array $notifications['active'] active notifications */ public function get_active_notifications() { $notifications = $this->get(); // Show only 5 active notifications plus any that has a priority of 1. $all_active = isset( $notifications['active'] ) ? $notifications['active'] : []; $displayed = []; foreach ( $all_active as $notification ) { if ( ( isset( $notification['priority'] ) && 1 === $notification['priority'] ) || count( $displayed ) < 5 ) { $displayed[] = $notification; } } return $displayed; } /** * Get dismissed notifications. * * @since 1.8.7 * * @return array $notifications['dismissed'] dismissed notifications */ public function get_dismissed_notifications() { $notifications = $this->get(); return isset( $notifications['dismissed'] ) ? $notifications['dismissed'] : []; } /** * Get notification count. * * @since 1.8.7 * * @return int */ public function get_count() { return count( $this->get_active_notifications() ); } /** * Get the dismissed notifications count. * * @since 1.8.7 * * @return int */ public function get_dismissed_count() { return count( $this->get_dismissed_notifications() ); } /** * Check if a notification has been dismissed before * * @since 1.8.7 * * @param array $notification The notification to check if is dismissed. * @return bool */ public function is_dismissed( $notification ) { if ( empty( $notification['id'] ) ) { return true; } $option = $this->get_option(); foreach ( $option['dismissed'] as $item ) { if ( $item['id'] === $notification['id'] ) { return true; } } return false; } /** * Add a manual notification event. * * @since 1.8.7 * * @param array $notification Notification data. * @return bool */ public function add( $notification ) { if ( empty( $notification['id'] ) || $this->is_dismissed( $notification ) ) { return false; } $option = $this->get_option(); $current_notifications = $option['events']; foreach ( $current_notifications as $item ) { if ( $item['id'] === $notification['id'] ) { return false; } } $notification = $this->verify( [ $notification ] ); $notifications = array_merge( $notification, $current_notifications ); // Sort notifications by priority. usort( $notifications, function ( $a, $b ) { if ( ! isset( $a['priority'] ) || ! isset( $b['priority'] ) ) { return 0; } if ( $a['priority'] === $b['priority'] ) { return 0; } return $a['priority'] < $b['priority'] ? - 1 : 1; } ); update_option( self::$option_name, [ 'update' => $option['update'], 'feed' => $option['feed'], 'events' => $notifications, 'dismissed' => $option['dismissed'], ], false ); return true; } /** * Update notification data from feed. * * @since 1.8.7 * * @return void */ public function update() { $feed = $this->fetch_feed(); $option = $this->get_option(); update_option( self::$option_name, [ 'update' => time(), 'feed' => $feed, 'timeout' => strtotime( '+2 hours', current_time( 'timestamp' ) ), // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested 'events' => $option['events'], 'dismissed' => array_slice( $option['dismissed'], 0, 30 ), ], false ); } /** * Dismiss notification via AJAX. * * @since 1.8.7 */ public function dismiss() { // Run a security check. check_ajax_referer( 'nextgen_dismiss_notification', 'nonce' ); // Check for access and required param. if ( ! $this->has_access() || empty( $_POST['id'] ) ) { wp_send_json_error(); } $id = sanitize_text_field( wp_unslash( $_POST['id'] ) ); $option = $this->get_option(); // Dismiss all notifications and add them to dissmiss array. if ( 'all' === $id ) { if ( is_array( $option['feed'] ) && ! empty( $option['feed'] ) ) { foreach ( $option['feed'] as $key => $notification ) { array_unshift( $option['dismissed'], $notification ); unset( $option['feed'][ $key ] ); } } if ( is_array( $option['events'] ) && ! empty( $option['events'] ) ) { foreach ( $option['events'] as $key => $notification ) { array_unshift( $option['dismissed'], $notification ); unset( $option['events'][ $key ] ); } } } $type = is_numeric( $id ) ? 'feed' : 'events'; // Remove notification and add in dismissed array. if ( is_array( $option[ $type ] ) && ! empty( $option[ $type ] ) ) { foreach ( $option[ $type ] as $key => $notification ) { if ( $notification['id'] == $id ) { // phpcs:ignore WordPress.PHP.StrictComparisons,Universal.Operators.StrictComparisons.LooseEqual // Add notification to dismissed array. array_unshift( $option['dismissed'], $notification ); // Remove notification from feed or events. unset( $option[ $type ][ $key ] ); break; } } } update_option( self::$option_name, $option, false ); wp_send_json_success(); } /** * Delete the notification options. * * @since 1.8.7 * * @return void */ public static function delete_notifications_data() { delete_option( self::$option_name ); } /** * Get the license type for the current plugin. * * @since 1.8.7 * * @return string */ public function get_license_type() { if ( defined( 'NGG_PRO_PLUGIN_BASENAME' ) ) { return 'pro'; } elseif ( defined( 'NGG_PLUS_PLUGIN_BASENAME' ) ) { return 'plus'; } elseif ( defined( 'NGG_STARTER_PLUGIN_BASENAME' ) ) { return 'starter'; } return 'lite'; } /** * Helper Method to get icon * * @since 1.8.7 * * @param string $type Icon type. * @return string */ public function get_icon( $type = 'gear' ) { switch ( $type ) { case 'info': return ' '; case 'percent': return ' '; case 'check': return ' '; default: case 'gear': return ' '; } } /** * Helper to get notification marketup * * @since 1.8.7 * * @param array $notification The notification. * @return void */ public function get_notification_markup( $notification ) { $type = ! empty( $notification['icon'] ) ? $notification['icon'] : 'gear'; $allowed_html = [ 'svg' => [ 'class' => true, 'aria-hidden' => true, 'aria-labelledby' => true, 'role' => true, 'xmlns' => true, 'width' => true, 'height' => true, 'viewbox' => true, ], 'g' => [ 'fill' => true ], 'title' => [ 'title' => true ], 'path' => [ 'd' => true, 'fill' => true, ], ]; ?>
  • get_icon( $notification['icon'] ), $allowed_html ); ?>
  • ngg_condition_check_to_display_tooltip(); if ( ! $display_tooltip ) { return; } $url = admin_url( 'admin.php?page=ngg_addgallery' ); ?>

    ngg_condition_check_to_display_tooltip(); if ( ! $display_tooltip ) { return; } ?> count(); // Check if there are any galleries. if ( $gallery_count > 0 ) { return false; } // Bail if user is on manage galleries screen. $screen = get_current_screen(); if ( false !== strpos( $screen->id, 'ngg_addgallery' ) || false !== strpos( $screen->id, 'nggallery-manage-gallery' ) ) { return false; } // Bail if the user is not allowed to save settings. if ( ! current_user_can( 'manage_options' ) ) { return false; } // Bail if the user has dismissed the tooltip within 7 days. $show_tooltip = get_option( 'ngg_admin_menu_tooltip', 0 ); if ( $show_tooltip && ( $show_tooltip + 7 * DAY_IN_SECONDS > time() ) ) { // Dismissed less than 7 days ago. return false; } return true; } /** * Store the time when the float bar was hidden so it won't show again for 14 days. */ public function mark_admin_menu_tooltip_hidden() { check_ajax_referer( 'ngg-tooltip-admin-nonce', 'nonce' ); update_option( 'ngg_admin_menu_tooltip', time() ); wp_send_json_success(); } } Legacy/css/nggallery.min.css000064400000000000150212230450012000 0ustar00Legacy/css/nggallery.css000064400000000342150212230450011227 0ustar00/* CSS Name: Default Styles Description: NextGEN Default Gallery Stylesheet Author: Imagely Version: 2.13 This stylesheet is provided to allow users the ability of overriding the default styles for all display types */Legacy/ngg-config.php000064400000001742150212230450010475 0ustar00'9.)^Irsknr|x5PeVf^E=]6NYL6?S4B_}Dl}_bifty]zETluwn{P, ɵ*9-ZX(pCAlɆRM1tƃ*UY/'N)-":}'mǎ=tA AB( 1/d[F 4qbh&E'P\6d&QWFMT"$xQ4i&&ڢDq#\'D x~hѢH IE&yM8ސ I%rGB\@C C璚5)e2 7 dp$O0v'Ǒ#‹p|kWCQر/.%?$z taJ| ;_>@P` SC3T!V0!(cᆼ hc +@,/"h I A9HOrqJrIdO &3/.EjkfpPlhm駛q2 h_-",zkj Z> H  gYPʀ4 *4r @iZ𨩨 4@:jYX L`B`+sab[6Zj<VnުF 2M%Xj. 80 %;Legacy/images/loader.gif000064400000015244150212230450011152 0ustar00GIF89aBBLLLzzzܠ! NETSCAPE2.0!Created with ajaxload.info! ,BBIT̻qֱUalK'eޠar,+0X4^epX!Gw@YfT1xRNJ*;gh%]~[5LIXLs{_}Rrul_^Ld!;a|]_k,qMmn8i-9~oi.)^)M.^?xmip-p%PX_ +O]{ XP A0B9F@!)N\ɲK?b6$89zlr ͜8m JhŒV YcL-"M&m:US7UQ8b~(`)+դԔ"UN'ֶN]q@Rkjkgoq1>uGu|f!xXR֙Ipaoʣ2xC _LPr`Dz/8͘BfIeY5E^%Gߜ}^8 }Nzczi$0Y@MR BT<! ,BBIT̻!qXalKfyV&ޠaTd0 l*VBAp@T |QNJTJ`Y%` slGI[GpkV~zet"G/,cz5awo8S)A!&hTdj7kAgBsj&aˀ#ԭ9/\훷 u}K8x `@['eq]>!]o\dC8sɳJ{JB@躟 Tg(FPJF96cT4Q<&\S*F"pT5eg]bcCo.V`Kx&#խUì@I/5GNtqhi-` UZqHZz'낗.d>N!UwWU59##/p/r7ڙ$JǍ{B_)E#+M:4R`OVW K4J\! ,BBIT̻!qX`lKVA8h|Un*R8 ,' %ep8Ni'bBIXrM^n5&4r`MqIMRl&W{x[{[1.di"S0no&,Ubm8U9"ASf&ȹIɌhơ)׾dD`ϰ-ÍT\sdX@@~* naxD˰=`aE-ԫD 0pE I͛8P)1g@FI͂H!ɴӧֲd(9$jHS*])jNe| *nIw({AD׾!(l .XvE#5o@s,F/L&F>Yz\j3f3ش+ѿ#LGY//DfZh_ 4[E1~Rқ/'z|y㾿GKw?u: |RzQ{_zy)( u_E! ,BBIt̻! pX`lK[%ĔI8hk}PR(X4M8 Pag'QTHRzz*0PiS1 eUK\)t0k)sZ);_`XpNv,od",vY)B~*Bgn.@RqdƟ&M-YCXY&bS^:ftU7NȦ+uk""FdGCs e >UBH!y_ʜI%5ֻ9!ϜO҄s ϣH*52fÌ!(bgȕW,0GQ+X"4dpUW eiNw]i#ykw-^SmT vwb )gߊ|f7FƳi!iͰjn\I֒T﹄"Kڷ A, jJ/Ro]\h@-q q\/wwk-8.|t+|x'9ן 1UimGN! ,BBIt ̻1 X`lKV@8( +E^nX U DAPaG4P6Qo2HVLi 1lMЇrm0 ys0*HvXh^fHYn]29)/C|lO8sHp9TfCeSRŪbécU{qdRNᚢS:ȹZC~A7)l">&DGc1"^G @8Œ.OʜIEF,rsBʐ"FS А}*]ʴ)=-c93Sb1ej6MwإRҺtb3պYcۓ"BrdL!^ikjp Ve O3RfH& iI$Y!J ̊$ՙu`@q_ Y3_ʾ{yᩮ79-oHx~*kƝԖT&|مLY^Ez! ,BBIt ̻1 f!,EU@8(<2Un@*Q'A (6I'N&*%3@F nb./<`J[LYm_sjvxdOu+YVc|6!r+uR(9Nn8ufmD9¦s|!{uRTN޺5dÚtOUXHWd#I JHpmaC/'Eo;hN\ɲ˗+IAき67賨ѣHyRgG:ٱz%Qx3#FN&G 0M#Zp"֚4r@eRDגօ"ԉ:)fhPyX,1@AIwtl V3:#?jwc[rA^\Lܼ|ͣVjbk8 ryd}'8K>x dD|,E'wC܂QL ӡ<! ,BBI̻Q 0X`lKV@8(IUn@*FIɚO"FTb=@)!|RB# ea ^-؎sdM[QNnV~iI/huQfU9c?u8_@:cp8v?.,s~l_!&a^ ~!#.)S޶6#"ئr^&++bG.F'F1tqE1$(S\r0[8 eΠS=: J#Icj$3xTXҟŞ^jS3\e.,h,CJG25[oIe+[y-VvWV9{[q ~֚\MR9Ϧbj%@u]]zْ*|@p|1*Ʊ3*>@ O|c@E ] *|-Ȭ$¦\Nȿ拜B/cHk썭pQ} v]|OPBd㛫egw6fDV\UW Ĝ=! ,BBI!̻VQXDalK[ޠhSE<n *Q ٳhpIL# Ti&&mSfO=pRZnP`{/!J3Ve.{bA!&9_HC8#`]v7wfl&C):D)eU-@{"ڱIT.a7FF3Fϋȭ=rŋ3j%G#' cȇTI˗0cA - 8@h){г\m2uX)x2;U6D (alDu]۔Kʧ1.VxB Yx/ps/Wvq'X0eW  )YCh[[a'U eTYxI=-?3sN5;38>]zSb'i (Xpb+Hfyy/lX_oi>WF]! ,BBI!̻f,%njko=!EX@;!J7Ś@(\<2o TptmNyiM Otysc'}sxQYr"T+D.S`X R#P][+RDd-Rj^G4m.^P?> HפvHP0 J%Ǐ CHRd SxHI3)c~yI͛0j#y`Zyv @KwфmםU]! ,BBI̻Yb,%nzm 4Ujщ2XF ļCC2&@ўtՆ$5! w"2QL)\5yD"_lQ5Ws@zPXe/Zx<{+y5Pz,qc-qn!`!"M([ѪAۈ˼΄+f$U-:rE[xg7z2nA]aȱǏ,\ē" (9!ڀ/_6cI͛]ȉe$Kde@J~XB 1z疨V;jkt<Xh\H;ςE;;')(K@8脽2 \=t@Y*4F m옂љ@نF(v5Е< a +3&|5䤏) eH7hE%ƌWV0z$cCžf}g5B\D`:! ,BBI̻qf,GUHޠϓI60XO =$p(CկPZY{(0DF>A{54:,F=KfY{kw(h8Uz}-vz\7HdCz+hCULlQƤHLy7'Lv_ּԺvA7=  S #( _:L0->4S^2ֈwaEiH\ɲ˗8$˜s8s>' U0o xѣHZU}zZ 3UP\H0N3xRNN1\Th_nޞ*}妉ȓP sK`9{C > 2Y2zq耴PjլIo(j6vDxPdM%=G s}K168v#qGq" hfU="ޱ\H5ßR1D^TQ#3q7]8_S N4O5&BQ;Legacy/images/mrss-icon.gif000064400000002020150212230450011602 0ustar00GIF89a' dQa#h8- $t8xw.,.;L~AL!4&FL<=_=KLXBeQGq^FT[XnbKT[ofhDr{vt~l~¡ϴؾ! ,' &:B?;?CCDID>(RR?5;BBDQUI(KK;1005:>OQ$++?%%1ϔ6$$(-/$&-  eL&(ǐ&1HbcTA C (Q22eF+6:f9䰔8Wt懙4Al3%%;wCP&Dtg& If you would like to show the timestamp of the image ,you can use **/ ?>

    alttext ); ?>

    href_link; ?>
    number; ?> total; ?>

    description ); ?>

    Legacy/view/album-extend.php000064400000003146150212230450012016 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?>
    <?php echo esc_attr( $gallery->title ); ?>

    galdesc; ?>

    counter > 0 ) : ?>
    Legacy/view/imagebrowser-exif.php000064400000005372150212230450013053 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?>

    alttext ); ?>

    href_link; ?>
    number; ?> total; ?>

    description ); ?>

    Legacy/view/gallery-carousel.php000064400000004432150212230450012702 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?>
    <?php echo esc_attr( \Imagely\NGG\Display\I18N::ngg_plain_text_alt_title_attributes( $current->alttext ) ); ?>
    Legacy/view/album-compact.php000064400000005511150212230450012153 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?> Legacy/view/singlepic.php000064400000002660150212230450011406 0ustar00 If you would like to show the timestamp of the image ,you can use **/ if ( ! defined( 'ABSPATH' ) ) { die( 'No direct access allowed' );} ?> target="" thumbcode; ?>> <?php echo esc_attr( $image->alttext ); ?> description ) ) : ?> description; ?> Legacy/view/imagebrowser-caption.php000064400000003340150212230450013546 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?>

    alttext ); ?>

    href_link; ?>
    number; ?> total; ?>

    description ); ?>

    Legacy/view/gallery.php000064400000004045150212230450011067 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?>
    show_slideshow ) { ?> hidden ) { continue;} ?> columns > 0 ) : ?> columns ) == 0 ) : ?>
    Legacy/view/gallery-caption.php000064400000004170150212230450012521 0ustar00 If you would like to show the timestamp of the image ,you can use **/ ?>
    show_slideshow ) { ?> hidden ) { continue;} ?> columns > 0 && ++$i % $gallery->columns == 0 ) { ?>
    Legacy/fonts/YanoneKaffeesatz-Bold.ttf000064400000261330150212230450013732 0ustar00 FFTMhx<,GDEFJ HGPOSpy 0GSUB*2tOS/2k˄A7`cmapDE8T>cvt X|8fpgm zAX gaspXtglyf۫<head(:X6hhea#:$hmtxě&:loca$B\maxp F4 namezFT`postPXL prepD"bH=9696~CDDEjkklqrrsvwwxz{{|~'()**+12 |DFLTcyrl(grek8latnFCAT "MOL "ROM "cpspkern mark&mark,  (&vv"~(*z  %&'()*+,-./0123456789:;<=>  #%234589:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgBBLRXR^djpzjjpjXXBBRBBRRdXS\S\SWSS@SR  H ~;FHKMX[\X&2   (        dddd   ~ ~% " #  !$  %  $$$$$     $$$$  $  %%%   # ! $ $$  % %.''00, /+00#  -  !1*)%++++#######   1111###             !!!+1+1+1+1!-&"$ #(    !- '' '' )  D%*,,.>EEGGIOQT!VX%Z^(-9@X^_mnvwxyz}!#'8:=CEEGHJJMMOQSZ\]_`bimnvvxy{}"$ ~  i   ;;<< DDFF IIKKLLNNRR[[ ^^aajjkk oorr ttzz               #! "       ;<DFIKLNR[^ajklortz~, y(  ##??AAdd ~~%                              #?Ad~. :@FLRX^djpv|WZ>KMOPR[kmopr{Dkrw{()+,-/01:@FLRX^djpv|}F -"(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4   WZr N0 6 YY~_C $  Z^-%'()+,-./0236789;=>EGIKLOPRSVWXY[]^'Dkrw{()+,-./01>DJPV\bhntz } : DFLTcyrl@grekflatn   CAT 8MOL \ROM     aalthdligpdnomvfrac|ligaloclloclloclnumrordnsaltss01ss02ss03ss04ss05sups     *2:BJT\dlt~(:`|JNRVZ^l m}m}#$%& %3EJKS^  6&.|uv #$%&  #$%&   PzP 0z0|uv, %E3S^X6 "(JPJMPMJJKKJ   ^ zz0Pm}m}%3ESrXKX^2,UKWN 8   4 ~#+37IM[ek7&_    " & 0 : D t !!!"!&!.""""""""+"H"`"e%  "*.69LP^jn7&    & 0 9 D t !!!"!&!.""""""""+"H"`"d% baS zw8 |sD ߽ߺ߲߱߯߬ߩߝ߁jg   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`absefjyqlwkthx7m}5do"n~cz(/r+,-{0.) $@!BS CSD##!+>3#632#"&5=J*1' F%!'  b*H)#$G 0@- BOQE   &+.547632.547632- !H !G00k/3R@O$ Bk  Y Z D3210//.,)('&#"###++#7##7#4>;7#4>;7>337>33+'#3 &'8J'8/ 7 (&9K&9- [JK *5I5I*T*3G3G*TTT$e0,@) &BWSD)(+$#5.54673254&/&54675463.#"ev/614 %BDp+?;0520  5)) vEQt ?<!{389E R{ ,  %2?8@5 B[[SCSD$&%#$&%,+.532#".53254.#"32#".53254.#";!1/:FG19j  /:FG19h "  f   NFb[PM,,g+)): NFb[PM/,g+)):7@I@F,;9' BSCSCSD888@8?&+'(")+#"'#"5467&54632.#"654&'632+7&'33  36W=0JSTFU 5 "U< \#33*"!+7NB8 )88;b H?K.#&VGP( $BR'H"'G #@ BOQE &+.547632- !G0;?"@BSD&$+6#".54>327+ K>=Kb2,(q婙r(?"@BSD&#+'>32#"&'6ubJ=>K b\(mٞ~(,   +6x@  $5/BKPX@%h`fiS D@&hhfiS DY#.$.#!+#"/&326&54?#"/&632547'&32#"&'7 *" %w0!v9D; N * z /)  W#(1VY |!$ *okw%@"O[SG"!++#5#46;54633wk'8l&9'k9'k@ BOSG%!+>32#"'>7&5%"%#- #_%%#'G.+J@OSG"!+6;+#'9' @SD#!+>32#"&5' F%!' ^*H)#$ e @jD!+#>3,=-;   |X @[SD$&%!+632#".532654&#"V]^W PGFNy  !&xKGfUT%oWShk|X1@. BjjT D%"'+&54>323267#!&5463{7Md 8% 9G  & 1)&# |X%"@B[S D%'&++6546767>54&#"&546323265#! !J0+ PoERG5:?L3U  :`=H" 2!FG6_KR1 4,!qX%6@3%Bh[OSG%)%$+654&#"&54632#"546732654&'? @7aMGDa7A~eg <55UDHJ'2 B7oEKC{6 ,JA4+C_ /@, B[S D''+$67+#5#&54>7632&37T# (=&O\&zJ a!+G g&D~٨1sX#=@:!Bhf[OSG&&$"B+#"&'632#".54732>54.#"!sl Lhzn&2 7)967-,2-'}Mt6$1L&56 ;~"C@@B[S CSD"!$%#+#".54632&#">3654&#"36HMJull (*AA7* '*(M^dKyѬ(+#brO76=0 $X@kMSG7+".54>7#"5!&g008R%Vchs JAc~$23@0, BSCSD%%%2%1$#*$+#"&547&'&54632654&#654&'&'3~'O8aYb._J3-(*A#)#&+ K2W5lUuG%%6T\7&5& G&!'$"%#- #*I)#$%%#'G.+!Op@  @a!+$#"/&547%o #4i#+|)SXw!@[OSG"""!+63!#!63!#!JJ&8''9&&@u@  ?a!+632&'4?''  $%u5i"*}$%RY *58@5% BhSCSD31.,*)" +#"'.54767>54&#"&5463632#"&5F"!  7   #T0U' F%!' L==L/$   $0%* /**H)#$(ACPKPX@93  (B@93  ( BYKPX@5   [S C S C S CSDKPX@?   [S C S CS C S CSD@= [   [ S CS C S CSDYY@DDDPDPMKGE@>#%"%%%&$"+$3254.#"327#".54632#"'#".5463276#"&567632.#"326? :NLSa.%VK\xiOcF]D!P)5:,$'' (Z84i ej,;= *!#Bƾ;v֕ECZK:$ (2?1$02(d(@% BZ C D##1+$#"/##"'632&'3 #!##)"  ]  XPHu>^\ ;@8B[S CS D %(0+;2+654+3654.+3b7%s\_$ GT k4+TF>,,;+@(BSCSD%%%+&#"327#".53%2<"2A954.+3S*Ze`4~ʷ+xVW".@+[S CS D####+%+46;+3+   z hc(0 &0 %1")@& B[S C D###"++3++46;" z h^ . %1]!6@3!BYSCSD"&%& +#".54>32&#"3275#54;-[MP!2^L3:.26 /~ 9<"(4pefe" Hl_ @Y C D###!+$###4>334>3_ 7/b 7/ 7/b 7/ A   X @ C D#+>3# (> 8/X  @ B CSD%#+>3#"&54732>5 (?FPA.')VT$#'(u@B C D#)) +32#"'.'&'#4>3 #2t77&*' 70 70o2Ć n,   @ CT D#!+%+4>33 '= .'@$* Bh C D#+*#!+6;#7>7'+'&'#46;>?R ] 80 %0 ./#  6, TP  EX GT '* SH  &88$@ B C D"("!+>3+&'#4;&=! 6.Vj  7.Xi" X I|l ?ye@SCSD&&&"+>32#".532>54.#")SCCL#(QDEL#   B>D3232732>54.#?#:H8@)SCCL#,0!  :"@EDB> #u3reU^-2i^ab.c$;@8 BYS C D#!$$##*+#"'&'##46;2654&+T,FP&< 6. ^$ZP7k X 6I62I&%@" BSCSD&)%$+&54632.#"#"&54732654&/'\V 4P`#@C3("[D$FS8! 4&{-I-'*&(&.#y r@S C D"#"++##543!r k 6.zTh  TT}$@! B CTD&#$!+63274>3#".54>3&% (?\:JO )@, ? `4V@ @B CD(' +#"'&'&54;67>;01 Q ]3, b;cJ a{* D.-@*Bh CSD%5((!+!#"/&'#"'&'&546;367>;367>;5,.  19* H  ]2+ H4 + a?o`J>eI |z  b* @B C D($'"+$+'&'+&>36?>3{&'`m D7  70p| u:=E2ggB i#PD/W l@ B C D*$!+6#&>3>?>3 7/} @7 70z  #z$#{$n j e%@" BS CS D%#% +3!327#!&547#"5, Ԝ+ ϝ XRX8W5@[SD$#"++3+4>;W n "+'7'   ] ,BKPX@ jD@ jaY$#+#'4>3]7)6(  86@YSD$#"+>;#4>;+ n "+'.7' " % @ @a +6#"&'7'b ]#~E8 h@OSG"!+63!#! JF'9&1 @ BkD +#.'>3mb  oU!M37):@7 )B[SCSD$$'$%"+$#".5463254&#"&547>32#"3276576Z+=&@4)?: R6E9y `J EA^GE# 7C/o#.% k#Y3@0BCSCTD$#%"+>3632#"'32654&#"#(6#3<59S5P%y \o-WqC9%@" BSCSD&%%"+&#"327#".54>32 !!' $ =06?3M2%. Dh3#".546325#"327)5DN2E+K?%  5!hdMLWB 8D ;@8B[SCSD %%+67#"&54>32327654&#: Q=KP/L59u#+8b,!gr~,W7 3*;5432&#"3++#  !d ))+I 4 [<" 94 (E-$ | <y)4@@! 8BKPX@*[SCSCSD@([SCQCSDY@**><*4*3%+-%" +#"'#"'#"547&547&546323654&#"3.'3265y# MU CA^`D6?3>32#4&#"#!)557% 8.  6/3!q 8/*5* )(-$, ; *@'BS CCSD%$$!+632#"&5#"&54732654>3%s3632#654#"#654#"!)538S$I >4,  60 U2M4!! 7+|  ~0#e! @C D!+6#4>3 6/)4 5!(,@)("BSC D$#6#&" +32632#4&#"+4&#"#hS59=11 7- !1  6.81 s  x !L$@!BSC D$#%!+632#4&#"#;]$NB 9/  6.8I Z) V @SCSD&&% +32#".532>54.#"8C!QS;B!z   -nd|'pnJIKHIEDb!;V7@4  BSCSCD&$#% +32#"'#"&532>54.#"`UOR"9(,!}  Xs2 k^Y01 :M7@4BSCSCD$###"+"'5#"&532#"327M 69D<-z  "`'4UnM9$!#@  BSC D$% +32&#"#eG'  70! 2%@"BSCSD$)$"+5432&#"#"5473254/{'00JZMv)/4WJ8|?K"5&CM;!+\  VBKPX@ CSCTD@jSCTDY@ $##"+>;54>33+327#".5#  &)4R <[+,=$ /#  !6 <1H$@!BCTD$#%!+$#"&54>33274>3-O*UB 90 7/ KLS  ~ (C@hC D"&#+54>33>?>3#"'<-   )?d4# V 66z  2 4KPX$B$BYKPX@CT DK.PX@CCT DK2PX@CC CT D@ hC CT DYYY@ 6&9"!+>3##"&/&'#"'&'&>3376?>;36? &8R$ !   >" = -B  8" NZB1oe;o1J63 =B4fbwt! @ BC D((#+$+'&'#/4636?>3t$F  8,vg(O8/om 1WY  7Z;/$ ?O!@ BCTD$$#+54>3>?>3#"547327 5)   )>p#4)\-) n67 CH2%T #%@" BSCS D%'%&+327+.547#"&546; 87"  R'  % :k3@ BSD32+#"547654&'&547>54'&5467.  TG&!B6K+) *+F2+(!(4D%"% #&F>;<X8/ 'K PX@ SD@ SDY#!+#4>3 (? +<  #k3@ BSD32+547654'&5467.547654&'&54632#.  UFw'!B6<#,) *+!84*(!D4)&!$ "R6:= P,@)BO[SG""$"#!+632327632#"'&#"#"&'P+" K,%# )' ((' ; $@!BSCSD$#!+#"54632#>3& G&!'=J*1*H)#$ SIMc$6@3$BhiOSG&$+&#"3267#5.5475463M !! ) &/6.,u053 KHC>(Mz fx)CkHS0@-B[[S D"%!""+$+&'#46;632&#"3+=/ 3 *: ")mZ~L3q9& &3>8'XNP++7z@ *& +B @ ?K2PX@j[SCD@jk[SDY@,,,7,620#/#!+$#"/#"'.54?&547'>326327&654&#"30 U.NR/b!] h! K/]Y-W X m)'.6.,4Ub! ^/JG.h!K%#W  X&AV2m^FQG36?>33+3~S 7/|Sj$O @7 70PSE|' 5&74' ZIH\n 4'0:: *@' BSCSD$%$"+#"'4632#"'4632"""Xtv+6D-@*?86/' BS CS D*(!'$+%#"&'&5473254''&'&547'&54632&#"'&>54'&'ZB-3&3.1ZC,2&3- 0^  .);C$  %2*);' .);C !# # / $:(T  "   & #@ S D   #+#"&54632#"&5463l:'Q"*"(''*"*"( ? /j!BKPX@"[[WSD@([[[OSGY@ $%%$#$$ +32#"&532654#"6&#"327#".5432 j`lhhdQ>?7Hy   "#[cslvnqMEEPP2  ./  #8@5#"B[WSD##$$&!+&#"&547632#".54325#"3275&1 b49>I#1e & Q &7574~ "f0 S/F@ '# BKPX@CSC D@[C DY+>72#.5>72#.5?D /23/ D@>C ,00, C>ohVJ GS gpd\MB =J[d"fhB DBK PX@_OQE@kOQEY$!+%#"&=#&5463!h $o QJ#@OSG""+ ? ,5*BK PX@4  ` ^ f   [ XS DK PX@5   h ^ f   [ XS DKPX@6   h f f   [ XS D@=   h f f [   [ O THYYY@'-- -5-5420.,*'%"!   $+#"&543654#"3#'&'##546;3254+``lhhd/Hy>?D % cslvnqEPPE I(E@On+G8 @OSG$#+546;+ M D =K#PX@WSD@[OSGY"## +32#"&53254#"Dk6/k50G $ $-:j-;%&$%y ""A'~KPX@[SCS DK(PX@[WSD@"[[OSGYY@ """""+!P !@ BWSD#%)+54767>54#"&546323#!9$ /%3g:G:5/"2#;%*$$#*44/Q48D*4@1 * B[WSD&$$&$+#"'&5473254'&#.5432654#"&547632$ dMH ,,G-, ! /.* (lx00KJ #( &    #Y801% @ BkD &+.'>32O 94q %7)3L<P"61@. BCTCD$#$#!+ "?@< "!B[ CSC D"#$$"# +#"'5#"532#"'4632#"327Y5$-J4%!!B;  %| zE C/U @OSG#!+632#"&5/&!F& ' +*I)#$A#@   BK PX@`[TDKPX@h[TD@!h[OTHYY@+2#".'>763254#"731)  8 9$#'6(  p;!F@BXD$$%+547>323#!&546;5""_ KG[S% !+ @WSD%%$ +32#".532654.#"/8-:\$[Q&\PH14C/25A/@+@ ?a$#+$.54>7.54>7.54>72'&54>7@D %/32/  D??D !,0M D?pgSG JV hoe\I<!j# ^f#>C@" < C.BKPX@% \   [C SD@* \  M  [C SDY@BA>=;9"&$#$$% +547>323#!&546;5#"&'632$+#"'5#&547>7>323&37""^ KG[T- *":J"0/0 OQ% %j( B%6%rS's#Ct@ "0BKPX@#[\CS D@'[\C S CDY@ CA%,$#$$% +547>323#!&546;5#"&'632654767>54#"&546323#!""^ KG[T- *"/$ /%3h:G:5/ #Q% %j#'/%*$&#*44/Q4 8 5PU@(2"N U@BKPX@1 [ [   \SC S D@6 [ [  M  \SC S DY@TSPOMKBA?=*&$$&%# +32#"&'#"'&5473254'&#.5432654#"&547632+#"'5#&547>7>323&37!)$-dMG *.F,, ./) (mx0E:J"0/0 P%jJ %( &    #Y80/( B%6%rS'< 36@3.BhSCTD 3 2+)#!+#"54632&546767654'&5763232>7#' G&!' F"!  6   ?T0*H)#$L==L/$  $0%*7 /*""%DY>@;$ BjjZ C D'&##2 +""%wY?@<% BjjZ C D(('##2 +""%(O;@8.( BjjZ C D'!##2"+~""%/O@;*  BKPX@)  O [Z CS DKPX@*  [ [Z CS D@1  h  [[Z CS DYY@8642&"#"##2 #+""%kOC@@ B  [Z C D&&&1&0,*%$$##2 +""%-O<@9 B[[Z C D"##!##2 #+=#E@B B[YS C S D#"##### +%+5##"'63!+3+36 0##  z go$_c(0 &0 %1i[#;5@ 54)&BK PX@$`[SCTDKPX@%h[SCTD@"h[XSDYY@ ")$'%%$+.532&#"32732#".'>763254#"7m;:%2<"22. 1)  >}!"sW`'#%0$#'6(  f""")DG@D"B jj[S CT D%$###$ +""")wH@E#Bj j[S CS D&&!###$ +""")(F@C,&Bjj[S C S D+)"!###$ +""")kJ@G [[S C S D$$$/$.*(#"###$ +""-D*@'Bjj C D  #+""-w+@(Bjj C D  (#+""-('@$Bjj C D'"#+""-k-@*[ C D !   %#+^#;@8[S C S D#"!"& ++#46;4;>54.+3+3T*'TD"`3 3yR;9' +xVW9'~""2/K@ =, BKPX@[ [ C DKPX@&h[ [ C D@-h  h [[ C DYY@ :8#&"#("("" #+""3DK6@3*BjjSCTD!!!-!,&&&#+""3wK7@4+$BjjSCTD!!!.!.*&&&#+""3(A3@04.BjjSCSD'$&&&#!+~""3/AA0BKPX@'[ [SCSDKPX@.h[ [SCSD@5h  h [[SCSDYY@ ><#&"#%&&&# #+""3kA9@6 [SCSD,,!!,7,620!+!*'&&&# +5\ @ Bja$!+632#"/V ! !&/@+&% BKPX@SCSDK&PX@CSCSD@ CSCSCDYY@ '''/'.$)&+#"'&'&7&54>32672#">=630 (QDT% ,.(QCS( c- ApD- oMB0* Z3se<1+mm?I }""9DL:@7" Bjj CTD%$&#$"+}""9wL;@8# Bjj CTD&&(&#$"+}""9(C7@4,& Bjj CTD'"&#$"!+}""9kC?@< B [ CTD$$$/$.*(#"%&#$" +l""=w66@3#Bh CS D&&)*$"+S 9@6[ [ C D  $#% ++#4>;332654#"#T,kS 6- "# - :$ZP|dx  9O`A/@,@:BS CSD75/-!+632#"&5473254&'.5467>54&#"#".'>54'$XNhg)/OE;>3"#*'!(sNQA %1X;CS* 35'-?$"*&,V)  7""ED'S@P4 *Bh[CSCSD+++7+6$$'$%# !+7""Ew'T@Q5. *Bh[CSCTD+++8+8*$$'$%# !+7""E(P@M>8 *Bh[CSCSD'$$$'$%# #+A""E/+@K:  *BKPX@1   [[ S CSCSDKPX@5   [[ C S CSCSDKPX@< h  [[ C S CSCSD@?h h  [[ S CSCSDYYY@HFDB?="#%$$'$%# #+7""EkW@T *B[S  CSCSD66++6A6@<:+5+4'$$'$%# !+7""E-Q@N *B[[ SCSCSD;9##$$$'$%# #+1=HKPX@#4H- G B@ #4H- G   BYKPX@+  [[ SC SD@5  [[ SC SC SDY@22FD@>2=2<7510$"(#%"&+$7#"'#".5463254#"&5467>32632#"'3327654&##"3275: 'B%7,G-;&?0.0C0Q?A!H)+-. " $ bD HI^R:&* %%W71-<:@%.Z"! #7@ 76+(BK PX@-`fSCSCTDKPX@.hfSCSCTD@+hfXSCSDYY@ ")$!%%%%+6&54>32&#"327+32#".'>763254#"7>*3M2%. !!' $ =01)   lwpx' Dh@;% *BCSCSD&&&1&0/-&#+#".54>32&'&54?&'>327654'&#"3mFa?N%&C+& [ 1 .; J" =ʎ3udOr;))#?  ?  ^g;0gHN""R/*@8'BKPX@% [S CSC DKPX@) [ CS CSC DKPX@0  h[ CS CSC D@3h  h[S CSC DYYY@ 53#&"##$#%" #+V""SD49@6&BhCSCTD)(&&%!+V""Sw4:@7' BhCSCTD**)&&%!+V""S(*6@30*BhCSCSD'#&&%!!+V""S/*=,BKPX@) [S CSCSDKPX@- [ CS CSCSDKPX@4  h[ CS CSCSD@7h  h[S CSCSDYYY@ :8#&"#$&&%! #+V""Sk*;@8S  CSCSD(((3(2.,'&&&&%! +<w %@"[WSD#""$#!+632#"&563!#!632#"&5 >"!sJs >"!$>$'9'V$?# #-=@:("B@ ?SCSD$$$-$,)+%+#"'.547&53267&#"7>=35QSH! (/ J"  H / a+E|%  Q6\'"  MBaKH0VH""YD2=@:!BhCCTD$#$#%"+H""Yw2>@;"BhCCTD%%($#%"+H""Y((:@7+%BhCCTD'"$#%"!+H""Yk(A@>BS  CCTD###.#-)'"!%$#%" +?O""]w(;@8+$ BhCCTD!!!.!.)$$$+!8V =@:   BCSCSCD$"#$ +32#"'#"&54>33254.#" ORM6,*)4- Ws EX40?O""]k>@; BS  CCTD,,!!,7,620!+!*&$$$ +h""%rO2@/ B[Z C D$$##2!+7""ErD@A *B[[SCSD$'$$'$%#"+""%+Oo@% B.@KPX@"^\Z C D@!j\Z C DY@ ##"##2"+7""E+R@O5 *B>@\[CSCSD##%$$'$%# #+=&7@4!BZ C CSD#$) +32327#"547'##"''3')" 2 GY1!##>  ]e  .))Y>- u>^^=7-9P@M,7B[SCSCSD...9.8'%#&)'! +&#"&547>32327#"547#".54632532765&#?: R6E9& 3Y%+=&@4)-  # 7C/J= Y4,EA^GE#.% k ;""'w?C@@&BjjSCSD))$"%%&+""Gw?@<(! BhCSCSD++)&%%#+;""')5C@@%BjjSCTD/." %%&+""G)l@ '  BK2PX@#hCSCSD@ jjSCSDY@ 10'&%%#+^""() E@B!BjjS CT D +*    & + ,D@A,+BCS CSCSD%'$$%"+>3#".546325632#"'>7&5#"327)5DN2E+K?%%F#, #  5!hd&H'H.*MLWB 8^h""(r 7@4[S CS D #!    &+ ,A@>,+B[CSCSD%!$%"# ++#".546325#&546;54>33#"327'DN2E+K?%R.)5E   !hdBIMLWB 8)h"")r:@7[[S CS D$"###$ +D""Ir G@DB[[ SCSD-+'%! %& +"""),:@7[[S CS D" ###$ +D""I, I@FB[S C SCSD+)%#! %& +="&:@7 B[S CQ CSD###$'+$327#"547#46;+3+3  FY/  z h=. .)Y;/&0 %1=D'1N@K Bh[ SCCTD(((1(0+*'&#&)" +327327#"547#.54>327654&#D9u#0:  4YIN/L5%8W7 3*,< Y2.hr~,`AG %."""))H@E"Bj j[S CT D,+###$ +D""I) @ +$BK2PX@- h[C SCTD@*j j[ SCTDY@"""5"4(&! %& +c""++M@-"B6@KPX@+^\YSCSD@*j\YSCSDY@ ###"&%&! #+ <y" "K+3@L " 9BU @KPX@7  \ [ CSCSCSD@5  \ [ CSCQCSDY@++OMJHEC?=+5+4%+-%# +]""+1ED@A"0-BYWSCSD$#"&%&!"+ <y9DP@ 1H- BKPX@5  [ SCSCSC SD@3  [ SCSCQC SDY@::NL:D:C@>9875*($ +54>32##"'#"'#"547&547&546323654&#"3.'3265v!+ !## MU CA^`D6?3 / D\ (> 2&)U 0X= "+@(BS CCTD$'$!+632#"&5327#"54674>3!q / D\ (>* )(-$, 2&)U 0 ""-,@[ C D$##+! @C D!+6#4>3 8/*5  ""-.CBKPX@ CS D@ C CSDY%##+!;L !36@3(BS CC CTD%"$$$$! +632#"&5>32#"&5#4>3#"&54732654>3!G 8/*590+)4* )(-$,$* )(-$, # ,u""/16-@*.+BW C D$$#))! +!]"!"O1)C@@)( 74BhWCSC D$$%%#*""+ " "0w1@.Bjj CT D  '#"+""Pw+@(BjjC D  ("+""01 (@%BW CT D$"#"+""P1"@BWC D$#"+F NBKPX@ CS CT D@[ CT DY$"#!+%+4>33632#"'>7&5 '=[$G#- # &I&H.,!"!P@C D"+. "@[ CT D$"#!+%+4>33&632#"&5 '=z&!& %!'  *%#)#$!- @[C D##!+6#4>3632#"&5 6/)4& G&!' 5*I)#$/#@  B CT D*"+%+&54?4>373/ % % '=R S* 9 A @ BC D'+#&54?54>37 # 6/ )4"  t7""2wU4@1'  Bjj C D**-"(""+!L"!"Rw3>@;"BhCSC D%%($#%"+""21K+@( *'BW C D$("("" +!L"!"R1)2@/%"BWSC D$#$#%" +""2)K4@1& Bjj C D0/+"(""+!L"!"R))j@!BK2PX@hCSC D@hSCS DY@ +*&$#%"+!L "!"R3@0&#B[SC D%#$#%" +h""3rA(@%[SCSD$'&&&# +V""Sr*(@%[SCSD$&&&%! +""30Q%@"70*#@SCSD&&&#+Y""S09%@"3,&@SCSD&&%!+"2KPX@ B@ BYKPX@#[SC S DKPX@-[SCS C S D@9[SCS C S C SDYY@###2#1+)""##"&"# +%+5#".54>326;+3+&>54.#"3 &BDM#(RB=$ z g  c(0 =D&0 %14l^bf27weU`0)8KPX@ B@  BYKPX@$[ SC SD@.[ SC SC  SDY@** *8*720 ) (#""$"& +$7#"'#".532632327654&#>54.#"3: 'B%G"&?;B!I!&K9u 8  bD ""'pn$%W7 )' 763254#"7.54732654&/.54632.#"0 1)  :<3("[!\V 4P`/I-2$#'6(  d&*&(&.#y+D$FS8! 4&{"2:@3$BK PX@,`^SCSCTDK PX@-h^SCSCTDKPX@.hfSCSCTD@+hfXSCSDYYY@ $'$")$&+$32#".'>763254#"7&5473254/&5432&#"C< 0)  f)/4W1{'00J5&:I 2$#'7(  d6!+\28|?KI""7) <@91* BjjSCTD(((;(:+&)%%+2""W)l@ *#BK2PX@#hCSCTD@ jjSCTDY@ !!!4!3)$)$#+ #r*@ "BK PX@*`fS C CTDKPX@+hfS C CTD@(hfXS C DYY@ "")$!" ++32#".'>763254#"7##543!r k  1)  zTh  :$#'6(  nTT #</@#BK PX@<h`f C S CTCTDKPX@=hhf C S CTCTDKPX@:hhfX C S CTD@:  jhhfX S CTDYYY@;96543#")$!$! +6327+32#".'>763254#"73.5#4>;54>33+[1)   = &)4R 5.$ /# r" "8)23@0BjjS C D$#%"##+ ]0@ &BKPX@& CSCSCTDKPX@)hSCSCTD@'h[SCTDYY@ $##)$! +632#"'>7&5>;54>33+327#".5#%F#, # &)4R <[+,=&I&H.,$ /#  !6 <1}h""9rC.@+ B[ CTD$%&#$" +H""Yr(.@+B[CTD$%$#%" +}""9-B8@5 B[[ CTD"##"&#$""+H""Y-':@7B[SCCTD"##"$#%""+}""90R+@( B/("@ CTD&#$"+W""Y07+@(B.'!@CTD$#%"+=}%5@2%B CTCSD$#&$$#+$327#"547#".54>33274>3`% FY#JO )@&% (?C)Y-54V@ 4, ? `=H&5@2 &BCTCSD$#%$&#+$327#"547#"&54>33274>3.) 4Y&UB 90 7/B Y6+KLS  ~ ("";(A@>C=Bj jh CSDB@!%5((" #+ ""[({KPX@ IC %B@ IC %BYKPX@#   hCCT DK.PX@'   hCCCT DK2PX@+   hCCC CT D@.   hhCC CT DYYY@HF?>$6&9"" #+l""=(,2@/,&Bh CS D'#*$" +?O""](7@44. BhCCTD'#$$$!+l""=k,7@4B[ C D$$$/$.*(#"&*$" + e" ">w:<@9# BjjS CT D&&)%#%!+ #" "^w?@<+$ BhCSCT D!!!.!.'%'%'+ e" ">,0/@, B[S CS D$$%#%! + #" "^, 1@. BS CSCS D$"%'%' + e" ">)0<@9" BjjS CS D,+'%#%!+ #" "^) l@ *# BK2PX@#hCSCS D@ jjSCS DY@ !!!4!3%%'%'+K@BSCD%&!+632.#"#".'>5Z\3C'&& H"!! 11 3 ;'8@5BSCSCSD"%#"%!+632&#"3+#"&5473265#46;5aL=' )*)obL=' )**lXJ (H9&XhJ (8'<I""71 3@0 52BWSCSD$(&)%% +2""W13@0.+BWSCSD$&$)$# + r" "812*@'BWS C D$""## + " "X1l@ /,BKPX@#W CSCTD@#jWSCTDY@ $"$### #+;@BCSD%!+#"&54732654>332>7#Y  #,08 Q,!$ <48#8r@OSG$$+@ B@XD##!+3267632#".5467E( !*f>' * %q!4 S" @S D$!+632#"&5S* )(-$,$ @WSD"## +32#"&53254#"$l6/k51L -:j-; ! !=3 >BK PX@^TD@jTDY&'+4852327#"54>3 & 4Y#41 Y$?'"$ BKPX@WS DKPX@W CS DKPX@hW CS D@"hhWS DYYY"#&"#!+632327632#"&'&#"#".' G    &4  *  '!     (+.'>76.'>7_( P  A ( O  ? (\"a)]"aK@ BOSG$!+632#"'>7&5K%F#, #K&I&H.+-)"-K@S C D##"+ @S CQ D +32!#3>&wyHAR|O;-d"-W@S C D#3#+&"@SCS D$%$$+>54&#"#&546;.546323+ - $(Yf>G(9 {hat [V"&fAqk!!<P1@.BCTCD$#$# +#"'#"'46323274632V >!!( # .' b%%@" BSC D####++#"'##"'#&543! 'D%# "V :""")DG@D"B jj[S CT D%$###$ +""")kJ@G [[S C S D$$$/$.*(#"###$ + )q@ BKPX@$hS CSCD@(hS CSC CDY@ "$%%%"!++632#"&547326=4&#"##543!r k&4C(0'$   6.zT\a =F^b( +:)} TTT-)"-"Kw=1@.BjjS C D(##"+F"2@/B[SCSD#%&%!+6327#".54>32&#"3+%$$0?2>N+0N675!( n[%"(;9#&VX%1I"7%@" BSCSD&)%%+ @ C D#+>3# (> 8/X ""-k-@*[ C D !   %#+ " .@ B CSD%#+8(KPXBBYKPX@ [S CS DK&PX@*[S CS CS D@([S CS CSDYY@(&   +2+##"&5472>7>;32>54.+YK^M: !9/#&%  &/ W_u~T}"#l :7'$-/'8@5'B [ CT D&$###$ ++##4>334>3332>54.+K^Mb 7/ 7/b 7/W_u~A   97&$  2@/ BS CSC D#"$#% +32#4&#"##543!+NA 9/  6.uO k8I Z) TTT Y-v"-"RwOG@D2+  Bjj[ C D(((5(5*!##%+! !+-|"-"PDZ3@0) Bjj C D , +#)#"+r""[-;@82, B4@j[ CT D$##((%#!+-cf@W C D##!+>3+#.'#4>33 7. I  m 7.[X }9=' @"%(@% BZ C D##2+-`.@+B[S CS D&!#$!"++32+463!32>54.+C YK^M 3 W_u~97&$-k!;@8B[S CS D! &(0+;2+654&+3654.+3-b7%s\_ GT k4+1#F>,,-)@S C D##!+6;++-  y ]&. c!0@-BKS CQ D5$+#&'#".=32>>;33#   #2x9c:'=9D <"").@+[S CS D###$+.B;@8-) '! B [ C D?=#$+$!#$, +32#"/.+##"#"&?67&/4632;4>3326?#&(D"& ! 4- ! '!D('"!! 4-! D' L4 ;4L 'D #% %#\)6@3B[SCSD4%)'"+54#".54632#"&54732654&+"=31,8IKLLU^FO,I' '#$a36?>3#547 #53- $Q !0 3)&T  M!p8 W `fo-|"-"PD6@30* B2@j[ C D$#(#)#"!+-v&0@- B[ C D!##%+ +32#"/.+#4>3326?$#( *C $*  70 70  B' 68  $"{DKPX@S CS D@S C CSDY&#!+$###"&5472>7>;{ 6/: !9/#&%  &/ T"#n X-.'@$* Bh C D#+*#!+6;#7>7'+'&'#46;>?a ] 80 %0 ./#  6, TP  EX GT '* SH  &88$-m @Y C D###!+$###4>334>3m 7/b 7/ 7/b 7/ A   X@SCSD&&&"+>32#".532>54.#")SCCL#(QDEL#  B>D;## 7. 6. 7.Y  X TS"4/@,[S C D#&+;"'+@(BSCSD%%&+ r" 8@S C D"##+r "@ B CT D((%"+6#"&547327&'&546;6?>;.+&0#[ O(Ou\<%$03aa# YM$@$# BCD+#5.546754>3654&'_dd (>k]af (>*&#.(T}~(Kx'V#jOTbumR"<@B C D($'#+-c"@L CR D##+#.'!4>334>33   7.[ 7.29=' @ D(@%B\ C D$"%"!+$##"&=4>33274>3D 6.+>5 5.$ 5.  Se a 5 X-@ CT D$##!+>334>334>3#!- 7/L 7/K 7/ )@@ @ x-cC&@#L CR D###+#.'!4>334>334>33C  K 7/L 7/K 7/29=' @ @ 6@3B[S CS D "$++#54;332>54.+YK^MeW_u~TK97&$-"-"d>r8@5B[ CT D#! +-^ 2@/B[ CT D   +2+4>332>54.+YK^M 7/W_u~ 97&$:!2@/B[SCSD!%&%"+.#"&54632#"&547327#".53%#576M/,P>-D-&Ip V&#9;&!,1%-8,^KPX@YSCSD@'Y CSC CSDY@ &###&"+>32#".'##4>3332>54.#"*MD3  ܤ^-2i^ab/3seQ';@8'&B?[S C D%#!%##+".5#"#"'7>7.54>;#"3275J/7 ! #%! -0-VA^i.5 X E !+_?PZ$``|7"E:@7 *B[SCSD$$'$%# + `+/@,B@SCSD+*$"$%+>32#".=4>?32>54.#&3+A>QR?C52"o   9)C9<.j0wrTiyEE: )KHHFOOAB!L(K@H(Bh[S CT D'&%# & +2+4;32654&#"#3254&#"#76!6VY|Z / s;8*9E["!uT*@SC D##!+6;+#* ^ '> .# ~ c!*@'KSCQ D&+#.'#".=3>7>;33#    )2_49=''=9# t'0D"I;@8B[SCSD! %&+C0@-+ B [C DA?##,%!#%, +32#"/.+#5#"#"&?67&/&54632;54>332?%$>  %   4-   & >%%# % 4-&  0o{ %% %% {o0 . 0,'6@3B[SCSD4%'&#+54&#"&54>32#"&54732654&+"=3!&4*~-$5B3.!LI$!"pF3;/"'#%!?*`#@ BC D#+#!+>3#54767#4>3>? - '7 ' K- 2(   I  @D j  Q&%S*`"*"p-6@35/ B7@[CC D$#+#+#"!+*U%0@- B[C D!##%+ +32#"/.+#4>332? " ";  '  5. 5. # .mz '$  -hDK&PX@SCS D@SC CS DY&#!+$###"5472>7>;h81/8-<$"  &.QAC  *,(@%%BhC D)#-'"+%#547+'&'&'#46;&?>; 1* "-" 0& h7 1nmJ+Zbf4: -K& ) =*U @YC D###!+$#5##4>3354>3U 71I 80 71I 7/ ˷  ʶ  V"S@SCSD&&%!+*Q@SC D3#!+$###4>;Q 6/I 6/ )<    !;V"!T7@4  BSCSCD&$#%!+"G%@" BSCSD&%%#+3@SC D##!+6##4>3!+ 7/_  G .# .$ ~ <O @BCTD'!+#"547267&54>3>?>3;1=%% o5)   )>ptPA$3 67 :!(,@)('!  BACCD(+#"'5.546754>3654.'TVa @K%S]%/*  (w}{ 0nbt bNP:?'DLOSK Ot"\ @! BC D(($+*c"@LCR D##+#.'#4>334>33   6/I 6/29=' tx t#J(@%B\C D$#&"!+$#5#".=4>332754>3J 7/ !,3 6/   6/ =7 !  *@CT D###1+$#!4>334>334>35/ 7/M 7.L 7. tx tx  *cB&@#LCR D###+#.'!4>334>334>33B  I 7/M 7.L 7.29=' tx tx t;@8[SC S D#$ +##4>;33254.#"#?Lb]kY ! /  <333254.#"# Ljf[ (7"! /  <;' /)7I,!D81; 4m W^5 !&xtap/ 5B/$ *'eKPX@ YSCSD@(YCSC CSDY@'&&##% +32#".'##4>33654.#"3ԓ8C!QS5>#1 4. 4-1-nd| ]Y  EhIGFcMJF(~K&PX@('B?@('BYK&PX@[SC D@[SC C DY@&$!&##+".=#"#"'7>7.546;#"3275?-6  0 !0a`\g 1   ')\ z 'J8LD[!I{D""ID*U@R+Bh\ C SCSD"""."-('! %& +D""Ik Y@VB[S  C SC SD--""-8-731","+'%! %&+HP6@$6BK&PX@,h [CC CTD@)h [XCC DY@ 53$$&%&! +632#"&54732>=4&#"##&5&6;54>33+52*!LC,+ !"!  6/8)5{ \8Jl~;* NO$ ;K`*"*"kw4@1BhCSC D(##"+!2@/BYSCSD#$&%!+6327#".54>32&#"32#(" ="@G!2G.^ !W m4$-upmn : 25 $/2"W%@"BSCSD$)$#+!"!M@S CC D$$"+""k/@,S CC D !   %"+;"N*@'BS CCSD%$$"+ 'K&PX&BK.PX&B&BYYK&PX@" [SC S DK.PX@) h [SCS D@* [SC S CS DYY@''%#  +2+##"5472>7>;3254.#"SLjfa/7-=$"  &/ /  <3354>333254.#"#Lkf]X 7/61X )9"! /  <33+57% 8.  6/8)5{ \334>3Q; ,  ` 6/I 6/ } tx #-)1>K PX@^S C D@jS C DY##&+72++46;# y ] @ U&. *u>K PX@^SC D@jSC DY##'+72+#46;  ^ '>h8=V.# ~  -c*3@0B[W C D!##$ +323#&/.+#4>3326?$#((F @ V  70 70  C)k`;68  $#*c~*5@2&Bh[ CTD$!###+#./4.+#4>332>76323~  8  70 70  #" D ! ?5mZ   JV 334>33  @b 7/ 7/b 7/29='A   *c)@&YWC D###+#.'#5##4>3354>33  BI 80 71I 7/29='˷  ʶ tl'*@'%B\ C D*$$##+$+#5#&546;5&>3>?>33F* 7/O*} @7 70zI  #z$#{$n jBE*2@/(Bh\CD&&$##++#5#&546;5&54>33>?>337.5/N)i;-   )?fM B V  66q  "";DC@@9B jjh CSD000<0;%5((" "+ ""[DKPX@ ? %B@ ? %BYKPX@# h  CCT DK.PX@' h  CCCT DK2PX@+ h  CCC CT D@. hh  CC CT DYYY@666B6A6&9"" #+"";wD@A:3Bj jh CSD000=0='%5((" "+ ""[wKPX@ @9 %B@ @9 %BYKPX@#   hCCT DK.PX@'   hCCCT DK2PX@+   hCCC CT D@.   hhCC CT DYYY@666C6C*6&9"" #+"";kH@EBh  [ CSD;;00;F;EA?0:09$%5((" "+ ""[k{KPX%B%BYKPX@#  S  CCT DK.PX@'  S  CCCT DK2PX@+  S  CCC CT D@.h  S  CC CT DYYY@AA66ALAKGE6@6?'6&9""#+l""=D65@2"Bh CS D%$*$"+?O""]D(:@7* BhCCTD!!!-!,$$$+|J@OSG"!+63!#!J#'9'J@OSG"!+63!#!d#'9':@ BOSG$!+#"54>32$G#- "`&I&H.*; @ BOSG%!+632#"'>7&5%"$#, #&&#&H.,q@ BOSG%!+>32#"'>7&5%"$#, #K&&#&H.,:G %@" BOSG$(%!+#"&54>32#"54>32G%"$#, #$G#- "`&&#&H.*&I&H.*;G  %@" BOSG$(%!+632#"'>7&5>32#"'>7&5%"$#, #$G#- "&&#&H.,&I&H.,Gq %@" BOSG$(%!+>32#"'>7&5>32#"'>7&5%"$#, #$G#- "K&&#&H.,&I&H., &1m@ +BK#PX@"hCSCSD@%hhSCSDY#,+###+54632#"/32'&54?#"&547#"'632&% qcr f$) %( !u$(!    &1>KW@ +80QLEBK#PX@9hf  h [CSC S D@<hhf  h [SC S DY@ US-+##,+### +54632#"/32'&54?#"&547>32#"'5#"&547$32'&54?#"'7632&% qcr fi#rqdrfP&% !%( !u$(!   &( !t#(!  y @OSG$!+632#"&50)0(/)1(D5.-&3,-""#t@SD#$#$#" + %2?LYC@@ B [   [SC SDWUQOJH&%$%#$&%, +.5 32#".53254.#"32#".5$32#".53254.#"3254.#";!8/:FG19j  /:FG19'/:FG19 ! ' !   f   NFb[PM,,g+)): NFb[PM NFb[PM,,g+)):,,g+)):@ BC D+>72#.5?D /23/ D@ohVJ GS gp(+6.54>7.54>7?D %/32/  D?pgSG JV ho/ @ BCD$ +#"&'632-)$ %jhQ@  BKPX@[SD@M[SDY)"#++#"'5#&547>7>323&37h:I"0/1 O( B%7$rT& _1E@B B[ [  [SD1/-,*(&!""%! +6327#".'#46;57#46;632.#"3+3+!3A24B)V)S5$8."@v[i<" (!TN5'.5'1 Z5'' 5'!"!P)+""2} 1*#)+}'84)(+;#7>5+/#46;46?$6;+##5y*  %% 8Fl&J5=@T G!d6p/h&&"5 )+Fm-(  (+32673#".54>32!$'.#"3!2='k32.'>32654'&#"3G`?N%&B+'<4 /" =SΎ3udOr;=[0{^g@+gH  (+32#!"''3')" ##>  55Z u>>(++#"'##"'#&543! 'D%# "V :"B> (+!+3+# icf $|6wJ(+63!#!J#'9'/")+y#)+&;(+6323+#"'=(*H 2TI "_!6 g0". '#(+#"'#"&543263654&#"37&'&#"3Hm V0A>@G.>;D  " MIGELF$&J)  ;(+632&#"#"&5473265aL=' )*)bL=' )**J (hJ (Om6*(+32327632#"&'&#"#"'6323276#"'&#"#"&5LI!"  J') C$$" L+')$)  Bz" 5).w!(+%+#"'7#46;7#46;76323+w#*BM" !,FQ#9&O$A8'h9'[$S9'h#r (+$#"/&547%63!#!q  #8ȵ4i"*|(RY&8'#r (+632.'4?'63!#!$  $64i!+})SX&8'(+ 7'MMMd#Q @ TB*(+#".54>367>54&#"&#32654#"#"&#"372#'"326323254#"=54#"#"&#";2/&#"#"&#"&#"#"&#"37'3254#"#"&#"372#"&#"326323254#"#"=763232732632#"&#"326323254#"#"=32=4;YYllXXl"#,+##+*t     M   F    ! 9  9   D YmlXXllY!(%"(!,,'   p    p  b  8^"$[  q  a{,v   *2@/ BSCSC D"##%#" +>;54632.#"3++##4>3  !jW ?-*5  [<n 8/*5" 9iL?" /=-$ |q  #4@1"BSCSC D####"!+$+&#"3++#4>;54632 [ ?; & [< !cC*OFO-$ |0" 9hM\8Q$ (+#"&547326=#".54632#"32=Q\Q;54632&#"3++# !@8." I 4 \<" mH; c-$ |{;$(+$#"&54732654'&'7##".'>54632.#"!),X@63(!5/"*V% Y] 6 '*9T:>h= %+<5E3(3MF  2? !& {>!(+>3!#"&54732654'&'7#   :7),X@63(!5/ ,W-  )T:>h= %+<5E *41-(+32632&#"3++#+#4>;567&#";5F3-)F6- ))*H 3 [P [< ! 4/!  (E-$ ||0" @)>O9C)2< :50,(+32632&#"3++#+#4>;567&#"35>3#A7+-R 0C-)4  [P \< ! 4P*5 8/?"/=-$ ||0" @$#>O9Q <.751*(+#&#"3++#+#4>;54326327&#"35< 6/?3  [P \< !3.(>TB 4P[ |CI-$ ||0" @)a#>O9 {0&(+$#"&54732654'&'7+##4>;54>33!)Z^+,(/ ,WP< (=< %*4 :T:c'):7E .$  ) ?" "X^?/ )+sX#"(+#"&'632#".54732>54.#"!sl Lhzn&2 7)967-,2-'}Mt6$1L&56 ;F(+547>323#!&546;5""^ KG[0% P(+654767>54#"&546323#!9$ /%3h:G:5/ ##;%*$&#*44/Q4 8C*%(+$#"'&5473254'&#.5432654#"&547632$dMG *.F,, ./) (mx0/KJ %( &    #Y80h(+$+#"'5#&547>7>323&37h:J"0/0 O( B%6%rS'!F(+547>323#!&546;5""^ KG[Q% !P(+54767>54#"&546323#!9$ /%3h:G:5/ #2#;%*$&#*44/Q4 8C*%(+#"'&5473254'&#.5432654#"&547632$dMG *.F,, ./) (mx0/KJ %( &    #Y80h(++#"'5#&547>7>323&37h:J"0/0 O( B%6%rS'J#)+8$(+3267#5.5467.54675463.#"27=+)"H=+/6KF8,"KA/6$78()/= ?4% .7&!BiMI9I0*?U Bk 5!%6hf>GD?8(+#3267#"&54632754>3>73267#".=&#"765t7  I )G+QJO]9L{/'9 %$3:',:t//!##qC@1* ./{,,""?:040I /! (+3267632#"&'47U   ,>=6JA%!&!428)*E`D1K[_< ee8/M $";" o !$!&& (gEi-(r- +]mX| px _Xg _%r 1Sn#$gY ~ j!!i!!!j!jk!l!? gJ|U-  !X  I[W:F 4" WDl]1o/A`F8GE----i5p]SSSSSS$YYYY jjjjjjggggUm!USSSE$E$ii-Y-Y-Y-Yr~ r~ !o!i!+ +>!E!>j!j!j!j!jj%*m!mmX?X?X?|  | N ggggpUpx - x - x -  X?|  S$K3--o-- 3-PX- B9- --w-v--3--Mk------]E| w;-r?-R- -r-XV-~St a!*Y/@**i***j{*k!$;T |*t#:*Q**d*' *pYYs*%?!"!*ni**T {*3-*-}**pJpUdd_1} !)F+s"&L ##   sM  R] I `k]|`k]|Xl1 8|NJvbT4,XL v p  B ~ > v  *  B >h8~Nz> \<Rp2~66zPdR B v \ F !.!d!!"#0#$d$$$%`%%&&&''R''''( (r()),)V))***++.+^++,L,,,--..//00:0v00011x22,2X23 3:3|344>4j4455F5p556"6z67$7T7788f889 9T99: :z:;;X;;<<<=$=n===>D>j>>>??0???@@<@r@@@AABAAAABB>BCCCD4D\DDEE6F FGGFGHHIIIJJ,JRJxJKKPKLL0L\LLLM M8M~MN N6N`NNNO(OfOOOOPBPPQ$QX~XXYJYYZZJZnZZZ[:[V[[\\D\\\]D]^^:^^__h_` `\``a ahaabb>bfbbbcFcbccddRddee\efFffgJgtgggh"hDhiliij&jRjjkkhkllHllm"mmnjno&oRo~ooopp@ppqqrlrrsRssst.tttuu"ujuuuvv0v@vPvvvvwDwxwwwyyhyyz"zzzz{X{{||@|j||}}:}n}}}}}~H~~~V"/n >v ;HY} 6 K ~   "e  @ ,  R *-  o l ) \ * 4Copyright (c) 2004-2010, Jan Gerner (post@yanone.de). Copyright (c) Huerta Tipogrfica (info@huertatipografica.com.ar)Copyright (c) 2004-2010, Jan Gerner (post@yanone.de). Copyright (c) Huerta Tipogrfica (info@huertatipografica.com.ar)Yanone KaffeesatzYanone KaffeesatzBoldBold1.100;UKWN;YanoneKaffeesatz-Bold1.100;UKWN;YanoneKaffeesatz-BoldYanone Kaffeesatz BoldYanone Kaffeesatz BoldVersion 1.100;PS 001.100;hotconv 1.0.70;makeotf.lib2.5.58329 DEVELOPMENTVersion 1.100;PS 001.100;hotconv 1.0.70;makeotf.lib2.5.58329 DEVELOPMENTYanoneKaffeesatz-BoldYanoneKaffeesatz-BoldYanoneYanoneYanone (Cyrillic: Daniel Pouzeot & Huerta Tipografica)Yanone (Cyrillic: Daniel Pouzeot & Huerta Tipografica)http://yanone.dehttp://yanone.dehttp://yanone.dehttp://yanone.deSIL Open Font LicenseSIL Open Font Licensehttp://scripts.sil.org/OFLhttp://scripts.sil.org/OFL  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~CR softhyphenAmacronamacronAbreveabreveAogonekaogonekDcarondcaronDcroatEmacronemacron Edotaccent edotaccentEogonekeogonekEcaronecaron Gcommaaccent gcommaaccentImacronimacronIogonekiogonekIJij Kcommaaccent kcommaaccentLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheOmacronomacron Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacuteTcedillatcedillaTcarontcaronUmacronumacronUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongs Scommaaccent scommaaccentuni021Auni021BdotlessjfirsttonechinesecommaaccentcombGammaPiuni0400uni0401uni0402uni0403uni0404uni0405uni0406uni0407uni0408uni0409uni040Auni040Buni040Cuni040Duni040Euni040Funi0410uni0411uni0412uni0413uni0414uni0415uni0416uni0417uni0418uni0419uni041Auni041Buni041Cuni041Duni041Euni041Funi0420uni0421uni0422uni0423uni0424uni0425uni0426uni0427uni0428uni0429uni042Auni042Buni042Cuni042Duni042Euni042Funi0430uni0431uni0432uni0433uni0434uni0435uni0436uni0437uni0438uni0439uni043Auni043Buni043Cuni043Duni043Euni043Funi0440uni0441uni0442uni0443uni0444uni0445uni0446uni0447uni0448uni0449uni044Auni044Buni044Cuni044Duni044Euni044Funi0450uni0451uni0452uni0453uni0454uni0455uni0456uni0457uni0458uni0459uni045Auni045Buni045Cuni045Duni045Euni045Funi0490uni0491uni049Auni049Buni04A2uni04A3uni04B0uni04B1WgravewgraveWacutewacute Wdieresis wdieresisYgraveygrave foursuperiorEurouni2113uni2116Ohm estimated increment divisionslashbulletoperatorg.ss01f.ss02germandbls.ss05z.ss05f_ff_f_if_f_lt_z.ss05t_zfive.001one.dnomtwo.dnom three.dnom four.dnomone.numrtwo.numr three.numr four.numrsofthyphen.001 uni00A0.001 uni00B5.001ampersand.ss03ampersand.ss04 breve.cyr .ttfautohintz\z\;8;8, `f-, d P&ZE[X!#!X PPX!@Y 8PX!8YY Ead(PX! E 0PX!0Y PX f a PX` PX! ` 6PX!6``YYY+YY#PXeYY-, E %ad CPX#B#B!!Y`-,#!#! dbB #B *! C +0%QX`PaRYX#Y! @SX+!@Y#PXeY-,C+C`B-,#B# #Bab`*-, E EcEb`D`-, E +#%` E#a d PX!0PX @YY#PXeY%#aDD`-,EaD- ,` CJPX #BY CJRX #BY- , b c#a C` ` #B#- ,KTXDY$ e#x- ,KQXKSXDY!Y$e#x- , CUX CaB +YC%B %B %B# %PXC`%B #a *!#a #a *!C`%B%a *!Y CG CG`b EcEb`#DC>C`B-,ETX #B `a  BB` +m+"Y-,+-,+-,+-,+-,+-,+-,+-,+-,+-, +-,+ETX #B `a  BB` +m+"Y-,+-,+-,+-,+-,+-,+- ,+-!,+-",+-#, +-$, <`-%, ` ` C#`C%a`$*!-&,%+%*-', G EcEb`#a8# UX G EcEb`#a8!Y-(,ETX'*0"Y-),+ETX'*0"Y-*, 5`-+,EcEb+EcEb+D>#8**-,, < G EcEb`Ca8--,.<-., < G EcEb`CaCc8-/,% . G#B%IG#G#a Xb!Y#B.*-0,%%G#G#aE+e.# <8-1,%% .G#G#a #BE+ `PX @QX  &YBB# C #G#G#a#F`Cb` + a C`d#CadPXCaC`Y%ba# &#Fa8#CF%CG#G#a` Cb`# +#C`+%a%b&a %`d#%`dPX!#!Y# &#Fa8Y-2, & .G#G#a#<8-3, #B F#G+#a8-4,%%G#G#aTX. <#!%%G#G#a %%G#G#a%%I%aEc# Xb!YcEb`#.# <8#!Y-5, C .G#G#a ` `fb# <8-6,# .F%FRX ,1+!# <#B#8&+C.&+-?, G#B.,*-@, G#B.,*-A,-*-B,/*-C,E# . F#a8&+-D,#BC+-E,<+-F,<+-G,<+-H,<+-I,=+-J,=+-K,=+-L,=+-M,9+-N,9+-O,9+-P,9+-Q,;+-R,;+-S,;+-T,;+-U,>+-V,>+-W,>+-X,>+-Y,:+-Z,:+-[,:+-\,:+-],2+.&+-^,2+6+-_,2+7+-`,2+8+-a,3+.&+-b,3+6+-c,3+7+-d,3+8+-e,4+.&+-f,4+6+-g,4+7+-h,4+8+-i,5+.&+-j,5+6+-k,5+7+-l,5+8+-m,+e$Px0-KRXYc #D#pE KQKSZX4(Y`f UX%aEc#b#D * **Y( ERD *D$QX@XD&QXXDYYYYDLegacy/fonts/arial.ttf000064400001140524150212230450010711 0ustar00pDSIGqlXGDEFQDQ`GSUB[JSTFm*iLTSHsE?Vt,OS/2 2kVPCLT{>C(6VDMXPj[cmapgM.@cvt pv~0fpgmyYx4ngasp Pglyf~G&hdmx.oQt|(head |6hheam$hmtxʢs@kern7a96`loca xAmaxp  name (`+post;U\2prepRm4 Q_<'*!g: >NC3:((?c/V 33f zMono@ Q3>@FN ^ t~&h   b f< \V16/=l q}b E a> 1 3 Z.]       ^  G Q i w &; a  b f   u \')  ' '  ' ''' '' '(( ( (+$(7*(E-(S  (a (m  (y  (Typeface The Monotype Corporation plc. Data The Monotype Corporation plc/Type Solutions Inc. 1990-1992. All Rights ReservedArialRegularMonotype:Arial Regular:Version 2.98 (Microsoft)ArialVersion 2.98ArialMTArial Trademark of The Monotype Corporation plc registered in the US Pat & TM Off. and elsewhere.Monotype TypographyMonotype Type Drawing Office - Robin Nicholas, Patricia Saunders 1982Contemporary sans serif design, Arial contains more humanist characteristics than many of its predecessors and as such is more in tune with the mood of the last decades of the twentieth century. The overall treatment of curves is softer and fuller than in most industrial style sans serif faces. Terminal strokes are cut on the diagonal which helps to give the face a less mechanical appearance. Arial is an extremely versatile family of typefaces which can be used with equal success for text setting in reports, presentations, magazines etc, and for display use in newspapers, advertising and promotions.http://www.monotype.com/html/mtname/ms_arial.htmlhttp://www.monotype.com/html/mtname/ms_welcome.htmlNOTIFICATION OF LICENSE AGREEMENT This typeface is the property of Monotype Typography and its use by you is covered under the terms of a license agreement. You have obtained this typeface software either directly from Monotype or together with software distributed by one of Monotype's licensees. This software is a valuable asset of Monotype. Unless you have entered into a specific license agreement granting you additional rights, your use of this software is limited to your workstation for your own publishing use. You may not copy or distribute this software. If you have any question concerning your rights you should review the license agreement you received with the software or contact Monotype for a copy of the license agreement. Monotype can be contacted at: USA - (847) 718-0400 UK - 01144 01737 765959 http://www.monotype.comhttp://www.monotype.com/html/type/license.htmlTypeface The Monotype Corporation plc. Data The Monotype Corporation plc/Type Solutions Inc. 1990-1992. All Rights ReservedArialRegularMonotype:Arial Regular:Version 2.98 (Microsoft)ArialVersion 2.98ArialMTArial Trademark of The Monotype Corporation plc registered in the US Pat & TM Off. and elsewhere.Monotype TypographyMonotype Type Drawing Office - Robin Nicholas, Patricia Saunders 1982Contemporary sans serif design, Arial contains more humanist characteristics than many of its predecessors and as such is more in tune with the mood of the last decades of the twentieth century. The overall treatment of curves is softer and fuller than in most industrial style sans serif faces. Terminal strokes are cut on the diagonal which helps to give the face a less mechanical appearance. Arial is an extremely versatile family of typefaces which can be used with equal success for text setting in reports, presentations, magazines etc, and for display use in newspapers, advertising and promotions.http://www.monotype.com/html/mtname/ms_arial.htmlhttp://www.monotype.com/html/mtname/ms_welcome.htmlNOTIFICATION OF LICENSE AGREEMENT This typeface is the property of Monotype Typography and its use by you is covered under the terms of a license agreement. You have obtained this typeface software either directly from Monotype or together with software distributed by one of Monotype's licensees. This software is a valuable asset of Monotype. Unless you have entered into a specific license agreement granting you additional rights, your use of this software is limited to your workstation for your own publishing use. You may not copy or distribute this software. If you have any question concerning your rights you should review the license agreement you received with the software or contact Monotype for a copy of the license agreement. Monotype can be contacted at: USA - (847) 718-0400 UK - 01144 01737 765959 http://www.monotype.comhttp://www.monotype.com/html/type/license.htmlNormaloby ejnnormalStandardTypeface The Monotype Corporation plc. Data The Monotype Corporation plc/Type Solutions Inc. 1990-1992. All Rights ReservedArialRegularMonotype:Arial Regular:Version 2.98 (Microsoft)ArialVersion 2.98ArialMTArial Trademark of The Monotype Corporation plc registered in the US Pat & TM Off. and elsewhere.Monotype TypographyMonotype Type Drawing Office - Robin Nicholas, Patricia Saunders 1982Contemporary sans serif design, Arial contains more humanist characteristics than many of its predecessors and as such is more in tune with the mood of the last decades of the twentieth century. The overall treatment of curves is softer and fuller than in most industrial style sans serif faces. Terminal strokes are cut on the diagonal which helps to give the face a less mechanical appearance. Arial is an extremely versatile family of typefaces which can be used with equal success for text setting in reports, presentations, magazines etc, and for display use in newspapers, advertising and promotions.http://www.monotype.com/html/mtname/ms_arial.htmlhttp://www.monotype.com/html/mtname/ms_welcome.htmlNOTIFICATION OF LICENSE AGREEMENT This typeface is the property of Monotype Typography and its use by you is covered under the terms of a license agreement. You have obtained this typeface software either directly from Monotype or together with software distributed by one of Monotype's licensees. This software is a valuable asset of Monotype. Unless you have entered into a specific license agreement granting you additional rights, your use of this software is limited to your workstation for your own publishing use. You may not copy or distribute this software. If you have any question concerning your rights you should review the license agreement you received with the software or contact Monotype for a copy of the license agreement. Monotype can be contacted at: USA - (847) 718-0400 UK - 01144 01737 765959 http://www.monotype.comhttp://www.monotype.com/html/type/license.htmlNormalNormaaliNormalNormlNormaleStandaardNormalNormalnyNormal1KG=K9NormlneNormalNormalNavadnothngArruntaNormalNormalNormalNormal R X 688~Y #~ O\_ :Rkmq~    " & . 0 3 : < > D o  !!!!"!&!.!T!^!!"""""""")"+"H"a"e###!%%% %%%%%$%,%4%<%l%%%%%%%%%%%%%%%&<&@&B&`&c&f&k:1 6<>ADOY}b? Y #~Q^ !@`mq~   & * 0 2 9 < > D j  !!!!"!&!.!S![!!"""""""")"+"H"`"d### %%% %%%%%$%,%4%<%P%%%%%%%%%%%%%%%&:&@&B&`&c&e&j: *8>@CFVz^>/wkri+*)(|zvlhL>i3][w}ujy,ߨߖޖޢދަq_0@3$FE<9630)"ۿ۾۷ۥۯEBA$"!>c6dNNR`b^ffPPRN&($ L^bcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,  -   ./0 !"12#3$%&'()*+   4NORPQUVWXST~?Avw|qrsYZ[\]uwvyx}56  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 688~Y #~ O\_ :Rkmq~    " & . 0 3 : < > D o  !!!!"!&!.!T!^!!"""""""")"+"H"a"e###!%%% %%%%%$%,%4%<%l%%%%%%%%%%%%%%%&<&@&B&`&c&f&k:1 6<>ADOY}b? Y #~Q^ !@`mq~   & * 0 2 9 < > D j  !!!!"!&!.!S![!!"""""""")"+"H"`"d### %%% %%%%%$%,%4%<%P%%%%%%%%%%%%%%%&:&@&B&`&c&e&j: *8>@CFVz^>/wkri+*)(|zvlhL>i3][w}ujy,ߨߖޖޢދަq_0@3$FE<9630)"ۿ۾۷ۥۯEBA$"!>c6dNNR`b^ffPPRN&($ L^bcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,  -   ./0 !"12#3$%&'()*+   4NORPQUVWXST~?Avw|qrsYZ[\]uwvyx}56llllb z @ . ( T0Z4N$d 4 !*"$%'^()*+Z,-./12|57P89;~=@ABBfCFI$JL LtLMBMMNzQLS*TVXPY[]8^,_DabefhjTklpqsZuxy|~^FD2~0F|` `*j V^F\jdH*6fD&nt2PL0b¸f Ĭ~`Dz$~bBt4Ъ(dNҚ ^ӎTԒՂh֤$X؂z,\ܠޒ:tp,fL| <pDp&VpNJ v"xF>|D   p t:<|v\>^&Nv,XDnJz$V> $ @ \ x  "$'^'z''''((`())*n+D+,L,-R--.T./n0,0X002d3X33344N4445"5R555666f667767f7799:(;x=.=^===>>H?v@@BDB|BD>DlDDDFNGHH^HHHIIDItJdKKL6LvLLMNPPQQHQRrRSTT6TfTTUU6UfUUVV>VtVWXY[z]_aabzbcefBghj"l<nhoZojozpppppprrr rrststtttv$xxDxzxxyydy{|^}Vf&Z&,dTd.V*:4D4Bt~ 0Xr.d:J0VFVƆƖƦfv\lʢ˰\T ^@ּؠ$\lf.N :vV0z0r@t:x0Px(p`|pv\>2H6lT4(X    4 l  @ : j<|HF@x \*hH !&!p"z"#$B$%&'(()*+p,X--/00<012`3f4P4z4445"6667 7J7t7778&8P8z8::.;P;`;;;<=?@A BBCEFH0IKMNO0PtQQQR RJRtRRRSSFSpSSSTTBV~WY>[&\n\\\]"]r]^^t^_&_|__`:```abTeeeffBflfffgg>ghggghh:hdhhhi i6i`iiijj2jjkmnop<qzrtbtruwxz{{|r}~~~~(Xh6F$vjz0pXhpFV(82BTdzJ|VfT.&6HXfvbr>N^L´n<LǬ|hծhג׼0ZjzؤBl|ٌٜ٬ټ@jڔھ<fېۺ8b܌ܶ 4^݈ݲ0Zބޮ,V߀ߪ(R|$Nx JtLvHrDn@j<pj.t(F.H~6t.>Lh 2DVhzV 2DTfxnt  F p   @     Z  " z 6ZjX :j*Hj <vJz2BRV2b :d*f6p  @   !,!d!!!"&"V""##D##$0$d$%^&,'L(():+&-".013r4Z56789;X<>\?@AC$D`EG&(% >u&5#'eS79]9q7$5S+7Ƥc  ) R M_c  S>+. . -%&%&.. ' '9%.7.7$..+.7.7cc0 -&&22222+11%&. . ' ' 'SS.7.7>>>>9]9.7$$.+.7.7.7.79%& ) %% .>u..M'> &)))$1$$$)(*)$)* % >>17 1%$%  u..11M+%11.&1$&'( 77 77$75 11,1$*1%'7&1+9$$7 71    ,    , , ,, # #+ ,,,,,,,,,))))++++22222222##22,,,,#### +9%&%&%&%&%&%&%&%&%&%&%&%& ' ' ' ' ' ' ' '>>9$$$$$$$77ĖĖ%&>9$77777%&.    !" # $!%"&"'#($)&*&+',(-(.*/+0-1-2.3/405061738494:5;5<6=7>8?9@:A;B<C<D=E>F?G@HAIBJBKCLDMFNFOGPHQIRISJTKUMVMWNXOYPZP[Q\S]T^T_U`VaWbWcYdZe[f\g\h]i^j`k`lambncocpdqergsgthuivjwjxkymzn{n|o}p~qqstuvvwxyz{|}}~   !" # $!%"&"'#($)&*&+',(-(.*/+0-1-2.3/405061738494:5;5<6=7>8?9@:A;B<C<D=E>F?G@HAIBJBKCLDMFNFOGPHQIRISJTKUMVMWNXOYPZP[Q\S]T^T_U`VaWbWcYdZe[f\g\h]i^j`k`lambncocpdqergsgthuivjwjxkymzn{n|o}p~qrstuvvwxyz{|}}~   !" # $!%"&"'#($)&*&+',(-(.*/+0-1-2.3/405061738494:5;5<6=7>8?9@:A;B<C<D=E>F?G@HAIBJBKCLDMFNFOGPHQIRISJTKUMVMWNXOYPZP[Q\S]T^T_U`VaWbWcYdZe[f\g\h]i^j`k`lambncocpdqergsgthuivjwjxkymzn{n|o}p~qrstuvvwxyz{|}}~ɱTA"/O__o@3@3@jl2@a3@\]2@WY2@MQ2@DI2@:3@142@.B2@',2@%2 2Ap@$&2d 2A d2AJ?/?_?Ӳ792Ӳ+/2Ӳ%2Ӳ2Ӳ2Ҳ) +A0 P`p`p   0@Pв +ϲ&BAƲA /$A/?O_"dA @j@&CI2@ CI2@&:=2@ :=2 &@&2@ 2@&2@ 2@&2@ 2@&z2@ z2@&lv2@ lv2@&dj2@ dj2@&Z_2@ Z_2@&OT2@ OT2$'7Ok Aw0w@wPwwww**@+)*Re~<^+@8@@89@s&%$ 7@!I3@!E3@!AB2@!=>2A!?!!!!!@! "2@!2@"*?2@!.:2oAH/`?_"""/"?"_"""!!o!!!/!?!O!""!!@+HO7 A &A9&%8s542V&, /& 8ʸ&~&}Gke&^s@R&ZHDb@s?^<&50+*V)#U7h@,XO62,!  @+JKKSBKcKb S# QZ#BKKTB8+KR7+KP[XY8+TXCX(YYv??>9FD>9FD>9FD>9FD>9F`D>9F`D+++++++++++++++++++++++KSXY2KSXYKS \XEDEDYX>ERX>DYYKVS \X ED&EDYX ERX DYYKS \X%ED$EDYX %ERX% DYYKS \Xs$ED$$EDYX sERXs DYYKS \X%ED%%EDYXERXDYYK>S \XEDEDYXERXDYYKVS \XED/EDYXERXDYYKS \XEDEDYX ERX DYY+++++++++++++++++++++++++++++++++++++++++eB++;Yc\Ee#E`#Ee`#E`vhb cYEe#E &`bch &aeY#eDc#D ;\Ee#E &`bch &ae\#eD;#D\ETX\@eD;@;E#aDYGP47Ee#E`#Ee`#E`vhb 4PEe#E &`bch &aeP#eD4#D G7Ee#E &`bch &ae7#eDG#D7ETX7@eDG@GE#aDYKSBKPXBYC\XBY CX`!YBp>CX;!~ +Y #B #BCX-A-A +Y#B#BCX~;! +Y#B#B+tusuEiDEiDEiDsssstustu++++tu+++++sssssssssssssssssssssssss+++E@aDstK*SK?QZXE@`DYK:SK?QZX E`DYK.SK:QZXE@`DYK.SK=<;:987543210/.-,+*)('&%$#"!  ,E#F` &`&#HH-,E#F#a &a&#HH-,E#F` a F`&#HH-,E#F#a ` &a a&#HH-,E#F`@a f`&#HH-,E#F#a@` &a@a&#HH-, <<-, E# D# ZQX# D#Y QX# MD#Y QX# D#Y!!-, EhD ` EFvhE`D-, C#Ce -, C#C -,#p>#pE: -,E#DE#D-, E%EadPQXED!!Y-,Cc#b#B+-, EC`D-,CCe -, i@a ,b`+ d#da\XaY-,E+#Dz-,E+#D-,CXE+#DzEi #D QX+#Dz!zYY-,-,%F`F@aH-,KS \XYXY-, %E#DE#DEe#E %`j #B#hj`a Ry!@E TX#!?#YaDRy@ E TX#!?#YaD-,C#C -,C#C -, C#C -, C#Ce -,C#Ce -,C#Ce -,KRXED!!Y-, %#I@` c RX#%8#%e8c8!!!!!Y-,KdQXEi C`:!!!Y-,%# `#-,%# a#-,%-, ` <<-, a <<-,++**-,CC -,>**-,5-,v##p #E PXaY:/-,!! d#d@b-,!QX d#d b@/+Y`-,!QX d#dUb/+Y`-, d#d@b`#!-,&&&&Eh:-,&&&&Ehe:-,KS#KQZX E`D!!Y-,KTX E`D!!Y-,KS#KQZX8!!Y-,KTX8!!Y-,CXY-,CXY-,KTC\ZX8!!Y-,C\X %% d#dadQX%% F`H F`HY !!!!Y-,C\X %% d#dadQX%% F`H F`HY !!!!Y-,KS#KQZX:+!!Y-,KS#KQZX;+!!Y-,KS#KQZC\ZX8!!Y-, KT&KTZ C\ZX8!!Y-,KRX%%I%%Ia TX! CUX%%88Y@TX CTX%8Y CTX%%88%8YYYY!!!!-,F#F`F# F`ab# #ŠpE` PXaFY`h:-,B#Q@SZX TXC`BY$QX @TXC`B$TX C`BKKRXC`BY@TXC`BY@cTXC`BY@cTXC`BY@cTX@C`BYYYYY-,CTXKS#KQZX8!!Y!!!!Y-&iiiD|ZRRD/W~ "APoLu\7LnpX cc-\ @Wr]g!wM+Le|C]h5G!\M-x ,I?)9Io#o 2@z1UW~~FB/OV)or,11di+ &  sC_a^m8Q[h|ATkhqBBSsX2Q|  !U{{~!""#rw"+5<Yoq22 *<Qaajx *>LQ_jqx !".5BOO^eq *G]ety "&+G_u\ m6>PQ]`E3-_dM?}$x;;N&;MKSj1<ex ~ 90+ P >X!q}E +NT2N7kwdg3|)n*i9$]u MRhm}qyXgV%|2!r\/AMrLjUxiWnTgeRZgn-|{pLFF-S%F>S?("bJmH3NFpyQ hlOa+999^ssIwVXZ||@r9A99sUss<sVssUsMsasSsU99prpsZoVVfV9m97Vs9cV9XV\0V V V)999'6sYsJsPsFsK9sBsssDssH?9$s!(9/WVVhV9csJsJsJsJsJsJPsKsKsKsK99#99 ssDsDsDsDsDsssssI3skssQmL=dN9SdNdMdMs8zd1/-%DrdTs.d3ssVV9cRsSGldN/!VV9s\\sI9lG%VVVVV99999c9c9c9.k:(sV\?)(sIV!Vsrk!kk!s9msB9V\?fPfPsFkVsJVsJGVsKVsKsBsUsss9csD<V\?09$0#ss)()(h9`bUHtHbD).0HkR3OOOjrq"~~~~~~f0 0 *+kUo@:@7?@%UapVsJfPfPVsKVsKVsK9msB9msB9msBss9999999f7Vsss9csD9csDkV\?09 ssssV!VsJD9S9V!sZk""JkWF2xVVXV)9VX 3m9cV0VV a9VHbsk`Hss\\sDV`3z?W`sH`?WW2UdV\997u 1 V@VUkVcN@9cVf0 RV UWUU@UsJ[@sKZ2xxksDUsP&!K+Ek(+0UsKsK?9 @s!kJA-11~~!}3 9iV21-_(P<P<Z<n_s f(d$(ZVZ((WWH-ddddiiiV21-KJK(P<P<Zn_s f(d$(V2P_s<%QCMyFFFFHFFQF5|5.555,5555555B6555F656==ZvZ'ZvZ'2j0FF@FQ sJ]My"VVuxux-Y2jYB=656==656==656==????Z*65'Z*65'OmOm$$ss''  ii''55B6='uxux2j2jZ@@Z&0ZSAZSAFFQFFHFFFFF@0FFc?D[/Ts) grksSrj}_vlX,VsJVsJVsJVsJVsJVsJVsJVsJVsJVsJVsJVsJVsKVsKVsKVsKVsKVsKVsKVsK9c9|9csD9csD9csD9csD9csD9csD9csDc?Dc?Dc?Dc?Dc?Dss[[[[[V!V!V!VsJ99csDsssssU cZkssV UW+EU+csU9`sD,                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                                                                                                                                                                 "                  &                                                                                                                                                                  &                          *                                                                                                                                                                    *                                   0                                                                                                                                               0                                          6                                                                                           6   :                                                                                          :       @                                        #    !"                  "      "                    ####          @    !B    " "          ! !  !!!                 $!!! !!!!!"#       "! """      #!!   !#              !   $$$$         !B    %J !   & &         % % ! %%#%    %           (%%%$%%%%%&'" !       &%! &&&      '% ""#!% "%(                ##%      ))))       %J               "*T %   +! #!!*    $  ! **!#  %*!*(*  + !!!    ###!   ! !".***)*****+,'  %!!!   !! * *%! *** ####!#!#  #!#   ! !$ ,*$'#! ''!%*#"#  &"*-      %              "'"' *       ####..$$..$$!!         *T$$##  !!!!!!!$$$$$$$$$$ !' !.\# )    /!!$! %!$$!!.   & ! !!$! ""..$!!&#).$.+.  . $$$!!!    !&&&$ !!!!  !!$!! !!$%2...-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"...../0*###" )!!$$$!!   !!$$! !!!!.! .)$ .!.!.! &&&&$'$&# ! %!$!&"   !$ $(! 1.'!*!!%!$!!#"*+$)!.! &%&!# *%.1        %       ## ###### ###########!! ####%+%+################ ##.#############################   !! !! !! &&&&33''33''$$     ## ### ## ### # ##############################################################################.\''&&  $$$$$$$'''''!!''''' $!!!!!*!#$2d&,! 3!!$$!'$!)$'!'$!$!2!!  (# !!$!$'$%%22'$$)&,2!!'2/2 ! 2!!!!!'''$$$ ! $!!***'!$$!!$$!! $$'$$! $$'( 62221$##############################################$2111135.&&!&% ,!$$!!!'''$$  ! $$''$!$$$$2#! !2,' 2#2#2#! ****!'*'*& !!!!$!!)$!'$!!!*%!  $' '!+$!53+ $!!!"!.$$!)$'$!$ &!%!./(,!$3$!")()$&  -)26#    #  * #####  &&&&&&&& &&&&&&&& &&&$$ &&&&)/)/ &&&&&&&&&&&&&&&& &&2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&   $$ $$ $$ ))))77**77**''       && &&& && &&& & &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&2d+!+!** !!!!!!!!!!!!!!!!!!!!  '''''''+!+!+!+!+!$$+!+!+!+!+!!!!! '$$$$$.!$!!!&'6l)0$   7$$''$!*'$-'*$*'$!'$6##!  -' $$'$'*'!((66*'',)0!! "6$$*636 #  5$$$$$***''' $!'#$ ---*$''$$'!'$$ ''*''$!!''!!*+!#;6665' ! !!&"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'!65555!!!791))# )(! 0!!$''$$$***''  $ ''**'$!''''6'# $60*!6'6'6'#  ----$*-*,) $$$$!'$$-'#*'$!!##-(#  '* *$/'$97-"'$#$%$2!''#-'*'$'!")#($13+0#'7' $%,+,"')  1,6:% !   &# * &&&&!  &#  )))))))) ))))))))")))'' )))),2,2" )))))))))))))))) ))6)))))))))))))))))))))))))))))!  " '' '' '' ,,,,;;..;;..++   " "     )) ))) )) ))) ) ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))6l.#.$-- $$$$$$$$$$$$$$$$$$$$  *******.#.#.#.#.#''.$.$.$.$.$###$ *'''''2$'$$$)*:t, 4' " """ ;''**'#-*' /*-'-*'$*':%&#     1  )"''*'*-*    #++: :-) !)0 -4##" $ :''-:7 : &   9'''''---*** '#* &' ""000 - '** ' ' *$*' '  * * - **'$$* * ## -." $& ?:::9*"#"##)$)))))))))))))))))))))))))))))))))))))))))))))*#:9999###;=5,,&",+# 3##' **' ' ' - - - * *   ' * * - - *'#* * * * :)& ' :4-#:):):)&  #0000'-1-0, ''''#*''/*&-*'$$&%0+&" ! ! ! )- -'2*'=;2"%*'&'''6#**"&/*-*'*$%,%+'56.3&*;* !" ' "(  0!/0$*,   5/  :>(!##"##!!  (%.((((!!!#"#!!  (% !  ,,,,,,,, ,,,,,,,,%,,,)),,,,!/6/6%",,,,,,,,,,,,,,,, ,, :,,,,,,,,,,,,,,,,,,,,,,,,,,,,,$  %" ))))))!!!0000@@11@@11""""""""  ..""## %"%" # # # #,, ,,, ,, ,,, , ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:t2&2'00 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '   - - - - - - - 2&2&2&2&2&* * 2'2'2'2'2'&&&'  - * * * * * 6'""*  ''', - C2%%<- '%%%%%%%%%%'''%D--00-)40"-%704-40-)0-B+-)%%%"%%%%"9%%%%"%!/ !!'--0-040%%%%%%"%%%%%%%%%%%%%%%%%%$)11C%C40%%%%'!07%3<))'%%%)%%C--4C?%C%!!- %""%C-----444000%-")!0%-!-%''888%4%-"0"0"%%-%-%0)0-%-%%%%0%0%4%00-"))0%0%)!)!%45'%)+%"IC"C"C""B0'('((/*/////////////////////////////////////////////1(CBBBB(((DG=22$,(""21( ;((-%0"0"-%-%-%4%4%4%0%0%"-""%0%0%4%4%0-")0%0%0%0%B/-!-%C<4)B/B/B/-!%(8888-58482----)0--70,40-))-+82-'%%'"%%""'!%& %#04%%%4-:$0-"GD9'+0-,-$-->(00',7040-0)+3+2-=?5;,0D0%&$'%-%%'.%%$%"!7 C*0#"2$%%""=6%!%!CH.&$"((("((&#&% %"/+"""7""$////&&&$"(("(&&% %"/+$%'    ############222###2222222222222+222002222&#$$!!6>"6>"+'222222222222222222%C22222222222222222222222222222)+'000000&#$$&#$$&#$$!!!!77$$77$$JJ99JJ99''''''''$#$#55''((""##+'+'$($($($(22 222 222222 222222222222222222222222222222222222222222222222222222222222222222222222222222C9,9-"88-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%-%4%4%4%4%4%4%4%9,9,9,9,9,0%0%9-9-9-9-9--!-!-!-%4%0%0%0%0%0%$>-''0%%"%"-"-#-#2%4%K8**C2,**********,,,*L22662.:6&2*=6:2:62-62K11."***&****&?****&*%5$%%,22626:6******&******************(.77K)K:5)))*+%5>):C..,)*).**K22:KG*K)%%1 *&&*L22222:::666*2&.%6*1%2*,,???*:*2&6&6&*)2*2*6.62*2****6*6*:*662&--6*6*.%.%):<+*!.1)&RK&K&K&&I6,-,--5/5555555555555555555555555555555555555555555557-KJJJJ---MOE88(1-&&87!-B--2*6&6&2*2*2*:*:*:*6*6*&2&&*6*6*:*:*62&.6*6*6*6*K51%2*KC:.K5K5K51%*-????2;?:>82222.622=61:62.-11?81+!*)+&!**&&+%"*+$)'5;)*);2A)62&OL@,06212)32E-66,1=6:626-09172EF;B16L6*+(,*2"**!,4)*)*&"%>$+'<>/6'&8)**&&D=*!%)%KP4*)&--,&##--+(*)#$)&40%%%<&&##(4444***)&-,&##-+*)$)&40)#)+ ''''''''''''888'''88888888888880888668888*'((%%=F'=F'0,888888888888888888*K88888888888888888888888888888. 0,666666*'((*'((*'((%%%%>>((>>((RR??RR??,,,,,,,,)"')"';;,,--&&''" 0,0,)-)-)-)-88888 888888888888888888888888888888888888888888888888888888888888888888888888888888888888 K@1@2&??2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*2*:*:*:*:*:*:*:*@1@1@1@1@16*6*@2@2@2@2@21%1%1%2*:*6*6*6*6*6*)E2,!,!6)*&*&2&2'2'8*:*S>..J7 0..........000.T77<<73A<*7.E>,61**>=%2I227.<*<*7.7.7.A.A.A.<.<.*7+*.<.<.A.A.<7*3<.<.<.<.S;6'7.SJA3S;S;S;6'.2EEEE7AF @D>77773<77E<6A<73468E>60%.-0*%..**0)%./(-,;A-.-A7H-<7*XTG05<767-87M2<<06E-..**KC.$'.)"SY9 /-!*2 21*&&220,/-&(.*:5)))#C**&&,::::///-!*2"1*&&20/-(.*:5-&-0",,,,,,,,,,,,>>>,,,>>>>>>>>>>>>>5>>>;;>>>>/,,,))CM!+CM!+51>>>>>>>>>>>>>>>>>>.S>>>>>>>>>>>>>>>>>>>>>>>>>>>>>3"$$51;;;;;;/,,,/,,,/,,,))))DD,,DD,,[[FF[[FF00000000-%,!-%,!AA0022!!**!!,,%!$$5151-2-2-2-2>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SG6G8+EE7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.A.A.A.A.A.A.A.G6G6G6G6G6<.<.G8G8G8G8G86'6'6'7.A.<.<.<.<.<.-M80$0$<..*.*7*7+7+>.A.\E!33R=$633333333336663]==BB=8HB.=3KBH=HB=9B=[>=8)333.3343/M3334.3-A---6==B=BHB333333.333333333333333%333 18DD\3\HB33335-BL3""GR886233933\==H\W3\3--=3..3]=====HHHBBB3=.8-B3=-=366MMM3H4=.B.B.33=3=3B9B=3=3333B3B3H3BB=.99#B3B38-8-3HI53)9$<3."d\.\.\..ZB68688A:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8\[[[[888^aTEE1<7/.ED)8!Q8!!8!=3B.B.=3=3=3H4H4H3B3B3.=/.3B3C3H3H3B=.8B3B3B3B3[A=-=3\RH8[A[A[A=-37MMMM=HM#GME====8B==KBME=5)325.)33..5-)34,20BH232H=P2B=.a]O6:B=<=2>=U8BB6D=TVIQ*33(6?3323.*-L-50JL:B0/E233"/.SK3(-3-&\c?#42%/7#76/*+77 5142*,3/@;...&L//++1@@@@4442%/7&6/*+7 542,3/@;2*25!&000000000000EEE000EEEEEEEEEEEEE;EEEBBEEEE4011--KV$/KV$/;6EEEEEEEEEEEEEEEEEE3\EEEEEEEEEEEEEEEEEEEEEEEEEEEEE9&((;6BB#BBBB401140114011----LL11LL11eeNNeeNN666666662)0$2)0$II6677$$//$$00#)$((;6;627272727EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE \O/MM=3=3=3=3=3=3=3=3=3=3=3=3=3=3=3=3=3=3=3=3H3H3H3H3H3H3H3OO>O>O>O>=-=-=-=3H3B3B3B3B3B32"U>6(6(B33.3.=.=0=0E3H3dK$88YC!!':!8888888888:::8fCCHHC=NH2C8SHNCNHC>HCcBB=+8!88288782T8887!281G111!!:CCHCHNH8888882888888888888888(888#6=JJd!!7dNG7778:1GR7%%MY==:787=88dCCNd^8d!!711B8!!228!dCCCCCNNNHHH!!!!!!!!!8C2=1H8B1C8::!!!SSS8N7C2H2H287!C8C8H=HC8C8888!H8H8N8H!H!C2>>&H8H8=1=17NP:8->(A72$md2d2d22bH:<:<>BBTKB:-87:2,8822:1-89074GN787NCV6HC2jeU:@HCBC6DC\@LBJC\^OYBHeH895$:8C.88,:E78682.1R194PR?H43K688$32[Q8,171)dkE!!!!!!!!!!!!!&!!!86(3<&<;3..<<#9597.073E@111*O33..6EEEE8886(3<);3..<#997073E@6.7: $)55555555555 5KKK555KKKKKKKKKKKKK@KKKGGKKKK855511Q]'3Q]'3@;KKKKKKKKKKKKKKKKKK8dKKKKKKKKKKKKKKKKKKKKKKKKKKKK K>)++@;GG&GGGG855585558555""""1111RR55RR55nnUUnnUU::::::::6-5'6-5'OO::<<''33""''55&-'++@;@;6<6<6<6>  %@9Ou!  %9  h+]+]+<<<<<<?<<r 88)^  1^ j7q+]]]]]]??.+}<<<10]]]]]]]]]]]]]]]]]]]]]]]]]]%#"'&5467&&5463267&6654&#"326YzkcBϝ-0ReymuE_GIa##MfQcc|SrBøєXt(|[FEh?K_^D"K*5WIYeZ'&@ jq+]?991053.0|Q`=@ '33@^ +]?|G_<DZCTX@  U U @ U @UUU U@    9/9//++++?+++210CTX@  U @ U @ UU  U@ U  9/9/++/++?++210@6;;I Y Tk dzz  @  O @ s@!#4 8@ ?_o$+]+<?<c`Ҋ~K|]Ya p@    @0 s@!#4O_os O__?_o+N]q54'#"5432#"&4&#"326p|aS}P66mƏ{z˥tx|}SznLp Vk4Ĝ&8@  << 54&#"'6632531$8wsZX6i$jM:;+b:i`tNJ`loQGW@W! !!%5 3EID!F$FIGVTz)%)& *&)569C%VY[!V)VIYVee%f)vzr$!&PS@ '0 P  HCKC: : +p++M'/H$@P>$$0p?8*$+ #@ 55XW+N]M]]/]???]99910]]%#"&&5463273327654$#"3 $73#"$$'&547!2#"&'&32>54&#"AQYirW9")5Vr}bX3CTdz@ra̶EU T8|qHa@qj@K[h؁?[]a'=P "g~ir啽 ɭ*'LCfAYgUU U@Y U U U/0gh ` YVPh         @ U   @ U   p@  @  @ eRP@ P    @+]q]q]q?<?<<.++}ć.++}9999ć10K SKQZX8888Yrq]++++++#3#!!&'3XݫF"3FDZw*@G UF#V#f#s iup s  ' '* **))& U@3U U U U U UT%& U U @ U ,   UU U U U@ U]+;\+++++++]<54&&#!&sfgW=8JKFm^&CZ:TYe^3'g`1RfMIo) 8kFRy1fvӵcj U@_ U 2 cpt  *(* G VWVhk{޲(9@-(9  &J& &  Uc\+N+]MN]M??910++]]q]++r#"$54$32&&#"326=כC,;3“\m憣1nU-銼Z@/ C& @ U U U  U @ U    UU U U U@ U];\+++++++]<<+++++]?<?rs^sg0pMQOa7" ع @4    U@ U U@ U U]    @ 4 UU U@ U U U@ U]  P ` p ;Y+]q++++++++]<<]+++++<<?CTX@  /33???910@$/*(% / 0 `  P  CTX  ??99@$     ee@ (9P@ @(9_@ P0` `+]q]q+]q+?<?<.+}ć.+}K SKQZX 888888YK(SK6QZX8YY10]q]]Y!3673A}."-׀pxx)Fv@&)&)&9696IGIGXWXWCTX@3+44 DD KTT [dd ktt { ?????9]99@  < <  <@Z         A Q QQ@Q +N]MNEeD?<<(7-@, * *) **9 67:*I*] ]*j i*`0 ) ( U'@ U((((D@ U U U5@U U+,*499,IH,VY+fi+v +74/$42!_)o))/? UU@U UU@ UE' 2 )aa U%!$U$@ U$ U$ U$ U$@ U$U$ U$[@'@&& &0&&9U&ֶU&19@ #409999@AU%"/$?U U U U U U U18+++++++]q+]q+++]++++++++<+??+?9/+++++]qq999910]++++q]++q%#"&546676767654'&#"'>32#&326765ZCTX@4 @Pp  U U U U/++++??]2]210@G CCSS``    jiju p  "_o@y0@P`p    $ U"$ +@ U@UH U UI$? U U U14++++]q++++]rKS#KQZX8Yr+r??9/9/]]10]q]qY#"4632&&#"326<r鉭Zj kl‚FU@  % 4 D 55WT RSgde c`+<<Kp.$ .:5 KE FIW V g     3%%@`@ U@ UU@UU U@ UU U@B Ut$?O U U U U U U4P+N++++++]qM++++++++++]q<<??S@U]] U eko e  U@R U U'1:1AMAQ\Ramaxx P`p U@U @ ܴ U U U @ '*4  %&4@A#403$@$*4?O U U U U U U47+N++++++]+MNq++q++++M?]++?9/]*o@` , %L E , &,#9 6J FVX h .#,'>#>'L',,6!6)?,F F!E)T!T)ic!c)`,,'!#'(@ 0`p}@2 E" 3%3 %@`,@ U,@ UU@UU U@ UU U@J Ut%"$?O U U" U U U U+,t!4P++N++++++]qM++++++++++]q<<??]??<10]q]q32676'#"5463253#"&32654&#"f 2Ct}vnэze۠Ꙧ}|zxXQ%2dZ7<ݘjx*a4@ U%5E @:4  % @364  @ U@U (U U @ U  U  U @ U U @ U U U N@464p%@364 U@U U U U@U U UNGP+++++++++]q+<<]q+++++++++++++]q+?#ǹ U U @M 4%    #  # # %%%%%UU@ U U@ U U UU U U]@ %U@ U U@ U U U@ U U U]@3#%?O@U U U U UU@U U U$%x!GP++N+++++++++]qrpXdL:&N_bX'l_:xxP>}@@< 4y   $@U@ U (U U @ U  U " U @ U U @ U U @ U @364   N@464p3%UU@U U U U@U U U@364 N]q++++++++++<<<]q+]q+++++++++++++<<? k U U@s U U  GHVYgi4::5EKKE\\ R]]Rmm dmmdw  [TT [ lee l  $@ U@ U@U U U U UU U@$%40 1@I#40$ U U U U U U U U@$%4?147+]+++++++++q+]]]++++++++++??10q]qC\X@ SS bb ]Y++++7632#"32654&#"D{'v i!>b@ -=K?  ) #22Bp ::JJY[ \\jk imk  #++5:FJZ   $  @ `  @ U @ U @ U  U U U U @# U t33%?O@U U U U UU@U U UG7+N+++++++++]qr6@ +*;Ky ??K44?DDSScc` )" +95 IF Zi    3%@`@ U@ UU@UU U@ UU U@? Ut$?O$ U U" U U Ut!4P++N+++++]qM++++++++++]q<<????9910]]qq#"466325332654&#",*Uo~q!xsvui;N.C>@;/#4CSft      (" "%@364 U@U U UU@U U UNG+++++++++]q+<]r???999999ɇ}10]r]336632&#">i?[^>BB;^&qH:'G?`r?>0@{"": J D$V"e"| $, 0K,U2 \\ \ \ \ \ jj j j j j &''&$'$)6$Z Y d&d(t#t$$ (,0 '(&&( U" U# U$ U( U" U# U$ U@9Z'%  & .@", U?O_oU@ U@4@4.\l UU@U. $@42@/UU U U U U U U[$*9** U*U* U* U*2@!'*4`22?222$ U U U U @U $ U U U@ U U U"?O147+N]qM+++++++++++rN]q+++++q+M+++++++++r?+++?q9/++]qr+]qr+99910Cy@@'-#,&"  (- !#"# ) (' +++<<+<<+++++*++++++++++]q]rq]732654'&'.54676632&&#"#"&?{|x5%ƙOA8*S}Z si|j/Vi}=kreD=#%2INGy(+H{gR\R7# $3A|\ZW$*ع #&4 @A#&4  +  "" % E E`p UUU U UU@ U U Uj6f++++++++++]q<<<??<<993310]++%#"&&5#5373#32LeclM,&O@ 4 4@34+$    3%@364@U(UU@ U U@ UU@ U U@ UN@464p % @364   U @U  U U @U  U  U NGP++++++++]q+]q+]q+++++++++++<???<99910Cy@    ++**]+++!5#"&&'&53326653?|^O nQQ;HmO5s1GQS9& CTX@   $U/+33???9105"9 @ 9 4444 @ !4(!4 @ "%4"%4 @~(.4 (.4 )( & 95 HG VVYX ffii xwwyx w   ,   (& 7 O@ @4@ 4CTX@  @ U U @ U U 9/++++/??910@7 %  %  /  "@@@  @@ @" +]]]9999?<<!4@J!4)( /99 IFFI O\TTZ Plccj {t{  &)+ 94,9 @#9:  % a+ a @ U + [@ U" @`@$ Ut ~Oo Ut!|++N+]q!4++++qY]C\X޲9 ޲9 9 = 9 @ 999++++++++Y35#!5!63!(sXOdoyjw^{ 9Q|*{@MG(44 4% 4')** %  %   %:%&:*':&**_i+ph+]<<<<<??9/9910++++q>7>7633#"33#"'.&&'9Ma  1H8&V8hD W]ncA_8b,@T aMdON5Tf= KEkt-.%D6ghPQY2~@v +N]2!)d+CTXA+@ @4 dH+++Y55Y&$?@ h+)++q55f[v&&"@0 0O0/0000H+)++]q5,&(Tj(@/H+!)++]]q5&1QKU@ UoO_zH+!)d++]]qqq++5c&2,#!)+CTX A+  dH++]Y55"&8@  A!)++55J&D@/;?;;H+;")++q5J&DC@999 H+9")++]5J&D6@&: :0:p::::::::@.24:=A>")+++]qr5J&D'@<@ Up<<<<bH+?")++]+55J&D8@I@ UI@ UI@4I@ 4IIIдH+G")++]++++5J&D@AAAh+A")++q55Po>&F7@U/0 H+)++]]qr+5K&H@!!! H+!")++]5K&HC&@ 4p H+")++]q+5K&H'@ @;5 @-24  # A$")++r++5K&H#@"@ U"" dH+%")++]+55.&2@ U4@"%4/ZH+")++]+++5#&C(@@4@"%4 H+")++]++5h&@  A ")++5 :&@ UH+ ")+++55&Q5&")+CTX# A+("$4O((H++]+Y5D'&R@H+")++]5D'&RC&@ 4pH+")++]q+5D'&R @@.24A ")++r+5D'&R*@ @U@ UnH+!")++++55D'&R0@/+?+++O++/+?++H+)")++]]]q5&X!@@4O p+]<<<<<<<<?<<<:+N]M<]]{?{@{AsIsJ->?@AHIJ)) )$)"1HC EB?9% ":/'<HCB?:9/'% 6'@-' <>+^2><)O++L"^><8E)OKq+N]MN]M??999910]]732654'&%.5467&&54632&&#"#"&6654'&'&'zifs$>uJxiG:ȥiY\q$87GCI*pPOdm3JI45CQE..FihF3+K[gL`DsAz`c<4,D`-54&#"YЂ$\d-@͠~/2d7Ll ['(g m[kpr3l?  AY6MiƇjH]HhF8(>r99<'PX">_!6@@6,-&')-)0+1 +++ e01/d/t//г&-4/b@.,..,-,+*).012601(3-,+*/))5b77 !@?b@!""".//6O  o   b b;b&T/b.@756!6b J bBb Az+NMNM<<<<??]q<<<]<<9/9/999.++q}910Cy@J<>%$%=&%&%&& %&%>#;,!! !!<%?, !! !!++++++++++++++++++++]q]2#"$54$"32$54$!2#'&'&##32654&&##jjӪ,,Li+1GcHU4$EMrS(G`hk}Ѥէ+/,-p?Y0q&D8$9:3@  036p !$/0..`+8b@O$$o$$$$2b@ ++++b b/b. b!5b'd b<b ;z+NMNM??]]q]10Cy@T37%*)&%&%&& %&%3*57%5!! !!4(26&8 !! !!+++++++++++++++++++++]2#"$54$"32$54$#"&546632&&#"326jjӪ,,T{Ëdw wuOspZhk}Ѥէ+/$}ʄcmJOh@] 95JF  i b@  b;;b b@ 0`ٹ.+]<<<<?<<<<<<999910]]!5!!!33##e|{yyJ/uTJOeȳ44@&4oooOP`S٧+NM?]<10]]]]+++3ޅ=nH@#<<<_o$p+N]M<<<<?<991053353=N@         ?  %  0   %   U >q+<<<<<<9/9/?TX8'l@Owvx % &D dsy%{&%& Uk:%E/)6#  =) &i(h+??9910]]]]]'6632#"&5476%.#"3276F^L{/-ڎ(`A>v}fDKUur@"#l vy+<<?<IlUk{`0H8 F0#A<"Yw=>w=2(,&):N9- C/| |@)ip) ih+]]??10]2#"&546"32654&uQceOPdeȰįȅr~uuzt*Y@%99EJJF%YVif|zt%&;. H@) +;::+';'''':*:)((::'(@ U( U/Ox@ & J(U U U@ Uj, (@((x)$&J)U)U) U)@ U`)) ))++]q++++]]++++<]++<<?<<<<]q]q?10Cy@ # "%& %&!$ #  ++++++++q]%&'&54$3 %!567>54&#"!5l9W^/PlW5`lP,Hd3cɏiC?`I]:?(&=gxHD>5<J{@5=9=HL)O9Z)^9z(@0"4%LCB%DH[VVS%iged#wt&$ U=U=@. U====F6....2: :'' F 2}@ 6%3=%.7@. U.@ U. U. U..?...ĵ+5$3+U+ U+޴ U+@ U+0+@+++@; %"C$  U " U  U  U  U  U  ? O  K47+N]q++++++M]++++M]q++++?<]?<9/]9/]+++10]]#"&'#"&5466767654&#"'>326632!3267!&&#"326762Mh{c–fiWx9iăf;(@sbCXgHz~Om,;jesE`ff`VN~e*MUuN2@FI}*Wvk"'"/LGarU4dg!+@", %FTdU(!"FI LLEK&Zfdf""+,+/"; =8&T-X \^&" !"!!|y!y"#j!i#z zlfm&u;"EJ&-,"9M CIF'z"v#"d mmh"""#@7 !}!#"(-(,  % [[% ($U U U U U@UU-4-@5 4---- ----$U U U U U@U,3+N]q++++++MN]q++]+++++++M??999999999.+}<<<<<<<<10C\X޲ 9!޶9""9#@ 9"%9@9++++++Y]]]]qq]]]]]]]]]]]]qqC\X@)"#"#$ ""-]q]qY]q+q]7#"''7&'&532&#"32654'&c`k?zi^l;(&R[d4?Nb FVFdԍqPGDDm- *Fʖe?L9*SO&"@7|k|`k]]KRLK:D ')"@!<^l $$<"^"^ v#+]<]?<71$7wrYY6&"nM:;+b:jatOJ`ll& vCTX@ <:<:/?/10@#< :8 8:<<  !++]<?/10KSX <F&7igq3x2*-@c$ #+$""%+-// "%!"%&!!5656EFEFVVeevv )-  )-$ #' p    : + p  '>$ >$##> > i/+>>>>i.+<<<<<<?]]10]]]]56323267#"&&#"56323267#"&&#"3j<{EE#A6@R .5@m&W DD#K&K*D-K2D4WWS#_&_*S-gh`$l&l*c-\2T4R[23#;&:*3->224 (% 53/+ 3 %}@& /@(@@3 U U U?IJ0@UUִ Uд Uִ UUU U˴ U U 4@@!$U U U U U U( U U?O647+N]q++++++++M+q++++++++++]q+++?<]?<9/]99999910]]]]]%#"46326632!3267#"&32654&#"!&&#"Lzu3@|c +볆G\WM-K vxcd sX]nӦooiĺa~bo[@5 z+N]/M105!sʑ[@ 5 z+<]</105!ʑSZ @\~~llZZ      < < P@/o8< <@4u8<<q+N] @4 u<8' jq+]<<+<<?<?<9910qqqqqqqqqqrq]53'667353'667W+[,65+[,65ѥ;Q)G_Sѥ;Q)G_SQ ~@6{ Zl  <8oP@8'<  y+N]º(z-Q0X[RM`Eb:xLl*1FXQe\H,L9@ 9@uu< 0jKZ+]/10]++#3# ;9\H!4@uup+]<<<<<<<<<<<<<<<</<<<<<<<MHDFJBM7!+5#2-)+/'2 T;QN?QGEILAI9 63$6,*.1&.  +++++++++++++++++++++++++++++++++]34632#"&7327654'&#"4632#"&7327654'&#"4632#"&7327654'&#"@YaOA; +,"<>!-BOA; +-";>!-OA; +,"<>!-6 ǵǺŘj-/.>ǵƹŗk-=>/.>Y,&$@j@oA!)d++r5,&(kj*@ @ 4 / _  H+!)++]q+5Y,&$?j!@ 4 H+!)d+++5&(lG@ U@4@ 4@4H+!)++]q++++55,&(Cj(@ o  @  H+ !)++]qq5,&,j+4@"%4/ZH+!)++]++5Y,&,j2 !)+CTX A+@@344@4aH++++Y55&,@ H+ !)++556,&,Cj9!)+CTX-A+@@4@"%4 H++]++Y5c,&2j$@4pH+!)++q+5c,&2j@ !A"!)++5c,&2Cj$@ 4PH+!)++]+5",&8j+@@ 4O/H+!)++]qq+5",&8j'!)+CTX A+5H'+Y",&8Cj#@@4H+!)++]q+5z&j @U% U U U U@ U U+++++++]<<+??<1033ƴ&I@d<=@ 4dd<h+NM+?<]<<<10#3#XqT@@ :??@  v Mv!z++NEeD?M910Cy@, %&22  222 2+++++<<+++]&763232673#"'&#":9Y>k;# "mT?gC"h>>6#4rr8$/_#@45h+N/M+105!p˔.} KU @ @@ A+]NM?<,+?:IjkLMjkO/@@--@?k[A : OZ@ : vM>Wy+? @^&>k U4Ks u:A@!<r<rp+NM]?<<M[4z-cxYKDT.w"xeV(H@d<=@ 4dd<z+NM+/<]<<<1073#3gn+ @     @$    T  e] U U U U U U  ;\+]++++++<<<<]?9/9/?<<10573!!Lf5{|ҭ @H p       E  @N 6 U U @U  U U  U U U @ U  N GP+]+++++++++]<<<<?9/9/?<10]5737#>nnss)\&&6(d@ 11H+4!)++]5?&V@ p11H+5")++q5)&&=d@ A!)++5(&])")d+CTXA+A+Y5QYOe~@# v  !++N]</l*Q {j=@ u  a '? a@:) )'h+NM<?]999CTX99Y10q]q676$7654&#"'6632!)? %FDBA;-S#99V)+0>/CoivUTK8s=$y!+v@##M'0a)@ '_o?a@) ')&)'),h+NM?]r]9/99910732654&#"#7654&#"'6632#"&! +;GVHW QK<;8?)}xGCYT<N72<n<+%4,:jTkP7VeD]ok *@/,3!?&D!T!(((@!(),+   @ :/?Ma(a)a@ **' 'c@)":**)i, )D+Wh+<<<<?<<]?<<<999999.+}ıCTX&*)99Y10]]q356673676$7654&#"'6632!M6fz>/l=*> %EEBA;-T#9 *Q {j=89W)+0=/BpivUTK8t=#yk @   )+::Vf fv@   @  :d@-' 5_5M  5 h+N]M<<<]<]<?<<<<<<<</lzhh9 *Q {j={l!-8;3/=@'=<% 23:% 1:20M @  0 @/?_o_oa a+@35449677/;9d0/.32@ 88.. 0@;1108:5363.)8N=)"" )0(((@ )")<|f+NM]<<?<<<<<<<<&V:2 )+CTX23..A+@ 3333343.&D@ 8'H'8 )++Z&&'d-@@U@U@ UH+!!)+++++5G (4@06'SS'bb'56-!: I CEI(Z j - # & C@4@@&H H @1#3   %U@UU U UU@ U U@> U@`t$ U U U U" U U?O)4+N]++++++M]+++++++++<<<<<&H='@`PH+ )++]]]5&&(3d*@ @ 4 / _  H+!)++]q+5K&H@  H'!")++*,&/Rj@  pH' !)++B&Od[<!)+CTXA+4@ "%4/ZH++]++Y5*  Q@3ee Q Ue    $U U @ U U @ U  ;\+N]+++++eclM,5F{"E*t0&&7d5 !)+CTX A+@ @%'4@ 4H++++Y5# "@*ol```ppr   !-@$@3 @@$+!  "0%EUU UUU U@ U#6f+N]+++++++M<<<??<<NM?<99993310]]53'667#"&&5#5373#32EHN-31LeclM,"+&8>;@:<4}?r+55CTX A+55h'+Y&X@ A"")++55",&8j3!)+CTX A+@ `UH++]]Y55&X1 ")+CTX A+4dH+++Y54),&=j(@@ 4YH+!)+++]]5(&]OiH+")d++]5)&=0j  H+ !)++]5(&].@@ U/H+")d++]q+58@  $UU U UUU U U;+N++++++++ @P "7GVVv u IFFI[TT[h h gy  %*5:o`  UU Uk@ U U@G UB7"@ U  U U  U % U  U? O  4!]++++++<q]++++++33????9]10qr]q]3#&'!"326%"32654&F;F;+S}D|&~d^,!eg#ĿH,@;X Z Uh h xEJJUZ '(78E3993[  ko c `coo`~ __ P PP_ZP+k j @3{0@[k@@!@ U!@ U@U U UU U@J$%40 1!@ U U U U U U U U?1 ]++++++++]]++++++++3/3/]99]r9]??3?3910q]]]r]]]q!!#"57&'32654&#"!dվ]Rzf@ Aʪܼ˼bc>$@7&_&}}&&!96"uy!!  @ 4? @ p  #@+  @ @"4  `&@@U U UO4%]+++]2/q3/+339/9??9/q3/]33/+3910]q]&#"327&#"327#"&547&54632={kXQxt# opM{h]^6F]nEGam~LSwD>$@=6699EEIISXTRT^ejdddm   $U UUUմ U U@! UP`p0@P`p @2 ?$ @$%4 U  U U  U U @U U  U U ?  1]++++++++++q]]q+++++++???9310]!#"32"32654&߅#K_&|}±.&@ P ` p O  p%U U U U@ UU U@- U p@p J/^]^rq]++++++++]]?L<;Ol#67!5!&&'VcM^g;L<;l%-0lea^vSh;5367#&&w^`elɐ/.%L;g^McVOn#67!#&&'56673!&'3^PE}}EP^^PE}}EP-++-,Ug3&'67#&&'5566-,,-+^PE~~DO^^OD~~EPg3&'67#&&'5566!!-,,-+3^PE~~DO^^OD~~EPbjk3!!jded#!F@  #!! "y+NM<32#4'.#"% D|wנE  5o\\s.mE}b]4t?rvLPh6r: j@< %?   %0%   WZ+N<<<<<<<<<</ON?2abu u??e!00!"//"!00!"//$$_dd #/! ! 4&#"326%4&#"3263267'#"'vu/"!00!"//"!00!"/2ba2?NOu u"//"!00!"//"!00_dd_$!FU/;3!!#&&''&&'!5!66776674#"32LfX"4I&P|9bkLpP3BD P BE0$e\$,-U?G5_J`]E2H9 Q>=3TjEjT9F=,-I '!!#!5!"&&546632"3254&&5;4gv~~n;I;yzzyoT&#"&&5432'"3254&&$93NXh v~~TfEK25yzzy:"#"&'!726'#"&54766766!lJ\N1K-TZ!-0IClE`a]c %%__[I;R6S73!!7676654'#"&54632&&5463267632#"&'&'J6Qg=[t^"#"3o|rvt3FG)rmYb(tx=3%X=)?&&'&'&&5463267632bsy.)mnQ=&!R>M[wh[|#N>CU.w=vgP~FfW@U6 UOp ~ E  E %U@U U U UU U@" U N]qr++++++++<<<M[uhet"N>CU.w&Q! A/+5]@^;4 ?A il{uru $$/q  /& $U Դ U U U @ U  V  UU U UU U U]+++++++<]+++++/]/?<@J$4Dr    %U@ U U U@ UU U@ U@364pE%@U U UU@U U U@364 N 9]q++++++++<<<]q+]q++++++++<<9?&U%/\&&6Ld@ 36A2!)++5?&V@ 36A2")++50@&  0  99   /@ UU U U U U@ U s+]+++++++<]<]<<<<??<<9/<<10]!5!!5!!!!#JHu #&4@[#&4/ + + 4 U 4 U   3  "" %EU@U U UUU@ U U@ UNG +]q+++++++++<<<<3/q3333++99??<<9/<<10]++#53#5373#3#327#"&&5%@ /I=jslU>Hu"&8d@ !A!)++5&X @@ST4%A")+++q5"&8d%!)+CTX A+H++Y5_&X@  A)++5"&8d@  A!)++5&X(")+CTX  A+ رH++Y5V""3XX"$@*4:;4!6"JJF!F"XV!f"v" " 4]  @  ]@ &U@ U U U@ U  P`p]$& UU U U U U UU 4]#;++]++++++++]]q+++++9/]q3//]?M[vebyIt۴NG*GT.w=xeFqPO^NW&%r "4'@ 4 4@@4 &5Dw*+ E #%   @pE %"!#0@%$@364'@U$(U$U$@ U$ U$ U$@ U$U$@ U$ U$@ U$$$N'@464''p'''''%U@U U U@U U U@364 N&GP+]q++++++++]q+]q++++++++++++<99/2//]<??L\uhbw|~;nS[0N>CU.wASPSS/SpSSS AAAA/qr55/]q5+55+5@,PDH+QRPSKO4S@``4S@884S`SSSSSS8?4S@ ,.4S)/4S'(4S#$4S"4S@4S@4S4S@+++++++++qr+++10+5Y,&j@ A!)++5D&X@ N%H'N")++S,&j@ 42H+4!)++5d&6@ ,H'/")++Y&$@<<+NM/<<1053Yv,&:Cj A!)++5&ZChA")++5v,&:j@ H+!)++5&Zh@ H+")++5v&:l+!)+CTX A+H++Y55&Z@ H+")++55F,&<CMj@ H'!)++!Q&\C@ UH+")+++5[ GP@ < i ? +N]J)yzk !-8@/:{wB\4@';4?%6a@ %/%?%%%+a@    }0a@  ")'.) @()'3)::9  )F9Wh+<<<99NM?<<<<99/]9/9/.+++}10]356673&54632#"&54732654&#"32654&#"M6fz7.l}F33IH67@GPVDFL9 *Q {m=/sPokVs-)j~d244-.7:E5:DE""6BMQ@/Oi&f*{&w*&*B\4@';4?!--:##Ka@ :/:?:::2@a(2a@ ! 0da!@/?_o_oa}Ea@2  7)%'C)5@/=)+'H)/OON)" )0(@' d)")N|h+NMr]9NM9?<l ` ٹ+9<</<<1053'67J^6]un&T(kk[K@ M   1@:M/8)j W+NM<]]10632#"'73254#"#|?M ,+2nHMt uLCO Z@8 @ P `  u@,/4_P/r]+q3/]3/?]q<<103#%3#%3#[u<֭[UUU U@e U U U/0gh ` YVPh         @ U   @ U   p@ RR@4@ 4T  @ eRP@ P    @ +]q]q]qr++?@'O_  b V b V ??9/]q10!!!!!!#^gyY&&c2" @4 U@ U U]   UU U U@ U U 4] @ U  P ` p ;Y+]q++]++++++]+++???10+3!#!~F 3 @< 66   &- 7:? I ij xx   U@ U  @6U U       1  ]<<<9??<<9.+++}ć.+++}10]qrq]!!!55y <!/07F< I;0 @J@O I@@`p  0@ 4 4## 44 ]  @ U   U U @ U 0 @ @ ` p  ]@ 4@ U UU U U ]]++++++]q]q+++9/+<<????9/<<10]++q]33663#$uO sb ;5 aw@[XYXW [TXXzu \P od v % KKFE   * ; --  ::@ U U/Ox@ & JU@ U U@ UU U@ Uj_ @x&JUU U UUU U@ U` ]q++++++++]]]+++++++<]++<<?<<<<<qui>)@Wrp %5F   %@ U U @ U  U  U @ U U @ U U @ Up  N%@U U U@U U U@364 N 9]q+++++++<<<]++++++++++<<9?9V=&L@ N% U U@ U U EG +]++++<<??<1033&& Z U U @> UD? ZYii   (8XYJ@  @R U%U U%  e     Pp % U @U  U  U U U U @364   N ]q++++++++</]9q?<RiE>  @dk jj`_bjl blP__ P_9579IFFIVWX Y h x    $@ $%4UU@ U0` 1@ #40 %@ U U@ U U@364 N]q+++++q+]]]++++3/???910]]]]]q32#"'"32654&s#i."}@VQ>"@K')69 FJ   & 7 G v  ! $ U U U U U @$%40    1$$@:#40$$$U U U UU U@$%4?1#]+++++++q+]]]++++++3/39/3??/10]]]&#"#"'732654&'&&54!2*pp‹|FަCU,:+`nO~Y${#t3%AsK S;69/d&@9DDTSP[cjs{ p  % @U U U @ U U U U @ U p  N%U@ U U@ U U@364 N]q++++++<<]++++++++<<?53#.5z05Mδȋ.&gYb ʗDW&$U@I&( &9H@&S\]Sdknavzuz$$&&& HH   00@#  P  0@ U #@ U@ U UU U@)$%4 0 0 @`1&&@ #40&&@#@ U#U#@U# U# U#@$%4#?##1%]++++++q+]]]rq++++++9/+qr99/9/????9/]910r]3326653326543#"'#"5c@p%%q@b۪ab&d~7{cհI"&( ")+CTX A+H++Y55&#@p A")++]54D'&R@H+")++]5&# ")+W&&@ %' A%")++5&(^  !)+2@*fv" ]J  J& д U U U U @ U 7 UUִ U U U U Uִ UUT+++++++++<+++++9/???<9/9910Cy@  66 66++++]!!632#"'732654&#"#!2hLR8c˲!%^X U,&=j@ H+!)++5dv@+;]o )) ) 5;5 ;GKE KVT V Tj wyx   `p T   &&b/ -& @U U  c\+]++]]q9/??9/9/9/]10]q]!3 ! 4$32!"Y ^Y 836S Kt1GJ23\6,5&,( !)+CTX A+H++Y557a- )&=@b&&  H@  U$U U U@ U U@UU!& U@$%40 1( @ U U:@J UU-'++++]]++9/]++++++++<???9/10Cy@,$&&%%#&, !6$!6, 6"%6+++++++++++!2#!!#"'73265!26654&&#!^bɾ+j@Z!0"BBjzW]ohM wc)w`[{&D@/+     U U U U@ U U@"UU& U U U U U U@$%40 1!  UU U U U UUU] ++++++++<]]+++++++9/++++++++<<?32"'&#"#&&##"#67&&'&'&#5632kS=OW_  ]-.;@^Y.by`b .OdE?--YN e`P?Ti~iwQ--s&(Rer' k((OwdN&@SN9Fe!uKZt( @P`p ?O_%0@P% H %HH@% & U U@UK&" U"@ U ""\(&b&1']++]+++9/??9/9/]9/]9]910Cy@#$6$66#6++++q]]q732654&##526654&#"'!2# N]mo32"'&#"#&&##…lT=OXp  ]-.;JfG.el~gĐwQ--a'{R  b H@  U@U& U U U@ U UU] U@U U U@ U U:@ J  U U U b+++++++++]++++++++???10Cy@ & ,,+++!#!#"'73265 +j@Z!0"BBF wc0"+c2! @ 4 U@ U U U@ U9    UU U@ U U U @4]  P ` p ]q+]++++++]+++++??<10+!#!#F 3fv&07 @fh@ U@ U ] J H@   \\9/]9999??<<<9.++}ć.++}ć10r]r]33#"'53267 g{KmNWGg>~ք#-[R@I !!O!p!!!%++%{ {0 o   ?p &U U@ U?oó &U@ U U0`p@   @   @ U U @ U  O  /]r+++D[D(@E9 5%9'I F%H'YYU[Q%\' = & #3  & $*@ U*@ U@U U U@ U U UU@$%40 1*@C#40***#$ U U U U U UU@$%4?1)]++++++++]q+]]++++++++++???9910q]#"6632#"&!264&#"326 IsߢGDrp(2kTVeeO$ P໹&#2@6%/%F#+##++ $ UUU$ U U U @ U U @$%40    1%%@#40%%% U U U@ U UUE$++++++<q+]]]++++++]+++??9/9910Cy@3!%% & !   " <+++<++++++++]!2#!326654&##32674&&##k??Kc Ļ!sVDwrBju&3_Lq&^gI3TBGW3W&d@ + %U@U U UU@ U U UE]++++++++<??10!!#cQ&ol& ;@ +  + @ U U U U@ U@    %@ UU+@UUU@ U U@ U U Uڴ UU@$U?ON+ U @U    <]qr++rq]+++++++++++9/]q++9/]]+++++?<H`&8@9' %%:/:?:`:p:: ::0:O:::::4;!!!533U3@JU3+)'))'U+% !!%"#""#53') %# "7 @?.3 0 H"!! %'5)3/#! " @  (@ %8 UU U U U@ U(@O//"""P"""p""""39]qrq]q++++++<<]qq9999?<<<=eI%W7 QD2b>& @] (U ;P`p    @HH H ! $!$U@$%40 1(@ U@[']q+]]++9/9??9/]q9/]9/q]910Cy@*$#&!$! "%<+++++++]]q5>54&#"'!2# 732654&&#"rrSJaM=P2~PPл:[[yLVq P\& R@Vg{@ U U@9 U U+ % @U @ U$UU@ U U UUU U@ U@364N @464 p  % U @ U  U @ U  U @364   N ]q++++++]q+]q++++++++++++CTX9999Y?@K>??DD /,//L^z KK ?{{@ U%   @* H    I %U@U U U U UUU@364 N]q+++++++++<]]99?<33'"#&&##VEC5BV_$2G+)DGtp;X=&5B~PmhP!Ic?#&F@+3  %@ U@ U(U@ U U@ U U U U@ UUU@364N@464@`p%U@UU U U U U U@UO_op | +9/]+++++++++]q+q+++++++++++++??10Cy@ &% ++++!#!#"'532665D#lf?RO80&vX2&  U@v U   FJEJ VZ      xx     @ U + U@' U+      %@ UU U U@! UU UN? %@ U U U@ U N ]++++<]]+++++++<9?<<R& @+ % @ U@U UU@ U U& U U@ UUU@364N @464  p  %UU@U U U UUU@364 N]q+++++++++]q+]q++++++++++++?SP>F&&@/ 0 @ _ + WW%@ U U U U U U@& UUPP`/]qr++++++++??<10]!!#!&_&o!Q&\KiJ)5D@bX  77[\ USY Y"Y&U,V.U4jj edj n"n&h(f,e.f4yvy vv #0'33!3-  U% U@ U$$ U U UU@$$%40 17@7P7`7777 707@777@4#4077*$ U# U UUU@$%4?16]++++++q+]]]]+++++9/++<+<???l&&aTYEl& @+  + $ U U U@ UU@7$%40 1?_ %@ U U U UUU@364 N]q+++++++<qr]]]++++++??9/10Cy@  ++++332#!732654&##>l&aTYEl+>S}@9@ UU U@UU7N+++++5>}@^ 4GZ_ PSS_[no eccon"+  $U U@ U U@ U0$ U U U U U @$%40    1!%UU@U U U U UUU@364 N ]q++++++++++<]]++++++9/]q+++++<????9/10]q336632#"'##"32654&yڴZ|{&D*˷̽& @& 4 D [T y $   U U@*U%    ++   %@ UU@ U U U U U@ UU"UN ($ U+++++++++++<9?<@:EUUk l ls s { tu_o "0@` @H 4+  $$7$U U U U U U@UU@$%4?14 +N]+++++++++MV<L :&@ UH+ ")+++55Q:M&" @$+"" ++ +  % @ U U U U ٴ U U @U@ `   $ U U@ UU@$%40 1$$@#40$$ %U U@" U U U UO_#]++++++q+]]]+++++9/]q+++++++<??<?9/10]32#!!#"'5326532654&##D> 'ohoG(?([k&a﯐G NnSZFk9&@(+ +  %U U@ U U@UU/ $ U UU@$%40 1@ #40 % @U  U  U U U U @364   N]q+++++++<q+]]]++++9/]++++++<99<?fkl)&FgOTBe@  %5Fz@2+4    %@ U@U (U U @ U  U  U @ U U U @364   N@464p%U@U U U UU@364 N]q+++++++<<<]q+]q+++++++++++/]/?@ + + U U U@U_o% @ U @ U U @ U U & U U U @ U U U @364   N @464 p  %UU@U U U UU@364 N ]q++++++++]q+]q++++++++++++9/]++++?<??<10!#!3!3.&nP@.U U U UU  UU U UU U U9+++++++9/+++++??/103!# @#+ %U U U UU@U  %U@U U U UUUE+++++++9/]++++++???103!#w0&o&A[@ /105!Aʑ@ !%:@'(/'  U@% U7fu8* f@(*M#"5$%u UU U@ U $%^ b@^ U>' UU U U&++++<<+9/++++<99?<<1_u=3oZ\%)gvۍG2)1v@,Tc   U U@ UU̴ 4 2/+3/++++2/?3//?<10]%3!5!4&&#"'63  BAjX1@V#/8 4K Y j {  #      @ @ U U/]++2}/]323/833/99?3??<<<|9/]399.+}ć.+}10]#"#76634&&#"'632bI{R;TKIVG=0Ca4o[VY6 f-%Q@   U U@U U̴ 0]]++++?1@ )6ZZij @K   U    U?_ @ U U U +++3/]+3/9?<<?B @*/7GSYY S S\\S  &@ U U@ U U@ U U U U UU@ & U@ U U U U UU+++++++++++++++++??10]432#"732654&#"Zؔpј6u1%@5 yyu u ;i@6U  U 3/]3/9/+3339/?<;+\%qHHn{mNL7YI(1h+ ; I @  / @ U UݴUU++++3/]3/?3??1088]63 #4&&#"(B>k \d*%!@F+/#15==1HHY\Zhjju r tvy! !@UU!U ! Ƶ# !"229/+++?<2 lg&&&&=3oZ\%)mpۜ>%%%%2)1& @ `A)++]51&F(@@$$ $P$$$$$A)++]q5-%&N @  A)++]5@1& @@pA)++]5%W ӷ  @U U@CD4@=5O@ /@4/+qqr++++??/10#2#"&5466š%&5&%%q&&+)%;%"@ $$Pb@ ' U  @+ UUU@4O@4̳$ /]+/]q++++3/+9/??/]10]"#54'&547!5!2#"&&546; %&%0TfjJ1q&&&#1@;&@ (!A)++5%f @  @"U U( U@CD4@=5O@ /  @4 /+qqr+++++?3/]9/10#2#"&5466š51#5&%%+)#1,(&(h1&@ A)++5PV7&("@ U"`"p"" A)++]+5<F&97!U! U!!@ 4!A)+++]++5P>1&?@ %A)++5<<1&b1 U 4A)++]++5Z>B (@!/*\\S 7GSYY S S"@ / @&O&_&&&&&&@ U U@ U U@ U U U U UU@ *& U@ U U U U UU)+++++++++++++++++9/]q??9/]qr10]]432#"732654&#"2#"&&546Zؔpј#%&%06u1Y&&&#1nh1(@ "4 4IK[)8=@!!l )  (4UӶ%U%@ U%@#&4%@4%%  U@ UU#U/@*  U U U )+++]++++9/+++++?3/?9/3/1088]]++327#"63 #4&&#"2#"&&5466&\-6D?~b %%&'z 5uN%%&%s7 -@MKz//==!@((l   #4>%+@ U+U+@!#4+@4++&UU U / @U U  U .+++]+++9/+++++3/3/?3/?3/9/3/10]]632!"'732654&#"327#"&52#"&546z8q.b¢TR{ 'Bb %0$#105G?Ĭ{I%$00$#1 f%&e+ U@ U AG )+q+++5h%&:@#U#@>C4#@374#@4#p##A)++]q++++5(1& @ UA)+++5d*%!.@Z/0 yjju r tvHHY\Zh+15==1"@((! !%Ӷo,,,@UU!U 0! Ƶ0 !/229/]+++9/]?<2 lg=3oZ5k%)mpۜ>$  ///10#$H %@ MM  4@   @ 4ض@??4@44 @4@[\4@&)4@4" 4 @+-4  @ @+-4   @+34 +-4+-4ַ"+34/3/+]+]+2/+]+]+/+3/++++<<3/+++<+</10]r#'7'77'$H1111m1111 _@6 rrr  "()4@ 4/++<<</<<9//10'7!#!'71GQ11b1Q# z@. @ 4r  r  r   ޳()4@ 4 @ 4  +++<<</<9//10+#!'7!#G11Q11C 4 4  4/3/+9/9/3?3/++310#"&54767P?MfX+V!;75Tkp7=76(G660] 4 @ 4 @  4/3/+9/9/33/?2/]3/++310#"&54767#"&54632P?MfX+V!;7C00GF11B5Tkp7=76(G660"/EE/0DBC'3̳4@ 4@4@ 4 %@ 41+(. @@4""(.$/3/3/]3/+9/9/?2/+?9/++10++#"&54654&#"'4774'&'&54632#"&54632$)@2Bn@4AS*@* =J~ KxI41HI43F>/5B,DD"*I51Lt"izBR 48BpYol3IJ24IJy3$ 4!@4@4# 4# #   @ ##&@ 44 /9/+3+3/3/9/9/9/?3/92/9/+9/+910++'6767'&54767632&'&#"60bq] t3(0>PQK1 (4%='0h0%P+(#FZ/:@ 9 %# -3 4339%%## @9 0%5)#0 4005@ )@ 4)) 44/++2/93/+2/+9/99999?2/9/9/2/+9/9910'#67654&#"6763267&'&5476324&#"6V.:GW(  ."&E?'+5&G %A"  /)C6$B % #F7B*/ //4&U&F[E  4 $/<3/<?3/3/+2/10%4764764Z,S4Z,S[/,#Q,(";/-#R+*#Fb1#$/3/?3/104764Z,S1.-#Q,(#H(' !@ 4!!' ' @  '$$ $4$4$4$/+++2/3/2/99?3/9/3/+9910'##6767&'&54632'4&#"6S2J2I5G@!M-*  K& ,}$27H83'Be8()7 ]."F#$/3/?3/10%4764Z,S0,#P+("F(@%&!&@ 4&&! &%%4 4/++3/23/299?9/3/]3/+9/999910#"&'#"&546773276773276573 #** +  &K06 $ 922 $ #8K1 2(+/FQ -  /3/?2/10#"&546324&#"326Q\C66P;6Jb<6MwZWD-# | @  4 /3/99+/3/10&'&'667U0 U#"89&Wle0"D[v_1,.%; @ 4 @ 4 /3/+9/9+??9/10#474'&'&'7":-O(J`O0D#*ZwsԸ~@Z_Qs%! @ @4@4 4@4@ 4/3/+9/9+3/++???9/9/+9CTX@4+Y10#"'#'&&'7327677!49h 8&L0BC4_jp+ nBHP/OԲCU_.TK)k#]%) 4$$ @ &A   !!'&@ 4&&  @ 4 4/+3/+9/9]33/+9/????9/9/]9/910+#"&'##4'&'73276733273_c9T"hI% (8D4I4!\UUeJ9mL]o%XKFGLD??DY ")=9<3B#W !-.LdMbDG)+$ !HBAM)0 !@@@4 4@ 44/3//2/10+++#"'&547676324'&'&#"326guyFP,2FV\vJPCe]/B,$E?|zq*0[Qbx9B7-)ZIHR&#I@G(o( 4' 4 4 @ #@4##/3/3/+993/??9/+9/9910++&'&'&54767#"'&5465732767G&A!8$0J/0&$.jOcU .$+%=[o:=  N!"7%g3WAnWH%@ 4&44 4@4@ 4   4 @    G/333/3/333?+??9/++9/CTX@ 4 4 @ 4+++Y10+++#'376)@ǣ$eb? 'YV^3=1@T4&44 4 4 4  4@   G/333/3/333?+??9/++9/CTX84j4 4+++Y10+++&'#6763$1+ *[tG[WFV]) [/@Z'*. 8 P@ 4    /9/3/9//3//3/10]+#"&54632%##"&54632L76ML77L>mDL87JK66N7NO65JHGz6LL66ON0"9 4 4 @  /3/9/9/3?33/+3/+10'6765&'&54632&;"J*E)1%)K69VUI;9!777-( $<6MP:dgs 4#@2 4 #0qe6kY 4B 4YBGN,9ak*qFU;`kGq 4qqTGkkkN@ 4\ 4 \_QahKn? 4&@ 4?&,P333FGTUn`ah;*n,ah@ 4hh9,n@/3/+999992/q99++99993/q99++?3/]3/+9992/99++999999++10#"''#"'#"&5467'#"&54767&'#"&5463267&'&546327&'&5463267632676324&#"326d,!5JJ vV%4j  ! !$"!.0$VqC!;+!+*",k3=z;E(* 3#'"D6`*<  it8K`A2k۴qF,{@# 4 4! * @4 *@ !* 4.',/3/9/39/+399?9/?+9910++7#"&'#"'&54732654'&'326Bi\AJk0,Y/_=APM(0AWP)0@'1D=+Gжxiw%47_q 3'J|+CYRgJ@J-{#y 4 4  @@4@ 4###"/3/3/39/39++??9/9/9/9910++47"&54676632&&#"3267XGQNK;v-5sK IM1}l_V{-b^hDM-.?>/YJRV_ C26<"8"Xa!!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ FW:ι@ @ 4 @ @ 4 $*783./#*//$88$$*3* @ 4 /.'$#877/#$$/.4. 4.$/++3/23/299/+<3/<?9/3/2/9/99993/+3/3/+3/10476476#"&'#"&5476773276773276573[,S\,S3! #)++   &W.+%P+(#>0%P+(#L06 " 91$$ #8K1 2)-1!!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ %W/?10!5!WW%!!%!! @ !!%!! @ !!%!! @  $($44(4@ 44 4!#"$$%'&((@ o     A "$!##% &('%%A @*  4 */2/+2/9/9/993/993/99???93/]q993/993/9910+++++!"'&547673!54&'7'7'7''7Fr*9|oO6AM, DEJLJM"KN%CT]a#b..G8vA:p27pTVZU; µ44 @ 44 4  @ o   @ @ 4   */2/9/9/+993/993/99??3/]q993/993/9910++++%'7'7''7%!5!4'&'7JLJM"KNKNH8TVZUv>+Q[3M;!!!%!! @ !!%!! @ !!%!! @ !!%!! @ 6N u,04844.48@4) 4* 4y* 413244.57688-/.0@ 400  241335.0-//687@5@ 455 :'*/3/3/33/999]9/+993/993/99?9/99?999/+993/993/9910+]+++++"&#"676323263!3#"'&'&547676'7'7''7L@P4Z(#KB_Ep%Ӕ{F:؏XdOBFJ6F4@4J@4 4 * 4y 4GIHJJA?B@@CEF@DDD84=)%03"4-%%34=DFCEEAHJIGG@BA@?@4_????83@99""3433L))*/3/3/33/999]9/999/]+992/993/99??9/99?99999/]CTXDD]Y992/992/9910+]+++++#"&54767!3#"'&'&5476767&&#"67632326733'7'7''7{yf WXoF:؏XdUB%(Y$e?n"%SaM3a5()4!:2KUJLJM"KN%Zh':$4%DVll^ (0jyǫdSZ b&T%  8RۑTVZUyk"44"4! ""   "!@ T 4$/9/+9/9/993/993/99?<2/93/993/993/9910+++!5!&'&'&#"676323'7'7''7y%fFWHQS34/DhfEy+TN}Mb@()qzJUel/ *""sVj[Z4bZHnF)"+0s~9=XpTNT&m,!Z%E*ֳ4!4/4,40 4.@ 4;k= 4 44(4(ܳ 4(@ 4A(#A "  78@ (_((( ##8@AA 8G   4 */2/+9/9/9/]99?<TNѫF;@()XG=5!I/-=-{RZ,Q1 3ow%9=XpTNT&m,!)1YC.&Z4bZHnF:#0CA8<%Z9&3T)i? 1dk%m@4 4;k 44ܳ 4@ 4   @@o/_  */3/9/]]]99?TN}Mb@()qzJ%j[Z4bZHnF)"+0s~%d6ܹ/ֳ 4& 4441 45 43@ 4T+T2D+D2; k $ 4 4-4-ܳ 4-@ 4-"-(A ' "@ ---((8*/9/9/9/]99?<TN}Mb@()XG=5!e9&3T)i? 1dk)1YC.&Z4bZHnF)"+0CA8<%Z%,7@04/ 46 4@4 4;k 4*43 2 -... 4ܳ 4@ 4, A   %$ ,@ . 22@( A 9% $ 4$$( */2/+3/9/993/<?TN}Mb@()qzJUel/ *""sVJظ] j[Z4bZHnF)"+0s~9=XpTNT&m,!OYN?j$~FOZ%EP3@I4H 4O 4*ֳ4!4/4,40 4.@ 4;k= 4 44L#K"FGGG"(4(ܳ 4(@ 4A(#A "  78@ G#KK@ (_((( ##8@AA 8R   4 */2/+9/9/9/]993/<?<TNѫF;@()XG=5!I/-=-{RZ,Q1 3owظ] %9=XpTNT&m,!)1YC.&Z4bZHnF:#0CA8<%Z9&3T)i? 1dk˩OYN?j$~FO%m(@! 4' 4@4 4;k 4$#4ܳ 4@ 4  @ ##  @@o/_  **/3/9/]]]993/<?TN}Mb@()qzJaظ] %j[Z4bZHnF)"+0s~/OYN?j$~FO%d6A:A@4? 49 4@ 4/ֳ 4& 4441 45 43@# 4T+T2D+D2; k $ 4 4=(<'788'-4-ܳ 4-@ 4-"-(A ' @ 8(<<""@ ---((C*/9/9/9/]993/<?<TN}Mb@()XG=5!:ظ] e9&3T)i? 1dk)1YC.&Z4bZHnF)"+0CA8<%COYN?j$~FO2;&@4)44*4 4!' A 9' 4 03 @ ,$,@=! 4 $ 9/2/+3/3/99/??+??9910+++&&#"332!"'&54767673276654&##"&54767632 #a2W`X+5PHE`^f".<*?Cx+B71Cs}TePj6 @ 455@ 4,," 45& / @8  4 9/2/+9/9/??+9/9/+3/910+#"32!"'&54767327654&#&&#"&54767633])0Q0{@b(&%9zՏm#s?6I?3:??4HH44:C%%:,@ TKQKKQ @ QQ(?>743!HGG?/344?>4> 4>$/++3/23/2993/2/3/2/999?9/3/2/9/99993/+3/9/3/+99910"'&'#"&'6767&'&54632#"&'#"&547677327677327657'4&#"66#'#9<8L0: G-/   3! #**+   &Q#1  1& "!+U)# K06 " 82$$ #8K2 2)-1( F)1@&'"''"@ @4 @ 4 0*,,0.@**.@%(4.'&&4 4$/++3/23/299/+3/?3/3/++9/3/2/9/999910#"&'#"&5476773276773276574763 #**+  &3Z,S}K/5 " 82# $ !7J1 2),1/-$P+(#!!%!! @ !!%!! @ ///10#!$HbGQ$///105!#QHG !@   /<//<10###!!!HrG !@   ///10!!5!###rHGS@ ////<]10###!H @@  @4   /9=/<<//<+9=/<<<10#'77'$Hb ׶yyx #@    ///103#5!3###HGG)@     ///103#5!#3###HGGG !@   ///<10!!!##HFHS///<10#!$H,l@ /9=///<10##$HSW$'@ /<<//9/9/10##$HHH'88W' @   ///1053#5!#3WGBGGGW'///10#Hnw W$'@ ///10]#'$H'0W'///103!$'wGJ!'@/) !)i.@%) .0@>")> > i@)!?O>>>8H(y+?N]M]<]<M]<]<9999999910]'76327'#"''7&5432654&#"ՋsjitGGtijsGkklkwHHwn}~nwIIwn~}}llk #.48DHLRY`h@wz&S%c%#%3%C%Y=i=)=9=I=YAiA)A9AIAV;f;&;6;F;VCfC&C6CFCfhbdV`f`Y[i[**c*****u***3*C*S*cBB(-Wo]?]O]_]]]'VP(/(?(O((/ OGG23/3g<^P''O'_'' '0'@''R F"OM7K R6JMap999@9P9`999'W0^^'''_'o'@f''''$U-e-%-5-E--S++_oZP$$o!6 5## ! #j0eeo??????O??IJN/MMN1EQ2FN/]/]qr]q]]]q3]]]qr]]]/<<<<]]q]/<<<<]]q9/qq910]]q]]qq]]]]]]]]]]]]]]q]]#5#5!!5!#3#"'73253!5!!5353!#32##!!5!#"&54632#3!5!!334##324##32%#"32dCC?ddV4I(_tC~dYwdC~CddCdYeo|~ddd~C-Od?d ĺ[6.C?d{C~ddCcm !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ S0HH 44 4 /3/</3?310+++&'&'&4767670,h3g9JJ:f5d.l8<"8-}N౞Sy*K]SHW|@!!%!! @ % /|O@#%-.)$%!%%...@ 4!)!@c~9W=@C~~IIPPwccWCk55W==C%$ .--%$@%%c9Zg_@ccwPgg0TFI~}@TLPPT4T@ 4TTF5n0s ww00F/3/3/999/++3/99/9/9/993/2/23/293/2/?<<9/2/<9/9/9/9993/9/3/+2/]9/99993/3/9910&'&'632#"&'#"&5467732677327677"'&'#"&'#"&5467&&547673267&'&547673267&'&54767'3263 6 %%5)%  !** / & " wL=.(80?A{(p5p   C9.3'; $ 'B#:$X.4#72<Q=5-*$9 *jHk 6-- 0#U(()&%2&#;DL<;M!TL4"*"&RR{j70< '#*"%3wrI&.-'* )"+%"To #8 !y3 +@@?4  ?4 @ @ 4'$' @  $''/9/39/2/33//3/??93/+3/9/+99/+910#"'&#"'67632327'6654'&'667)02-c   & d2!54F2!31v ! $  PK(W L hu{,f-rt"%-@+-@?4--'+#"?4""'+@ 4   @--""## @ 4 /2/9/2/+3/33//3/??3/+3/9/+99/+910#"'&&'.'&'733#"'&#"'67632327D)$%  '{' "!b)02-c   & d2!54%70q{'0$xh|2* ! $  V n 44 4%$-0@ *4004$@  -00(%$$ (;/9/39/9/2/3/9/99??2/3+/9993}/+910++47&'&547632&#"326'6654'&'667n*d5;- $+]!2!31f @.#8> 4PK(W L hu{,f-rtV% 6 4,-@ *4--46!@  @ -,@ 4,,--&11 8;2/9/2/+9/2/3/9/99??2/3+/9993}/+10+47&'&547632&#"326#"'&&'.'&'733n*d5;- $+]!̌D)$%  '{' "!f @.#8> 470q{'0$xh|2*xcq *J͹-@ 4@ 4@ 4@ 4@+B2H0:@BBH@4HH0@ 400  %%!  @ @2==E++E006EE(( !L 4 ;/+39/2/2/3/9/99?2/?2/93/+3/+3/99910++++#"'&'&'73276767"'&547632&'&#"47&'&547632&#"326zBF3RAA8{1zmUU+OCL08VW&?')XM*d5;- $+]!a # >1]/j+1pgXfeO`% %13 @.#8> 4xcq-@R4@ 4@ @44  4%$-0 /$$@  (-00(%$$ (;/9/39/3/3/2/9/99?]?93/+]+3/+3/99910+47&'&547632&#"326'6654'&'667E*d5;- $+]!+2!317 @.#8> 4gPK(W L hu{,f-rtY@6@ 4,.4&@ ..4@444 4   @ ,))11"@1@ 41@ 411 @ 4 8;2/9/2/+2/++2/3/9/99??3/+]3/+3/99910+#"'&&'.'&'73347&'&547632&#"326D)$%  '{' "!*d5;- $+]!%70q{'0$xh|2* @.#8> 42q;[> 4&@4)44*4 4Q1Cs}TePk @.#8> 4j6V9 4 @ 4L7N>TIIQ77Q< 4%:Y ,@ 44 4" $*@ $$*@4**@ "' '''.;/2/9/9/2/3/9/99??3/3/+3/99910++!5!4'&'747&'&547632&#"326:KNHl*d5;- $+]!%v>+Q[3M @.#8> 4%:Y R3   /9/39/??910'6654'&'667R2!31$PK(W L hu{,f-rtY%<   @ @ 4 2/9/2/+??10#"'&&'.'&'733D)$%  '{' "!%70q{'0$xh|2* @ 44 4   A  A @"  4 */2/+2/9/9/99???93/9910++!"'&547673!54&'7'7Fr*9|oO6AM, DNJ%CT]a#b..G8vA:p27pT: ]4 4  */2/9/9/99??3/9910+!5!4'&'7'7:KNHfNJ%v>+Q[3MT: , '@ 4%% @ "")"(/3/9/9993/993/99?2/99+3/]993/9910'7'7#"'&54767'74'&'326NKALJ.GI07# !=#xWn/6- 908ːVTGn!=F\NO_T&?1 '#39?=%F%&/ @@ 4'+( . ((.ﵐ& @ @+#('  +1+/9/]999/993/99?2/]2/2/9993/+993/9910]'7'7#"'&'#"&5467&&5476733'32INKALJH7)\3s  !Wd"81<АVT[{\8>VND"*"$>t>DhmC7 %$@ 44 4@ @ 4 A    A @&  4 */2/+2/9/9/993/99???93/+993/9910++'7'7!"'&547673!54&'7%NKALJ`Fr*9|oO6AM, DVTzCT]a#b..G8vA:p27p%%:V{4 4     */2/9/9/993/99??3/]993/9910+'7'7!5!4'&'7NKALJKNHVT*v>+Q[3M%:V% (@ 444@ 4"4 4  @ @ 4 $A #$  $$##A @ *  4*/2/+2/9/9/993/993/99???93/+993/993/9910+++++'7'7'7!"'&547673!54&'7`MJhNKALJ`Fr*9|oO6AM, DcVVTzCT]a#b..G8vA:p27p%%:  @ 44@ 44 4         */2/9/9/993/993/99??3/]993/993/9910++++'7'7'7!5!4'&'74MJhNKALJKNHVVT*v>+Q[3M%: 6N u0@- 4* 4y. 4@ 4 #"$@"$##2 +*/3/3/33/999]9/99?9/99?999/+9910+]++'7"&#"676323263!3#"'&'&547676UM}L@P4Z(#KB_Ep%Ӕ{F:؏XdOB@ 4 * 4y 4A?@B@ 4BB84=)%03"4-%%34=@BA??83@99""3433D))*/3/3/33/999]9/999/99??9/99?99999/+9910+]++#"&54767!3#"'&'&5476767&&#"67632326733'7{yf WXoF:؏XdUB%(Y$e?n"%SaM3a5()4!:2KDMM%Zh':$4%DVll^ (0jyǫdSZ b&T%  8RUyk\  @ T 4/9/+9/9/99?<2/93/9910!5!&'&'&#"676323'7y%fFWHQS34/DhfEy+<KN%O,7J-Ad2m yTyk6N u,u@) 4* 4y* 4  @ .'*/3/3/33/999]?9/99?9910+]++"&#"676323263!3#"'&'&547676L@P4Z(#KB_Ep%Ӕ{F:؏XdO@ 4 * 4y@ 484=)%03"4-%%34=83@99""3433@))*/3/3/33/999]9/99??9/99?999910+]++#"&54767!3#"'&'&5476767&&#"67632326733{yf WXoF:؏XdUB%(Y$e?n"%SaM3a5()4!:2K%Zh':$4%DVll^ (0jyǫdSZ b&T%  8R%yk<  @ T 4/9/+9/?<2/910!5!&'&'&#"676323y%fFWHQS34/DhfEy+<%O,7J-Ad2m %yk6N 0@- 4* 4y. 4 #"$@"$##2 +*/3/3/33/999]9/99?9/99?993/9910+]++'7"&#"676323263!3#"'&'&547676MKL@P4Z(#KB_Ep%Ӕ{F:؏XdOH:%B-&>%)m-U%j%mf @     */39/9/9/99?2/9/3/9910]'7!"&546733!4'&'7NI@9[  *2>H:VB-&>%)m-U%F/pr@ * 4* 4 4 4@ 44 4  :  /32/9/??910++++++#"'&'&'73276654'&'7/^RztKEP=UHGB:~.%C9R',%nvhKH ( RK\OWFJLLVjF/pF/"@ * 4* 4 4 4@ 44 4 : $/32/9/3/99??93/9910++++++'7#"'&'&'73276654'&'7MK9^RztKEP=UHGB:~.%C9R',ȑTnvhKH ( RK\OWFJLLVjF/lWF@ 4@4! 4&4 4AAB:45,BB(55'( :, A145@ 455A ((''''#, @ 4 ABB?AAA=A @H  4*/]2/+2/]9/9/+<2/]9/9/+99??<?9?9/9/99/10++++#"&'###"'&546767327654'&'7327654&'732654'&'7O<[/*!/Z{,9ujt*$6(F-%5S2{_(#(%)K&C/ %!$& \WqBSFMVY6pE|CSdZGAR?Y4;# 7m>-Dq%5l Ro@ 44@ 4L 4*@4- 424 4  @ 4MMNF@A8NN4AA34 %+$F 8+ IM=@A@ 4AAM443333/8@ 4M(NN?MMMIA @ T% $ 4$$(*/]2/+2/]9/9/+<2/]9/9/+999/993/993/99??<?9?9/9/99/3/993/993/9910+++++++'7'7'7#"&'###"'&546767327654'&'7327654&'732654'&'7MJhNKALJO<[/*!/Z{,9ujt*$6(F-%5S2{_(#(%)K&C/ cVVTz!$& \WqBSFMVY6pE|CSdZGAR?Y4;#6'256 466B#&'@ 4''BCCB@ 4BB> I/2/+9/9/+99/+9999/993/993/99?<<?9/9/9/99993/993/993/9910++++'7'7'7#"&'##"'&'##5327654&'73327654&'732654'&'7gMJhNKALJM@\&/#3YA44"20PZQ#:) &.@CK$(*'":!)*A)cVVTz# %  $E:$<\*I%-9:"<^o+&!8> 7m>-Dq%l W1>@44 44 45-- <";2""2A @@  4 */2/+9/3/2/9/9??<?9?9/10+++!!"'&546767327654'&'73276767676324&#"!26 \rjt*$6(F-%5S2wfXaRAJYD?{RHY?aIH`r%hFMVY6pE|CSdZGAR?Y&!Gg4OI17 2&&'l W% >%0[ !))-  -& &2 /9/999?<2/9/9910!"'&'##5327654&'73276767676324&#"!26 N61%2*T\Q#:)#=AXTqzX QBJXE@zQdqpmd%$E;#l 5B̹@44 4 4 4"911!" @& @ ?6""!!&&6A @D  4 */2/+9/3/2/9/99/99??<?9?9/3/9910+++'7!!"'&546767327654'&'73276767676324&#"!26uLJ>\rjt*$6(F-%5S2wfXaRAJYD?{RHY?aIH`rdTlhFMVY6pE|CSdZGAR?Y&!Gg4OI17 2&&'l % )4z@ %  %--1 1 * *6 /9/9999/99?<2/9/993/9910'7!"'&'##5327654&'73276767676324&#"!26LJ N61%2*T\Q#:)#=AXTqzX QBJXE@zQdqpmddTl$E;#9/I  #- 1jC=ibI_NXAE%5,e/k^B_9/I  #- 1jC=ibI_NXAEȑT5,e/k^B_E&#8gM3I;P-8xYsωu]^-d" #i(`*/K1"C8\j/2DAQK]G % n4/  @4 4  /3/3/33/9+99?9/]?]9/910+##53&&54632&&#"66 Es$ś{P"QEn;cN]7K/w8v<b=21y//%mX(j@ $(4(  @$$$P  * /3/2/]9/9/9?<2/+9/9/99910#"'&'##532767'&#"#54763233mACP$CViZZTHRO* (:5qG]%H[%%BE&#8gM3I;P-8xȑTѠYsωu]^-d" #i(`*/K1"C8\j/2DAQK]G % !4@ /   @ 4 4 # /3/3/33/9+999/99?9/]?]9/93/]9910+'7##53&&54632&&#"66eKLFEs$ś{P"QEn;cNȑT@7K/w8v<b=21y//%m,@ ( ,  4 ,@$ (((P$$$$./3/2/]9/9/99/99?<2/+9/9/9993/9910'7#"'&'##532767'&#"#54763233LKACP$CViZZTHRO* (:5qG]%H[ȑT%BFUc,%h/"!)XHNYwQ(W[%~ *0G]jwubW/8)%1m%s%j%t@  # # @  4  !! '/9/99+9/99?2/2/993/9910'7!5!4'#"'&547632&'&#"326MJ)4.#I.528ZzB7*&#X4yVVYN %*Oht$%2-P%`!j@  4    #/9/99/99?2/93/2/9910+]'7!5!267&'&547632'&'&#" XSW>W33s7>Yf5*Z):(OK`~ 2xi]igP'K,L gw5BѳT  4@ 4!@ 41::)@@ @ 6 4&6#-==#A @D  4*/]2/+9/99+9/993/99??99/3/2/993/9910+++]'7'7!"'&54767327654&'#"'&547632'&'&#"326xNKALJz&#A* nfՠ &M'X7C:AYuD: *0-:%-"VTh]PWvxxF6J5C?>9FQ3-(0aqgt>).#$gw%j)@@ 4" '""'  @  4   %%  + /9/99+9/993/99?2/2/993/+993/9910'7'7!5!4'#"'&547632&'&#"326JNKALJ4.#I.528ZzB7*&#X4VTYN %*Oht$%2-P%`%@  4  " ""  ' /9/99/993/99?2/93/2/993/9910+]'7'7!5!267&'&547632'&'&#"5U}ViO{SW>W33s7>Yf5*Z):(ORQ 2xi]igP'K,L s%3(I.84 @ /H# /&&&H@ @ 4 2:=>353%'IB@&>2SSQ!@ ('K-J.&D!OiN%mI#v@  4 4! 4   #    4 % /9/+99/9?<9/2/10+++#"'&'##5327676767'&'&'mhCTaJ:yt[G7-=YPCE)7s &0!$:%#=G7.$AXA:iTrG:8/2 !2'>%mIl{v$ 4@4 4 4 A ! @ 4!! A @&  4 */2/+2/9/9/+99??9?3/9910++++'7!"'&546767327654'&'7KHjt*$6(F-0S5($ViqFMVY6pE|CSfXN:Ql{v%:[ 4 4   */2/9/9/99??3/9910+'7!5!4'&'7LJKNH‘Tv>+Q[3M%:6 q=%F'n@ # & &@  #)# /9/]99?2/2/2/99910]#"'&'#"&5467&&5476733'32FH7)\3s  !Wd"81<%{\8>VND"*"$>t>DhmC7 Zp(5C@: 4:-=2-#4##--2 A @=:2)# 40##)00 )@ :@ 4:: 6E /3/9/+9/9/9+99999??9/2/3/+9/999+10#"'&'##53267&'&54677667&54767%4'&#"6764'&'326Z$'')pgGt5C[ZZ)LA c!E,@a{G^..Pz+8#3)%<=2 :GM40.B #/S7=ts+=+)C#J/51Umo)4&"."" 22@ *. &. &. * **6/9/9/9/3/999?<3/3/9910!#"'&57#536767632!%4#"6764'&'326m@-9@xdx#*5:C;/.(+<5[>H(t_\5@#%7EQN/;SdH]Pe@Jl=X7!C_^-i&,OI<nGVxc *u@ 4@ 4@ 4  %%!  (( !, 4 /+39/?2/?2/910+++#"'&'&'73276767"'&547632&'&#"zBF3RAA8{1zmUU+OCL08VW&?')Xa # >1]/j+1pgXfeO`% %13xc25j62V;?Cչ&@4)44*4 4<>?==@BCA!' A 9' 4 0=?<>>ACB@@$3 @ ,$,@E! 4 $ 9/2/+3/3/99/9/993/99??+??99?993/9910+++&&#"332!"'&54767673276654&##"&54767632'7'7 #a2W`X+5PHE`^f".<*?Cx+B71Cs}TePߐVTjN6:>33 @ 4:44 4,./4,,"@ >79::88;=>>< 4<58:799<>=0;;;/& / @@  4 9/2/+9/9/9/]993/99?2/9?+]993/]993/]9/+9/+10]+++q#"32!"'&54767327654&#&&#"&54767633'7'7])0Q0{@b(&%9zՏm#s?6I+Q[3MDVTr:@DNe0@TVJOce@?4ee_c[WZ?4ZZS_WWc@'SS.<;K.7 4H7#K##@ 4##.KK?.@K@eeOZOZ[[#*7HK@@ ??<<;;  @ 4*E@ @ 4 @ 4 g@**/]3/++9/9/+2/3/93/3/9999993/33//3/???9/9/+]99+99993/3/9/+99/+910]'#656767&'&'&'&#"#"'&'&&5476326765'4674&'276#"'&#"'676323270;"%P&jruF #T!  /)-$ )NEUKIf-/C9,Kw:v2U)02-c   & d2!54F[~F(?A%4# LA[7<+#,'9.=+>#5NFreuJ^x!Bk,+$+/6'f$  ! $  @ >UH44ֳ4)ֳ 4(@ 4[+"@% 4+* 4*J 4)T 4(@ 4?SU@?4UUOSKGJ?4JJCOGGS@CC @ 4  0@ 4>03'&&>@ UU?J??JKK  4@ 4 7- 0033-77W&&/3/2/3/]99/+]+3992/33//3/?3/??9/+9/9/+92/3/9/+99/+910+++++]+++++&'&#"#"'&'&5432#"'&54&5!5$767654&'76733#"'&#"'67632327'8nzF:I,;)HtT3=`KY n!$)02-c   & d2!540}4#,:NX?[eW[n6ct& Q;^{bYT1"sc~6$ ! $  & DNn@Q@, 4TVJ<;K.7 4H7#K##@ 4##.K?K. 4..T?OdfVlTT4Tllf^@ 4^K@ dVaaiOOiTTZ@@ii#*7HK@@ ??<<;;  @ 4*E@ @ 4 @ 4 p@**;/]3/++9/9/+2/3/93/3/9999993/2/3/9/99??+2/3+/999?3/+9/9/+]99+999910]+'#656767&'&'&'&#"#"'&'&&5476326765'4674&'27647&'&547632&#"3260;"%P&jruF #T!  /)-$ )NEUKIf-/C9,Kw:v2U4*d5;- $+]!F[~F(?A%4# LA[7<+#,'9.=+>#5NFreuJ^x!Bk,+$+/6'f$  @.#8> 40  >^RA 4)ֳ 4(@ 4[+"@/ 4+* 4*J 4)T 4(@ 4  @ 4 @ 4> >03'&&>4@ 4DT?VF\DD4D\\VN@ 4N@ TFQQY??YDDJYY  4@ 4 7- 0033-77`&&;/3/2/3/]99/+]+3992/2/3/9/99?+2/3+/9993/++?3/?9/9/+9/+]910+++++]]+++&'&#"#"'&'&5432#"'&54&5!5$767654&'7673347&'&547632&#"326'8nzF:I,;)HtT3=`KY n!$=*d5;- $+]!0}4#,:NX?[eW[n6ct& Q;^{bYT1"sc~6$ @.#8> 4SDNn@Q@ 4TVJdOfVlT^@ffl@4ll@TTT@* 4TT<;K.7 4H7#K##@ 4##.KK?.K@ dVaaiOOiTTZ@@ii#*7HK@@ ??<<;;  @ 4*E@ @ 4 @ 4 p@**;/]3/++9/9/+2/3/93/3/9999993/2/3/9/99???9/9/+]99+99993/+]3/+3/99910]+'#656767&'&'&'&#"#"'&'&&5476326765'4674&'27647&'&547632&#"3260;"%P&jruF #T!  /)-$ )NEUKIf-/C9,Kw:v2U*d5;- $+]!F[~F(?A%4# LA[7<+#,'9.=+>#5NFreuJ^x!Bk,+$+/6'f$ P @.#8> 4A >^_A 444ֳ4)ֳ 4(@ 4[+"@ 4+* 4*J 4)T 4(@ 4T?VF\DN@ VV\@4\\D4D@ 4DD& @ 4  0@ 4>03'&&>@ TFQQY??YDDJYY-&  4@ 4 7- 0033-77`&&;/3/2/3/]99/+]+3999/2/3/9/99?3/??9/+9/9/+93/++3/+3/99910+++++]++++++&'&#"#"'&'&5432#"'&54&5!5$767654&'7673347&'&547632&#"326'8nzF:I,;)HtT3=`KY n!$*d5;- $+]!0}4#,:NX?[eW[n6ct& Q;^{bYT1"sc~6$ @.#8> 4SDN@)TVJ<;K.7 4H7#K##@ 4##.KK?.@K@ #*7HK@@ ??<<;;  @ 4*E@ @ 4 @ 4 P@**/]3/++9/9/+2/3/93/3/999999???9/9/+]99+999910]'#656767&'&'&'&#"#"'&'&&5476326765'4674&'2760;"%P&jruF #T!  /)-$ )NEUKIf-/C9,Kw:v2UF[~F(?A%4# LA[7<+#,'9.=+>#5NFreuJ^x!Bk,+$+/6'f$ A >44ֳ4)ֳ 4(@ 4[+"@- 4+* 4*J 4)T 4(@ 4 @ 4  0@ 4>03'&&>  4@ 4 7- 0033-77@&&/3/2/3/]99/+]+399?3/??9/+9/9/+910+++++]+++++&'&#"#"'&'&5432#"'&54&5!5$767654&'76733'8nzF:I,;)HtT3=`KY n!$0}4#,:NX?[eW[n6ct& Q;^{bYT1"sc~6$!!%!! @ !!%!! @ Fb1F=!!%!! @ !!%!! @ !!%!! @ FQ F!!%!! @ !!%!! @ HFZ!!%!! @ !!%!! @ !!%!! @ FIFWFKF=H@.J0wG!!%!! @ FF[!!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ >@ 4 /3/9/?2/+?10#4'&'&54632#"&54632+9 %F79IH42HH42HCv~:~-=]\72HH23JJ"  /?10#"&54632O76LM58N6ON76ONW *  /3/?2/10#"&54632#"&54632N85LJ78NO75LK68N8NN87NN6ON76ON!!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ !!%!! @ %F/?10!5!FF%%F/?10!5!FF%%:/?10!5!::%c, 4'@4' 4 4 4 4@F 4(  % (,,&U# U U U U8U&U U޴ U U U UҴU@ 4&! U !!c-]+/]++++++++3/++++++9/99???9/910+++++++3276'&#"%53#"$576!2676'+u߃&4Ŀ;_I[%rIѥ|B[Lly[h18-VD@,@Y' 4 4 4@4 4)  % (,,& U0U U$@U U UUӴUִ U@0 U $@$%4! U! U! U! U!U!@U! U! U! U!?!!1-]++++++++++/]+++++++3/+++9/99???9/910++++]327654'&#"%53#"'&763266'YTSYZTSYB&1v䅉ۋiD;lffmʿkfelѥ|BVHA'vm*ZU%%4 4 @ 4&!@6 %% U& UD U U UDUDU& U@ U U@ U U UӴU@U& UU U U U UUU4]&+++++++++/++++++++<3/+++++++9/????9/910]++53# &53327636765$c24gs8$"}V[œFѥ> ~PRO]YcafNl*v&$ 4@S4 4    $$& U U- U U U 3%,UU@ U U@ U U U޷U%U@U U U U UU@364 N%]q++++++++/++++++++<3/+++++9//????9/9910+++53#5#"&&'&533266536765\$\|]P #S:?Uѥ>GnO6r/T9a*vE+, 4S@`/]}?10+#'3/+, 4S@`/]}?10+#'3 #S 4@ 4//@ 4S@`p/]]/+]qr+10+#3 T+A44 4SO`/]+}?10++3#+@+84 4SO`/]+}?10+3#^+s #T4@ 4//@ 4SO`/]/+]qr+10+]3##),@ 4 @4 4%4@ 794@SZ4 @   W@ 4p/]+3/93/}?}++++]qr+9910+7676'&#"'6#55*[? 'i{NVp^ ^'*Ce2p m,@* 4 @@|4@RU4@KL4@<>4@&64 @4  /3/93/+}?q+++++9/99CTX@ 4+Y10+7676'&#"'6#51'T< $b]  AZ?7,@ 4 @4 4%4@ 794@SZ4 @   W@ 4p/]+3/93/}?}++++]qr+9910+7676'&#"'6#55*[? 'i{NVp^ ^'*K]2pgm,@* 4 @@|4@RU4@KL4@<>4@&64 @4  /3/93/+}?q+++++9/99CTX@ 4+Y10+7676'&#"'6#51'T< $b]  AZ?7I;0_ 4 @7 4 4  EE   @ 4?  v v@o/]3//]+qr3/]9/]2/10+++&6323273#"'&#"q[>k;#= ?gCNIf~6W8$_|+ٳK @ 4 4@@ @^5 @OS4 @CE4 @+-4o    @a  / O _  _ o   @5 @jl4 @a5 @\]4 @WY4 @MQ4 @DI4 @:5 @144 @.B4 @',4 @%4 4  /3/}/+++++++++++++]qr3/]q++++3/10++]&6323273#"'&#"q[>k;D= a?gCCN|R[,F,Lr s 4 @ 4 4  E@4!&4E / ? /  @ 4 @6>4?  v v@o/]3//]++qr3/]9/+]2/10+++&6323273#"'&#"sq[>k;#= ?gCN f~6W8$_f= 44 @#(4 /3/?q+10++&'3327673#"'&N;@AC@;OIMp#v#%H$&9O9@4 4/++9?r910#73#ЯC{{(@k;#= ?gCNIf~6W8$_I0k 4 @A 4 4  EE O  @ 4? O  v v@P/]]q3//]+qr3/]9/]2/10+++&6323273#"'&#"q[>k;#= ?gCNIf~6W8$_IM0k 4 @A 4 4  EE O  @ 4? O  v v@P/]]q3//]+qr3/]9/]2/10+++&6323273#"'&#"q[>k;#= ?gCNIf~6W8$_ri@2 4 4 4EE    @ 4 v v4 4o/]++3//+]r3/]9/]2/10+++&763232673#"'&#"s:9Y>k;# "mT?gC"h>>6#4rr8$/Hi@2 4 4 4EE    @ 4 v v4 4o/]++3//+]r3/]9/]2/10+++&763232673#"'&#":9Y>k;# "mT?gC"h>>6#4rr8$/ji@2 4 4 4EE    @ 4 v v4 4o/]++3//+]r3/]9/]2/10+++&763232673#"'&#"k:9Y>k;# "mT?gC"h>>6#4rr8$/}}J}{}}e} b#S 4@ 4//@ 4S@`p/]]/+]qr+10+#3  #T4@ 4//@ 4SO`/]/+]qr+10+]3##`i@2 4 4 4EE    @ 4 v v4 4o/]++3//+]r3/]9/]2/10+++&763232673#"'&#":9Y>k;# "mT?gC"h>>6#4rr8$/}_,}]vC}t}}l9}jX%}V]}},}*|+nK @ 4 4@@ @^5 @OS4 @CE4 @+-4o       /3/}?3/]q++++3/10++]46323273#"'&#"p[>k;D= a?gC@Q|R[,F,LI0k 4 @A 4 4  EE O  @ 4? O  v v@P/]]q3//]+qr3/]9/]2/10+++&6323273#"'&#"q[>k;#= ?gCNIf~6W8$_|4+nK @ 4 4@@ @^5 @OS4 @CE4 @+-4o       /3/}?3/]q++++3/10++]&6323273#"'&#"q[>k;D= a?gCCN|R[,F,LI40k 4 @A 4 4  EE O  @ 4? O  v v@P/]]q3//]+qr3/]9/]2/10+++&6323273#"'&#"q[>k;#= ?gCNIf~6W8$_<&@@Op  % U U U@ U U U@ U /]+++++++??10]rq33&Y&$}4 5<44A+++5J>&D}@ 99:/7A+]5Y,&$t@ ##"A+]5J &D4:LUL@ULpLLPL`LLLLLLʱH++]qr++5Y+&$'|q0@*4H+A@(4/+5+5++]q5J#&D'KZ_BB@=4B;H+: :0:p::::::::@.24:=A>/>>_>>@ 4>/+]qr5++]qr5++]5Y+&$'|n'@H+A@(4/+5+5+]q5J#&D'-Y@E?@&34?@4?<H+: :0:p::::::::@.24:=A>/>>_>>@ 4>/+]qr5++]qr5+++5Y,&$'|u1)@4)))(AA@(4/+5+5+]q+5J,&D'tHb@ SOSSS@>4SR;/>>_>>@ 4>/+]qr5++]qr5++]q5Y+&$'|<0@"@ 4@4 AA@(4/+5+5+]++5J&D'ztT@A?O??I:=A: :0:p::::::::@.24:=A>/>>_>>@ 4>/+]qr5++]qr5+]5Yh&$'|}455<44@AA@ (4/+5+5+++5J&D'}C@0@@A/7A: :0:p::::::::@.24:=A>")+++]qr5+]5Y+&$'{q4#AB4#@95##H+A @-4 /+5+5+q++5J#&D'H7@ `HpHH[HH@4HCH+<<h+<")++]5++]q5Y+&$'{n\ @-4 /+5CTX@T##AA+5+5@#@894#@)14#@ 4@#o####@ H+A+5+q+++5YJ#&D'\*IPIIC@H+<<h+<")++]5+]5Y,&$'{u;@ 6666*246@!(465AA @-4 /+5+5+++r5J,&D't\B@0PZ`ZZZZZ0ZpZZZZZZZYA<<h+<")++]5+]qr5Y+&$'{P,@###/##-AA @-4 /+5+5+]q5J&D'z+F@ 4FP?9A<<h+<")++]5++5Yf&$'{}45$5<4$4@$%AA @ -4 /+5+5+++5J&D'}&@GGH/7A<<h+<")++]5+]5&(}\@    A+]5K>&H}P`ش A+]5,&(t A+5K &H*@2222221 A+]q5&(|j@  A !)++5K&H@ * A)++5+&('|q0@*4H+A@(4/+5+5++]q5K#&H'LK_((@/4(!H+ @;5 @-24  # A /  _  @ 4 /+]qr5+r++5++]5+&('|n4@%@:5H+A@(4/+5+5+]qr+5K#&H'.Q@=%@U%@&34%@4%"H+ @;5 @-24  # A /  _  @ 4 /+]qr5+r++5++++5,&('|u1&@ 4&&&%AA@(4/+5+5+]q+5K,&H'tHQ@ O9999@0498!"A @;5 @-24  # A /  _  @ 4 /+]qr5+r++5++]5+&('|P$@AA@(4/+5+5+q5K&H'ztE@3%O%%/ #A @;5 @-24  # A /  _  @ 4 /+]qr5+r++5+]5h&('|}\$@  AA@ (4/+5+5+]5K&H'}9P&`&@&'A @;5 @-24  # A$")++r++5+]5c,&,t:@ UA++5 &CTXA+O"H++qY5&,} A+5|I&L}z@ @mo4O  A+q+5c&2}  A+5D'>&R}  A+5c,&2t8@p00000/A+]q5D' &R*@....-A+]q5c+&2'|qn0&&&@*4&H+!A@(4/+5+5++]q5D'#&R'MD_$$@)4$H+@.24A/_@ 4/+]qr5+r+5++]5c+&2'|n@4@%#@:5###### H+!A@(4/+5+5+]qr+5D'#&R'/C@1!@&34!@4!H+@.24A/_@ 4/+]qr5+r+5+++5c,&2'|u`16@ 46665!A!A@(4/+5+5+]q+5D',&R'tHL@ O55555@*454A@.24A/_@ 4/+]qr5+r+5++]5c+&2'| @#-!A!A@(4/+5+5+5D'&R'zt>@-!O!!+A@.24A/_@ 4/+]qr5+r+5+]5ch&2'|} @$% A!A@ (4/+5+5+5D'&R'})@"# A@.24A ")++r+5+5c,&jj@0o000%H+-!)++]q5D&k!@0O0_000%1H+-")++]q5c,&jCj @ ...%H+-!)++]q5D&kC!@_.o. .0..%H+-")++]q5cE&jt8@PAAAAAA@%%A+]q5D &k*@AAAAA@%%A+]q5c&jQ@ -9%%A-!)++5D&k@ -9%%A-")++5c&j}@ ../A+q5D@&k} ./A+5"&8}p@ OA+q5&&X}@P`p A+]5",&8t@ % A+]5 &X2@P------P-`-p-----@ 4-, A++]q5,&lj)'@95p'/'_'''H+&!)++]r+5&m@O(((E4@.34@$)4/@4@4@ 4/+]+]+q+++++]<++</<<10!5!#53#53u4 4@% 4@ 4?@ 4 @#%4@4 @9 4@4@Os4@>E4@.:4@$%4/@4@4@ 4/+]+]+q+r+++++<++</+]+++9910#7#53#53炇燇44  0444@#%4@ 4 @144 d4 @#%4@ 4@4@ 4? @ 4 @#%4@4@+,4 @: 4@4@Os4@>E4@.:4@$%4/@4@4@ 4/+]+]+q+r++++<+9+<++</+]++++++++99++910#53'#'37#53QȮؓɱbb4 @ @ 4 @ 4@ 4? @#%4@4 @9 4@4@Os4@>E4@.:4@$%4/@4@4@ 4/+]+]+q+r+++++<++</]+++9910#53'#'3#53`ؓU Z@  UU U@ U]  ??9/++++9/10!!!##53!Uo¤ e & b@ % U@U U UN +@ U+  ??9/+++++9/10!3###53!Q||ci[F@_817$G$E )9$&& ) )   EDEEDBDE1// ?=??=?=+6 E+ U U U @3U &/1$,76*?= *DF,B) *EF ??9/99999999/++++99+}99+}99+}99+}10]]]]]##&'&##"7#67&'&'&&56323276767632"&#"3[E].Z|`IBj .d:$6?\WN e])>M$DǖF%L>']_ 3 g9 36#:dki.ZR2-n')T3R<(M~O*;G&3S+'P&B1@;#h$&& U& U&%) U%)  0//@U/%;9;;9;9,5%BA@ U%A?A??>,A, % U @ U  U @; U U 9;5+0$&/,4*+*?A,>)+ * BA+ ??9/999999/+++++99++}99++}99++}99+++}10]]##&'&##"#67&'&'&&#"532332767633'&3P"0"5IJ4 1ovZ-808 (j)9.)91cd0q%:vB1L '%&NuomI-IQ 10SI)L3 K bB5A'=)c_$2$i'@%@/ U U &$&&$g$&$#'  7   '@ U')  U U U U U U @#U ](   $&#  & ??9/9999999++++++++99]+}9]+++}10]]]]##&'&##3276767632"&#"3E\,ZwF%J>']p 4 g9 37"9eki.\R~R+;G'1S)'v&&@ U%%#%%#F#"#%&@U% %&@ U &&( % U @U  U  U U U U @. U U  N'+  #%" + %+ ??9/9999999]+++++++++]+99++}9]++}10##&'&##327676767633'&3v/#5Id0:(,:+_$2K '%&Muom>-IQ 1&5A` I( d^%2$+$&&$&@8 U& IYi$$* U **) U@U U - U U U U U U @1U  ],&$ ! *)       ??99//99/999999]+++++++]9/+++29++}99]]++}]10!#&'#&##3273676767632"&#":/x3EG1x&/76NHYp 4 g9 37"9e_<R~An*X,(G'1S)'&(4i#!#@J U#%!!!!!'U%''& U * % U @U  U  U U U @; U U 0  N)#! + '&  +     ??99//99/999999]++++++++rr9/+29++}99]]r++}ıCTX@ -"=2]Y10]!#&'#&##3273676767633'&c#+-!c(,:+_$2K ')")6jpI7&5 D+9` I( dh(0i@   U UU@ U U@ U U   UU U U U@U]  ??9/+++++++++++++10##!#3!33†iMZW&@, %%@ U U U U U UU@ UU@ U U" UߴU U@ U %UU@U U U@ U U N + +??9/]++++++++++++++++++++++10##!#3!33W t-)&Fnm U @: U U    U U o UU@ U U U@U  &6??9/]9/++++++]+++}ć+}+++10#367m$ "09rHUE9ji& ֹ @ U U U @=U U  U %  U U%%UU@U U U U@U  $4Dt /?]?9/+++++++݇+++}ć++}+++++10#367nm.1&i&wmgmѹ U@HU U U    U  U    UU@ U UU@ U   ??9/9/++++++39Ƈ+++}9+++}9++10!!#!5!367mkUdaUj"099_UE9ji&@& F v &Fv@ U U U@GU U U U%  U U %  % U U @U U U @ U   + /??9/++++++Ƈ+++}ć++}++++++10]]!!#!5!367nBCm.1&ڄ&wmg iI@ UiDtI   U U@ U  UCTX  @ 4 4    ?Vw=I^M&@&F&FX&F @ U( U @( U  U U    @ U %%@ U U U0@ U%_o  U @ U   + /??9/]++333]]++}]]+++++}+++++10]]]]###367733I* #.$g-](@74A bW8@dEU6@ U U@ UUU@ U U@ U U U@ U UU U@- U U  UU U U U@U U U@! U]    ??99//3332229/]+++++++++++++++++++9/++++++10]]]!###"'&'&53733673¢xt,(±y xO< >FyocG>E&@te U U U U@ UU%@U U U U U@ UUU %@UU U@: U U UUUO_+ ??99//333229/]++++++++]]++++++++9/++++++10]]!##5#"'&'&533673ndcY^d$! ?,;cW{" 7;bYkt+T/! )@g[J U U Uд U U UU@U U U U U U U @U ]   ??9/32+++++++++++++++10]]]!#4'&#"#3$328Gċs,'\s[7a>Ezm&@ zh%U@ U UUU U@ U 0 % @ U  U U U @ U  U  N +  ??9/32]++++++]+++++++10]]]!#54'&'&#"#3632A:Zfo\c%!x(S0+6&T46:dYkc!@5 m \  J bUDw9Ivj   &U U U U@& U\#&& c"/   ??99//]3]+++++10]]]]]]]]]]]]]]]! '&5!&'&# '67632!32u u|S8ȟRGL T^~2pkbcU(> @-8HUey\lJ ( 8 l[cU $U U UU@G U"$$ U  U  U ? O  4!+    ??99//]3]]++++++++210]]]]]]]]]]]#"'&547!&'&#"'!2!3276({w LVN]v 8VSO `mWChXT`#@8Y""VuTFVy\IYx Y&@ UU U U U@/ U\%&  U  c$@U@ U   ??9/++]+++++++10]]]]]]]]]]]]]]]]!"'&'&576! &'&#"!3276ڹϧOJMEuאvwۆ~gjTۃxϋD'>!@D\ l ScdU7G[kH9iXf fUZj$#@ U#@ U@U U U U UU@/ U7#$U U U U U U@,UU U?O4"+  ??9/]]++++++++++++++++++10]]]]]]]]]]]]]]#"'&57632&'&#"!3276'u{놀BYYBjITSH"A'vJeeJano`'(  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !.nullnonmarkingreturnmu1pi1OhmEurodmacron overscoremiddotAbreveabreveAogonekaogonekDcarondcaronDslashEogonekeogonekEcaronecaronLacutelacuteLcaronlcaronLdotldotNacutenacuteNcaronncaron Odblacute odblacuteRacuteracuteRcaronrcaronSacutesacuteTcedillatcedillaTcarontcaronUringuring Udblacute udblacuteZacutezacuteZdotzdotGammaThetaPhialphadeltaepsilonsigmatauphi underscoredbl exclamdbl nsuperiorpeseta arrowleftarrowup arrowright arrowdown arrowboth arrowupdn arrowupdnbse orthogonal intersection equivalencehouse revlogicalnot integraltp integralbtSF100000SF110000SF010000SF030000SF020000SF040000SF080000SF090000SF060000SF070000SF050000SF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000upblockdnblockblocklfblockrtblockltshadeshadedkshade filledbox filledrecttriaguptriagrttriagdntriaglfcircle invbullet invcircle smileface invsmilefacesunfemalemalespadeclubheartdiamond musicalnotemusicalnotedblIJij napostropheminutesecond afii61248 afii61289H22073H18543H18551H18533 openbulletAmacronamacron Ccircumflex ccircumflexCdotcdotEmacronemacronEbreveebreveEdotedot Gcircumflex gcircumflexGdotgdotGcedillagcedilla Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonek Jcircumflex jcircumflexKcedillakcedilla kgreenlandicLcedillalcedillaNcedillancedillaEngengOmacronomacronObreveobreveRcedillarcedilla Scircumflex scircumflexTbartbarUtildeutildeUmacronumacronUbreveubreveUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexlongs Aringacute aringacuteAEacuteaeacute Oslashacute oslashacute anoteleiaWgravewgraveWacutewacute Wdieresis wdieresisYgraveygrave quotereversed radicalex afii08941 estimated oneeighth threeeighths fiveeighths seveneighths commaaccentundercommaaccenttonos dieresistonos Alphatonos EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaDeltaEpsilonZetaEtaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosbetagammazetaetathetaiotakappalambdanuxiomicronrhosigma1upsilonchipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonos afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061 afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109 afii10110 afii10193 afii10050 afii10098 afii00208 afii61352sheva hatafsegol hatafpatah hatafqamatshiriqtseresegolpatahqamatsholamqubutsdageshmetegmaqafrafepaseqshindotsindotsofpasuqalefbetgimeldalethevavzayinhettetyodfinalkafkaflamedfinalmemmemfinalnunnunsamekhayinfinalpepe finaltsaditsadiqofreshshintav doublevavvavyod doubleyodgeresh gershayim newsheqelsign vavshindot finalkafshevafinalkafqamats lamedholamlamedholamdageshaltayin shinshindot shinsindotshindageshshindotshindageshsindot alefpatah alefqamats alefmapiq betdagesh gimeldagesh daletdageshhedagesh vavdagesh zayindagesh tetdagesh yoddageshfinalkafdagesh kafdagesh lameddagesh memdagesh nundagesh samekhdagesh finalpedageshpedagesh tsadidagesh qofdagesh reshdagesh shindageshtavdagesvavholambetrafekafrafeperafe aleflamedzerowidthnonjoinerzerowidthjoinerlefttorightmarkrighttoleftmark afii57388 afii57403 afii57407 afii57409 afii57440 afii57451 afii57452 afii57453 afii57454 afii57455 afii57456 afii57457 afii57458 afii57392 afii57393 afii57394 afii57395 afii57396 afii57397 afii57398 afii57399 afii57400 afii57401 afii57381 afii57461 afii63167 afii57459 afii57543 afii57534 afii57494 afii62843 afii62844 afii62845 afii64240 afii64241 afii63954 afii57382 afii64242 afii62881 afii57504 afii57369 afii57370 afii57371 afii57372 afii57373 afii57374 afii57375 afii57391 afii57471 afii57460 afii52258 afii57506 afii62958 afii62956 afii52957 afii57505 afii62889 afii62887 afii62888 afii57507 afii62961 afii62959 afii62960 afii57508 afii62962 afii57567 afii62964 afii52305 afii52306 afii57509 afii62967 afii62965 afii62966 afii57555 afii52364 afii63753 afii63754 afii63759 afii63763 afii63795 afii62891 afii63808 afii62938 afii63810 afii62942 afii62947 afii63813 afii63823 afii63824 afii63833 afii63844 afii62882 afii62883 afii62884 afii62885 afii62886 afii63846 afii63849uni202Auni202Buni202Duni202Euni202Cuni206Euni206F;uni206Auni206Buni206C;uni206DuniF00AuniF00BuniF00CuniF00DuniF00EuniFFFC afii63904 afii63905 afii63906 afii63908 afii63910 afii63912 afii62927 afii63941 afii62939 afii63943 afii62943 afii62946 afii63946 afii62951 afii63948 afii62953 afii63950 afii63951 afii63952 afii63953 afii63956 afii63958 afii63959 afii63960 afii63961 afii64046 afii64058 afii64059 afii64060 afii64061 afii62945 afii64184 afii52399 afii52400 afii62753 afii57411 afii62754 afii57412 afii62755 afii57413 afii62756 afii57414 afii62759 afii62757 afii62758 afii57415 afii62760 afii57416 afii62763 afii62761 afii62762 afii57417 afii62764 afii57418 afii62767 afii62765 afii62766 afii57419 afii62770 afii62768 afii62769 afii57420 afii62773 afii62771 afii62772 afii57421 afii62776 afii62774 afii62775 afii57422 afii62779 afii62777 afii62778 afii57423 afii62780 afii57424 afii62781 afii57425 afii62782 afii57426 afii62783 afii57427 afii62786 afii62784 afii62785 afii57428 afii62789 afii62787 afii62788 afii57429 afii62792 afii62790 afii62791 afii57430 afii62795 afii62793 afii62794 afii57431 afii62798 afii62796 afii62797 afii57432 afii62801 afii62799 afii62800 afii57433 afii62804 afii62802 afii62803 afii57434 afii62807 afii62805 afii62806 afii57441 afii62810 afii62808 afii62809 afii57442 afii62813 afii62811 afii62812 afii57443 afii62816 afii57410 afii62815 afii57444 afii62819 afii62817 afii62818 afii57445 afii62822 afii62820 afii62821 afii57446 afii62825 afii62823 afii62824 afii57447 afii62828 afii57470 afii62827 afii57448 afii62829 afii57449 afii62830 afii57450 afii62833 afii62831 afii62832 afii62834 afii62835 afii62836 afii62837 afii62838 afii62839 afii62840 afii62841 glyph1021 afii57543-2 afii57454-2 afii57451-2 glyph1025 glyph1026 afii57471-2 afii57458-2 afii57457-2 afii57494-2 afii57459-2 afii57455-2 afii57452-2 glyph1034 glyph1035 glyph1036 afii62884-2 afii62881-2 afii62886-2 afii62883-2 afii62885-2 afii62882-2 afii57504-2 afii57456-2 afii57453-2 glyph1046 glyph1047 afii57543-3 afii57454-3 afii57451-3 glyph1051 glyph1052 afii57471-3 afii57458-3 afii57457-3 afii57494-3 afii57459-3 afii57455-3 afii57452-3 glyph1060 glyph1061 glyph1062 afii62884-3 afii62881-3 afii62886-3 afii62883-3 afii62885-3 afii62882-3 afii57504-3 afii57456-3 afii57453-3 glyph1072 glyph1073 afii57543-4 afii57454-4 afii57451-4 glyph1077 glyph1078 afii57471-4 afii57458-4 afii57457-4 afii57494-4 afii57459-4 afii57455-4 afii57452-4 glyph1086 glyph1087 glyph1088 afii62884-4 afii62881-4 afii62886-4 afii62883-4 afii62885-4 afii62882-4 afii57504-4 afii57456-4 afii57453-4 glyph1098 glyph1099 glyph1100 glyph1101 glyph1102 glyph1103 glyph1104 glyph1105 glyph1106 glyph1107 glyph1108 glyph1109 glyph1110 glyph1111 glyph1112 glyph1113 glyph1114 glyph1115 glyph1116 glyph1117 glyph1118 glyph1119 glyph1120 glyph1121 glyph1122 glyph1123 glyph1124 glyph1125 glyph1126 afii57440-2 afii57440-3 afii57440-4OhornohornUhornuhornf006f007f009combininghookabovef010f013f011f01cf015combiningtildeaccentf02cdongsignonethird twothirdsf008f00ff012f014f016f017f018f019f01af01bf01ef01ff020f021f022combininggraveaccentcombiningacuteaccentf01dcombiningdotbelowf023f029f02af02bf024f025f026f027f028f02df02ef02ff030f031 Adotbelow adotbelow Ahookabove ahookaboveAcircumflexacuteacircumflexacuteAcircumflexgraveacircumflexgraveAcircumflexhookaboveacircumflexhookaboveAcircumflextildeacircumflextildeAcircumflexdotbelowacircumflexdotbelow Abreveacute abreveacute Abrevegrave abrevegraveAbrevehookaboveabrevehookabove Abrevetilde abrevetildeAbrevedotbelowabrevedotbelow Edotbelow edotbelow Ehookabove ehookaboveEtildeetildeEcircumflexacuteecircumflexacuteEcircumflexgraveecircumflexgraveEcircumflexhookaboveecircumflexhookaboveEcircumflextildeecircumflextildeEcircumflexdotbelowecircumflexdotbelow Ihookabove ihookabove Idotbelow idotbelow Odotbelow odotbelow Ohookabove ohookaboveOcircumflexacuteocircumflexacuteOcircumflexgraveocircumflexgraveOcircumflexhookaboveocircumflexhookaboveOcircumflextildeocircumflextildeOcircumflexdotbelowocircumflexdotbelow Ohornacute ohornacute Ohorngrave ohorngraveOhornhookaboveohornhookabove Ohorntilde ohorntilde Ohorndotbelow ohorndotbelow Udotbelow udotbelow Uhookabove uhookabove Uhornacute uhornacute Uhorngrave uhorngraveUhornhookaboveuhornhookabove Uhorntilde uhorntilde Uhorndotbelow uhorndotbelow Ydotbelow ydotbelow Yhookabove yhookaboveYtildeytildeuni01CDuni01CEuni01CFuni01D0uni01D1uni01D2uni01D3uni01D4uni01D5uni01D6uni01D7uni01D8uni01D9uni01DAuni01DBuni01DCuni0492uni0493uni0496uni0497uni049auni049buni049cuni049duni04a2uni04a3uni04aeuni04afuni04b0uni04b1uni04b2uni04b3uni04b8uni04b9uni04bauni04bbuni018funi0259uni04e8uni04e9\ N$7<  h$$7h$9h$:$D:A:E-:H:I:K:L`:M:N:Q`:W:Z:l:m:n:w-;:;A;H;K;L;M;N;O;Q;T;W;Y;e;m<:<><@<A<E<H<K<Lw<M<N<O<Q<T<Y<^<f<l<m<o<q<y===w=w==:w=>w=A=E=F=H=K=Y=Z=\=^w=_w=b=e=f=g=hw=j=mw=u=v=x=yw>M>N>Q>aD>h>m-?A?k@A@H@K@L@M-@T-@Z@_@h@mAEAHAKALAMANAQAYDADHDKDMDNENE[EmFNFQFZF_FhFkFmFqFwH:H>H@HEHMHOHQHYH^HeHoJ}J}JJJJ:wJ>wJ@JAJEJFJHJKJLJMJNJOJYJZJ^`J_JhJwJyK:K>KAKEKFKHKLKMKOKQKTKWKZK`-KqLLLLLL:L>L@LALELHLNLYLZL\L_LbLdLeLfLh`LiLjLkLmLoLsLuLvLxLyMMMMMMMM:wM>MAMEMHMNMWMYM[M\M]M^`M_wM`MaMbMcMdMewMfMgMhwMiMjMkwMoMpMrMsMxMywN:N>NENLNMNQNYNeOAOHOKONOWOhOmPHPZ-SZSm-TwTYV`V:V>V@VAVEVFVHVKVL3VOVQ`VWVYW>W@WAWEWOWYW^W`WeWfWyX:X>X@XEXHXKXLXOXQX^XeXfZaZlZmZq[Z[^[_[`[a[e[f[k[m[n[o[q[t[w[y\Z\[\^\_\`\a\e\f\h\k\l\m\n\q\t\y]]]Z]^]_]a]e]h]k]y^t^w_[_^_`_a_e_l_m_o_q`[`m`q`t-a[a^a_aaaeahakamanaqatdZ-d[-d_dadedhdkdldmdweheqf[fafmh^h`hahehlhmhohqj^jajejljmjojqjyk`khkqkwlllZl^l_l`Dlelhlklmm3m3mmZm[m^m_m`memfmhmjmkmnmwmyn[n^nenlnmnqnyoZo[o_oaohokolonoqp_paphpks_shsmvl`vqww^w_wawewhwlwowyx^x`xexfxlxoxq33``.13 "&+M"9&@M Arial ?ARLR00@   "'6GK|}  LNgi $Xarabinitmedi fina&liga, >>!)/3'-15>"*04'-15`- (,.26-'+-15 X 6  & : &,GHIJKarab ghiB:06 *H '0#10 *H 0` +7R0P0, +7<<<Obsolete>>>0 0 *H ytTA(&Xꠂ800%J8Y]s_]ܣ0  *H 010U VeriSign Trust Network10U VeriSign, Inc.1,0*U #VeriSign Time Stamping Service Root1402U +NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc.0 970512000000Z 040107235959Z010U VeriSign Trust Network10U VeriSign, Inc.1,0*U #VeriSign Time Stamping Service Root1402U +NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc.00  *H 0. h|,-.  WSu3* [4 Z%}XsjxqX)X^-bXq"X/6MJ;"V~!lJGj6 -Ӵ90  *H aU>{ǒ~"Գ+[D x~rȲ㉔LNaﳤF=P4 pV*cyis.(]  γ(y)gBHaSs?OUcc00kzm\obOC0  *H 010U VeriSign Trust Network10U VeriSign, Inc.1,0*U #VeriSign Time Stamping Service Root1402U +NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc.0 010228000000Z 040106235959Z010U VeriSign, Inc.10U VeriSign Trust Network1;09U 2Terms of use at https://www.verisign.com/rpa (c)011'0%UVeriSign Time Stamping Service0"0  *H 0 za벧c+aހ='9)fHOO^/Ǒ{!NXc-)pP햻@۾%BU狙1L$*MhaXr0HO/oc ىʂ{K(Łh@F:?6LTBZze{GT=3*^:.uk=`BO[?"1s+FLmP.K*xt=,G100@+40200+0$http://ocsp.verisign.com/ocsp/status0 U00DU =0;09 `HE0*0(+https://www.verisign.com/rpa0U% 0 +0 U0  *H -Oc`,$R 볼g#F M|z 02h2;'{>! Ř@W%误j;#)]@US6:9ess2үc@0  *H 0p1+0)U "Copyright (c) 1997 Microsoft Corp.10U Microsoft Corporation1!0UMicrosoft Root Authority0 970110070000Z 201231070000Z0p1+0)U "Copyright (c) 1997 Microsoft Corp.10U Microsoft Corporation1!0UMicrosoft Root Authority0"0  *H 0 p;N(x^0ꢩ%_L >|Q`2kBdyvT뜆fkzb#<Ŀ-fh&:, X&F >8,(9IBlUa|`-wL陴d;P1$+=c`Xe7RӿUE:TNzmtN̖ (!W`i7Kc@0  *H  5$w\`2 >:!W,Gb;;Z6Ti$m?̪|1=pjOiCZ Ob{+7%-e%cT!RnC2gl QRǽ0 1 )M[WeIRT(~ū7,zwvj?6A5jj5EZ38nM b T?FUp:uҠ00s a* 0  *H 01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U "Copyright (c) 2000 Microsoft Corp.1#0!UMicrosoft Code Signing PCA0 010329212726Z 020529213726Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U "Copyright (c) 2001 Microsoft Corp.10UMicrosoft Corporation00  *H 0oE1=ćNHV+cD0xrLFfbFnD;GQ^wg"{S*-"|N3va `4;I,َ.-kUnp`/@0<0U0U% 0 +0U@OE{uf50U#0)\3Y}. 4(tr0p1+0)U "Copyright (c) 1997 Microsoft Corp.10U Microsoft Corporation1!0UMicrosoft Root Authorityj Oު@0JUC0A0?=;9http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl0  *H gqMGŽik_&ӞZ'i5+} WK 00j Oު@0  *H 0p1+0)U "Copyright (c) 1997 Microsoft Corp.10U Microsoft Corporation1!0UMicrosoft Root Authority0 001210080000Z 051112080000Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U "Copyright (c) 2000 Microsoft Corp.1#0!UMicrosoft Code Signing PCA0 0  *H  0S 04:/{m7#MҌ4$T~tG2XQ)8~:G9NnT1 :mPJ&?ˏIm>U7/`̀aBITJKٓ0ZGudӻݶ Os;:MON3 :doD4J#N`)*򄚙 p{4Af\3T?=tC9泬Hzk*ba9vn>KFGO%(0$0U% 0 +0U0[pir#Q~Mˡr0p1+0)U "Copyright (c) 1997 Microsoft Corp.10U Microsoft Corporation1!0UMicrosoft Root Authority<<>c@0 +70U)\3Y}. 4(0 +7  SubCA0 UF0U00  *H EXAHwwW_Ej9Y'-M88d"B߹/*Ϸ*|Q="mD_ddĩ,ې7Javv%$VT:>Ky_I^2i:TuMd0wz0>MLQ TS ۲9nDGLTזUs2uuIdsV/ǀ]VM= L0H *H  19050010U VeriSign Trust Network10U VeriSign, Inc.1,0*U #VeriSign Time Stamping Service Root1402U +NO LIABILITY ACCEPTED, (c)97 VeriSign, Inc.zm\obOC0 *H Y0 *H  1  *H 0 *H  1 011109205623Z0 *H  18{Lf>0  *H IV5;n ͯ)y7F/PyV/Vhg Sڣ>Oݢ⸻/aUڽ Y5%8]z>/ {Ыm }cÚR #rvi(2$7 B—j j$ZicrkQо|T̫韅[v*T<]D[5_@qݭ(n)A^'3ɎsӴg#]g`\hpH4Legacy/nggallery.php000064400000017123150212230450010443 0ustar00load_options(); $this->define_constant(); $this->define_tables(); $this->load_dependencies(); // Start this plugin once all other plugins are fully loaded. add_action( 'plugins_loaded', [ $this, 'start_plugin' ] ); add_action( 'wpmu_new_blog', [ $this, 'multisite_new_blog' ], 10, 6 ); // Add some links on the plugin page. add_filter( 'plugin_row_meta', [ $this, 'add_plugin_links' ], 10, 2 ); } public function start_plugin() { // Content Filters. add_filter( 'ngg_gallery_name', 'sanitize_title' ); // Check if we are in the admin area. if ( is_admin() ) { if ( get_option( 'ngg_init_check' ) ) { add_action( 'admin_notices', [ $this, 'output_init_check_error' ] ); } } else { $settings = \Imagely\NGG\Settings\Settings::get_instance(); if ( $settings->get( 'useMediaRSS' ) ) { add_action( 'wp_head', [ 'nggMediaRss', 'add_mrss_alternate_link' ] ); } } } public function output_init_check_error() { printf( "

    %s

    ", esc_html( get_option( 'ngg_init_check' ) ) ); } public function define_tables() { global $wpdb; $wpdb->nggpictures = $wpdb->prefix . 'ngg_pictures'; $wpdb->nggallery = $wpdb->prefix . 'ngg_gallery'; $wpdb->nggalbum = $wpdb->prefix . 'ngg_album'; } public function define_constant() { define( 'NGG_LEGACY_MOD_DIR', implode( DIRECTORY_SEPARATOR, [ rtrim( NGG_PLUGIN_DIR, '/\\' ), 'src', basename( __DIR__ ), ] ) ); define( 'NGGVERSION', NGG_PLUGIN_VERSION ); define( 'NGGFOLDER', dirname( NGG_PLUGIN_BASENAME ) ); define( 'NGGALLERY_ABSPATH', rtrim( NGG_LEGACY_MOD_DIR, '/\\' ) . DIRECTORY_SEPARATOR ); define( 'NGGALLERY_URLPATH', plugin_dir_url( __FILE__ ) ); } public function load_dependencies() { // Load global libraries. require_once __DIR__ . '/lib/core.php'; require_once __DIR__ . '/lib/ngg-db.php'; require_once __DIR__ . '/lib/image.php'; require_once __DIR__ . '/lib/tags.php'; require_once __DIR__ . '/lib/post-thumbnail.php'; require_once __DIR__ . '/lib/sitemap.php'; // Load frontend libraries. require_once __DIR__ . '/lib/shortcodes.php'; // We didn't need all stuff during a AJAX operation. if ( defined( 'DOING_AJAX' ) ) { require_once __DIR__ . '/admin/ajax.php'; } else { require_once __DIR__ . '/lib/meta.php'; require_once __DIR__ . '/lib/media-rss.php'; if ( is_admin() && ! $this->is_rest_url() ) { require_once __DIR__ . '/admin/admin.php'; require_once __DIR__ . '/admin/media-upload.php'; $this->nggAdminPanel = new nggAdminPanel(); } } } public function is_rest_url(): bool { return strpos( $_SERVER['REQUEST_URI'], 'wp-json' ) !== false; } public function load_options() { $this->options = get_option( 'ngg_options' ); } public function multisite_new_blog( $blog_id, $user_id, $domain, $path, $site_id, $meta ) { global $wpdb; include_once __DIR__ . '/admin/install.php'; if ( is_plugin_active_for_network( NGG_PLUGIN_BASENAME ) ) { $current_blog = $wpdb->blogid; switch_to_blog( $blog_id ); $installer = new C_NGG_Legacy_Installer(); nggallery_install( $installer ); switch_to_blog( $current_blog ); } } public function add_plugin_links( $links, $file ) { if ( $file == NGG_PLUGIN_BASENAME ) { $links[] = '' . __( 'Get help', 'nggallery' ) . ''; foreach ( $links as $key => $link ) { if ( false !== strpos( $link, 'Imagely' ) ) { $links[$key] = str_replace( 'remove_transients(); if ( is_multisite() ) { $network = isset( $_SERVER['SCRIPT_NAME'] ) ? $_SERVER['SCRIPT_NAME'] : ''; $activate = isset( $_GET['action'] ) ? $_GET['action'] : ''; $isNetwork = $network == '/wp-admin/network/plugins.php'; $isActivation = ! ( ( $activate == 'deactivate' ) ); if ( $isNetwork && $isActivation ) { $old_blog = $wpdb->blogid; // $wpdb->prepare() cannot be used just yet as it only supported the %i placeholder for column names as of // WordPress 6.2 which is newer than NextGEN's current minimum WordPress version. // // TODO: Once NextGEN's minimum WP version is 6.2 or higher use wpdb->prepare() here. // // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $blogids = $wpdb->get_col( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs", null ) ); foreach ( $blogids as $blog_id ) { \switch_to_blog( $blog_id ); \nggallery_install( $this ); } switch_to_blog( $old_blog ); return; } } // remove the update message. delete_option( 'ngg_update_exists' ); nggallery_install( $this ); } public function uninstall( $hard = false ) { include_once 'admin/install.php'; if ( $hard ) { delete_option( 'ngg_init_check' ); delete_option( 'ngg_update_exists' ); delete_option( 'ngg_options' ); delete_option( 'ngg_db_version' ); delete_option( 'ngg_update_exists' ); delete_option( 'ngg_next_update' ); } // now remove the capability. ngg_remove_capability( 'NextGEN Attach Interface' ); ngg_remove_capability( 'NextGEN Change options' ); ngg_remove_capability( 'NextGEN Change style' ); ngg_remove_capability( 'NextGEN Edit album' ); ngg_remove_capability( 'NextGEN Gallery overview' ); ngg_remove_capability( 'NextGEN Manage gallery' ); ngg_remove_capability( 'NextGEN Upload images' ); ngg_remove_capability( 'NextGEN Use TinyMCE' ); ngg_remove_capability( 'NextGEN Manage others gallery' ); ngg_remove_capability( 'NextGEN Manage tags' ); $this->remove_transients(); } public function remove_transients() { global $wpdb, $_wp_using_ext_object_cache; // Fetch all transients $transient_names = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", [ '%' . $wpdb->esc_like( 'ngg_request' ) . '%', ] ) ); // Delete all transients in the database $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", [ '%' . $wpdb->esc_like( 'ngg_request' ) . '%', ] ) ); // If using an external caching mechanism, delete the cached items. if ( $_wp_using_ext_object_cache ) { foreach ( $transient_names as $transient ) { wp_cache_delete( $transient, 'transient' ); wp_cache_delete( substr( $transient, 11 ), 'transient' ); } } } public function upgrade_schema( $sql ) { global $wpdb; // upgrade function changed in WordPress 2.3. require_once ABSPATH . 'wp-admin/includes/upgrade.php'; // add charset & collate like wp core. $charset_collate = ''; if ( version_compare( $wpdb->get_var( 'SELECT VERSION() AS `mysql_version`' ), '4.1.0', '>=' ) ) { if ( ! empty( $wpdb->charset ) ) { $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset"; } if ( ! empty( $wpdb->collate ) ) { $charset_collate .= " COLLATE $wpdb->collate"; } } // Add charset to table creation query. $sql = str_replace( $charset_collate, '', str_replace( ';', '', $sql ) ); // Execute the query. return dbDelta( $sql . ' ' . $charset_collate . ';' ); } } global $ngg; $ngg = new nggLoader(); Legacy/lib/meta.php000064400000044222150212230450010153 0ustar00image = \Imagely\NGG\DataMappers\Image::get_instance()->find( $image_or_id ); } else { $this->image = $image_or_id; } $imagePath = \Imagely\NGG\DataStorage\Manager::get_instance()->get_image_abspath( $this->image ); if ( !file_exists( $imagePath ) ) { return false; } $this->size = @getimagesize( $imagePath, $metadata ); if ($this->size && is_array( $metadata )) { // get exif data if (is_callable( 'exif_read_data' ) && \Imagely\NGG\DataStorage\EXIFWriter::is_jpeg_file( $imagePath )) { $this->exif_data = @exif_read_data( $imagePath, null, true ); } // stop here if we didn't need other meta data if ($onlyEXIF) { return true; } // get the iptc data - should be in APP13 if ( is_callable( 'iptcparse' ) && isset( $metadata['APP13'] ) ) { $this->iptc_data = @iptcparse( $metadata['APP13'] ); } // get the xmp data in a XML format if ( is_callable( 'xml_parser_create' )) { $this->xmp_data = $this->extract_XMP( $imagePath ); } return true; } return false; } /** * return the saved meta data from the database * * @since 1.4.0 * @param string $object (optional) * @return array|mixed return either the complete array or the single object */ function get_saved_meta( $object = false ) { $meta = $this->image->meta_data; // Check if we already import the meta data to the database if (!is_array( $meta ) || !isset( $meta['saved'] ) || ( $meta['saved'] !== true )) { return false; } // return one element if requested if ($object) { return $meta[$object]; } // removed saved parameter we don't need that to show unset( $meta['saved'] ); // and remove empty tags or arrays foreach ($meta as $key => $value) { if ( empty( $value ) or is_array( $value )) { unset( $meta[$key] ); } } // on request sanitize the output if ( $this->sanitize == true ) { array_walk( $meta, 'esc_html' ); } return $meta; } /** * nggMeta::get_EXIF() * See also http://trac.wordpress.org/changeset/6313 * * @return bool|array Structured EXIF data */ function get_EXIF( $object = false ) { if ( !$this->exif_data ) { return false; } if (!is_array( $this->exif_array )) { $meta = array(); $exif = isset( $this->exif_data['EXIF'] ) ? $this->exif_data['EXIF'] : array(); if (count( $exif )) { if (!empty( $exif['FNumber'] )) { $meta['aperture'] = 'F ' . round( $this->exif_frac2dec( $exif['FNumber'] ), 2 ); } if (!empty( $exif['Model'] )) { $meta['camera'] = trim( $exif['Model'] ); } if (!empty( $exif['DateTimeDigitized'] )) { $meta['created_timestamp'] = $this->exif_date2ts( $exif['DateTimeDigitized'] ); } elseif (!empty( $exif['DateTimeOriginal'] )) { $meta['created_timestamp'] = $this->exif_date2ts( $exif['DateTimeOriginal'] ); } elseif (!empty( $exif['FileDateTime'] )) { $meta['created_timestamp'] = $this->exif_date2ts( $exif['FileDateTime'] ); } if (!empty( $exif['FocalLength'] )) { $meta['focal_length'] = $this->exif_frac2dec( $exif['FocalLength'] ) . __( ' mm', 'nggallery' ); } if (!empty( $exif['ISOSpeedRatings'] )) { $meta['iso'] = $exif['ISOSpeedRatings']; } if (!empty( $exif['ExposureTime'] )) { $meta['shutter_speed'] = $this->exif_frac2dec( $exif['ExposureTime'] ); $meta['shutter_speed'] =( $meta['shutter_speed'] > 0.0 and $meta['shutter_speed'] < 1.0 ) ? ( '1/' . round( 1 / $meta['shutter_speed'], -1 ) ) : ( $meta['shutter_speed'] ); $meta['shutter_speed'] .= __( ' sec', 'nggallery' ); } // Bit 0 indicates the flash firing status. On some images taken on older iOS versions, this may be // incorrectly stored as an array. if (isset( $exif['Flash'] ) && is_array( $exif['Flash'] )) { $meta['flash'] = __( 'Fired', 'nggallery' ); } elseif (!empty( $exif['Flash'] )) { $meta['flash'] = ( $exif['Flash'] & 1 ) ? __( 'Fired', 'nggallery' ) : __( 'Not fired', ' nggallery' ); } } // additional information if ( isset( $this->exif_data['IFD0'] ) ) { $exif = $this->exif_data['IFD0']; if (!empty( $exif['Model'] )) { $meta['camera'] = $exif['Model']; } if (!empty( $exif['Make'] )) { $meta['make'] = $exif['Make']; } if (!empty( $exif['ImageDescription'] )) { $meta['title'] = $exif['ImageDescription']; } if (!empty( $exif['Orientation'] )) { $meta['Orientation'] = $exif['Orientation']; } } // this is done by Windows if ( isset( $this->exif_data['WINXP'] ) ) { $exif = $this->exif_data['WINXP']; if (!empty( $exif['Title'] ) && empty( $meta['title'] )) { $meta['title'] = $this->utf8_encode( $exif['Title'] ); } if (!empty( $exif['Author'] )) { $meta['author'] = $this->utf8_encode( $exif['Author'] ); } if (!empty( $exif['Keywords'] )) { $meta['keywords'] = $this->utf8_encode( $exif['Keywords'] ); } if (!empty( $exif['Subject'] )) { $meta['subject'] = $this->utf8_encode( $exif['Subject'] ); } if (!empty( $exif['Comments'] )) { $meta['caption'] = $this->utf8_encode( $exif['Comments'] ); } } $this->exif_array = $meta; } // return one element if requested if ( $object == true ) { $value = isset( $this->exif_array[$object] ) ? $this->exif_array[$object] : false; return $value; } // on request sanitize the output if ( $this->sanitize == true ) { array_walk( $this->exif_array, 'esc_html' ); } return $this->exif_array; } // convert a fraction string to a decimal function exif_frac2dec( $str ) { @list( $n, $d ) = explode( '/', $str ); if ( !empty( $d ) ) { return $n / $d; } return $str; } // convert the exif date format to a unix timestamp function exif_date2ts( $str ) { $retval = is_numeric( $str ) ? $str : @strtotime( $str ); if (!$retval && $str) { @list( $date, $time ) = explode( ' ', trim( $str ) ); @list( $y, $m, $d ) = explode( ':', $date ); $retval = strtotime( "{$y}-{$m}-{$d} {$time}" ); } return $retval; } /** * nggMeta::readIPTC() - IPTC Data Information for EXIF Display * * @param mixed $object (optional) * @return null|bool|array */ function get_IPTC( $object = false ) { if (!$this->iptc_data) { return false; } if (!is_array( $this->iptc_array )) { // --------- Set up Array Functions --------- // $iptcTags = array( "2#005" => 'title', "2#007" => 'status', "2#012" => 'subject', "2#015" => 'category', "2#025" => 'keywords', "2#055" => 'created_date', "2#060" => 'created_time', "2#080" => 'author', "2#085" => 'position', "2#090" => 'city', "2#092" => 'location', "2#095" => 'state', "2#100" => 'country_code', "2#101" => 'country', "2#105" => 'headline', "2#110" => 'credit', "2#115" => 'source', "2#116" => 'copyright', "2#118" => 'contact', "2#120" => 'caption', ); $meta = array(); foreach ($iptcTags as $key => $value) { if (isset( $this->iptc_data[$key] )) { $meta[$value] = trim( $this->utf8_encode( implode( ", ", $this->iptc_data[$key] ) ) ); } } $this->iptc_array = $meta; } // return one element if requested if ($object) { return ( isset( $this->iptc_array[$object] ) ) ? $this->iptc_array[$object] : null; } // on request sanitize the output if ( $this->sanitize == true ) { array_walk( $this->iptc_array, 'esc_html' ); } return $this->iptc_array; } /** * nggMeta::extract_XMP() * get XMP DATA * code by Pekka Saarinen http://photography-on-the.net * * @param mixed $filename * @return bool|string XML data */ function extract_XMP( $filename ) { // TODO:Require a lot of memory, could be better ob_start(); @readfile( $filename ); $source = ob_get_contents(); ob_end_clean(); $start = strpos( $source, "" ); if (( !$start === false ) && ( !$end === false )) { $lenght = $end - $start; $xmp_data = substr( $source, $start, $lenght+12 ); unset( $source ); return $xmp_data; } unset( $source ); return false; } /** * nggMeta::get_XMP() * * @package Taken from http://php.net/manual/en/function.xml-parse-into-struct.php * @author Alf Marius Foss Olsen & Alex Rabe * @return bool|array|object XML Array or object */ function get_XMP( $object = false ) { if (!$this->xmp_data) { return false; } if (!is_array( $this->xmp_array )) { $parser = xml_parser_create(); xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 ); // Dont mess with my cAsE sEtTings xml_parser_set_option( $parser, XML_OPTION_SKIP_WHITE, 1 ); // Dont bother with empty info xml_parse_into_struct( $parser, $this->xmp_data, $values ); xml_parser_free( $parser ); $xmlarray = array(); // The XML array $this->xmp_array = array(); // The returned array $stack = array(); // tmp array used for stacking $list_array = array(); // tmp array for list elements $list_element = false; // rdf:li indicator foreach ($values as $val) { if ($val['type'] == "open") { array_push( $stack, $val['tag'] ); } elseif ($val['type'] == "close") { // reset the compared stack if ($list_element == false) { array_pop( $stack ); } // reset the rdf:li indicator & array $list_element = false; $list_array = array(); } elseif ($val['type'] == "complete") { if ($val['tag'] == "rdf:li") { // first go one element back if ($list_element == false) { array_pop( $stack ); } $list_element = true; // do not parse empty tags if ( empty( $val['value'] ) ) { continue; } // save it in our temp array $list_array[] = $val['value']; // in the case it's a list element we seralize it $value = implode( ",", $list_array ); $this->setArrayValue( $xmlarray, $stack, $value ); } else { array_push( $stack, $val['tag'] ); // do not parse empty tags if ( !empty( $val['value'] ) ) { $this->setArrayValue( $xmlarray, $stack, $val['value'] ); } array_pop( $stack ); } } } // foreach // don't parse a empty array if ( empty( $xmlarray ) || empty( $xmlarray['x:xmpmeta'] ) ) { return false; } // cut off the useless tags $xmlarray = $xmlarray['x:xmpmeta']['rdf:RDF']['rdf:Description']; // --------- Some values from the XMP format--------- // $xmpTags = array( 'xap:CreateDate' => 'created_timestamp', 'xap:ModifyDate' => 'last_modfied', 'xap:CreatorTool' => 'tool', 'dc:format' => 'format', 'dc:title' => 'title', 'dc:creator' => 'author', 'dc:subject' => 'keywords', 'dc:description' => 'caption', 'photoshop:AuthorsPosition' => 'position', 'photoshop:City' => 'city', 'photoshop:Country' => 'country', ); foreach ($xmpTags as $key => $value) { // if the kex exist if ( isset( $xmlarray[$key] ) ) { switch ($key) { case 'xap:CreateDate': case 'xap:ModifyDate': $this->xmp_array[$value] = $this->exif_date2ts( $xmlarray[$key] ); break; default: $this->xmp_array[$value] = $xmlarray[$key]; } } } } // return one element if requested if ($object != false ) { return isset( $this->xmp_array[$object] ) ? $this->xmp_array[$object] : false; } // on request sanitize the output if ( $this->sanitize == true ) { array_walk( $this->xmp_array, 'esc_html' ); } return $this->xmp_array; } function setArrayValue( &$array, $stack, $value ) { if ($stack) { $key = array_shift( $stack ); $this->setArrayValue( $array[$key], $stack, $value ); return $array; } else { $array = $value; } return $array; } /** * nggMeta::get_META() - return a meta value form the available list * * @param string $object * @return mixed $value */ function get_META( $object = false ) { if ($value = $this->get_saved_meta( $object )) { return $value; } if ($object == 'created_timestamp' && ( $d = $this->get_IPTC( 'created_date' ) ) && ( $t = $this->get_IPTC( 'created_time' ) )) { return $this->exif_date2ts( $d . ' ' . $t ); } $order = apply_filters( 'ngg_metadata_parse_order', [ 'XMP', 'IPTC', 'EXIF' ] ); foreach ($order as $method) { $method = 'get_' . $method; if (method_exists( $this, $method ) && $value = $this->$method( $object )) { return $value; } } return false; } /** * nggMeta::i8n_name() - localize the tag name * * @param mixed $key * @return string Translated $key */ function i18n_name( $key ) { $tagnames = [ 'aperture' => __( 'Aperture', 'nggallery' ), 'author' => __( 'Author', 'nggallery' ), 'camera' => __( 'Camera', 'nggallery' ), 'caption' => __( 'Caption', 'nggallery' ), 'category' => __( 'Category', 'nggallery' ), 'city' => __( 'City', 'nggallery' ), 'contact' => __( 'Contact', 'nggallery' ), 'copyright' => __( 'Copyright Notice', 'nggallery' ), 'country' => __( 'Country', 'nggallery' ), 'country_code' => __( 'Country code', 'nggallery' ), 'created_date' => __( 'Date Created', 'nggallery' ), 'created_time' => __( 'Time Created', 'nggallery' ), 'created_timestamp' => __( 'Date/Time', 'nggallery' ), 'credit' => __( 'Credit', 'nggallery' ), 'flash' => __( 'Flash', 'nggallery' ), 'focal_length' => __( 'Focal length', 'nggallery' ), 'format' => __( 'Format', 'nggallery' ), 'headline' => __( 'Headline', 'nggallery' ), 'height' => __( 'Image Height', 'nggallery' ), 'iso' => __( 'ISO', 'nggallery' ), 'keywords' => __( 'Keywords', 'nggallery' ), 'last_modfied' => __( 'Last modified', 'nggallery' ), 'location' => __( 'Location', 'nggallery' ), 'make' => __( 'Make', 'nggallery' ), 'position' => __( 'Author Position', 'nggallery' ), 'shutter_speed' => __( 'Shutter speed', 'nggallery' ), 'source' => __( 'Source', 'nggallery' ), 'state' => __( 'Province/State', 'nggallery' ), 'status' => __( 'Edit Status', 'nggallery' ), 'subject' => __( 'Subject', 'nggallery' ), 'tags' => __( 'Tags', 'nggallery' ), 'title' => __( 'Title', 'nggallery' ), 'tool' => __( 'Program tool', 'nggallery' ), 'width' => __( 'Image Width', 'nggallery' ), ]; if ( isset( $tagnames[$key] ) ) { $key = $tagnames[$key]; } return( $key ); } /** * Return the Timestamp from the image , if possible it's read from exif data * * @return string */ function get_date_time() { $date = $this->exif_date2ts( $this->get_META( 'created_timestamp' ) ); if (!$date) { $image_path = \Imagely\NGG\DataStorage\Manager::get_instance()->get_backup_abspath( $this->image ); if (file_exists( $image_path )) { $date = filectime( $image_path ); } } // Fallback if (!$date) { $date = time(); } // Return the MySQL format $date_time = gmdate( 'Y-m-d H:i:s', $date ); return $date_time; } /** * This function return the most common metadata, via a filter we can add more * Reason : GD manipulation removes that options * * @since V1.4.0 * @return bool|array */ function get_common_meta() { global $wpdb; $meta = array( 'aperture' => 0, 'credit' => '', 'camera' => '', 'caption' => '', 'created_timestamp' => 0, 'copyright' => '', 'focal_length' => 0, 'iso' => 0, 'shutter_speed' => 0, 'flash' => 0, 'title' => '', 'keywords' => '', ); $meta = apply_filters( 'ngg_read_image_metadata', $meta ); // meta should be still an array if ( !is_array( $meta ) ) { return false; } foreach ($meta as $key => $value) { $meta[$key] = $this->get_META( $key ); } // let's add now the size of the image $meta['width'] = $this->size[0]; $meta['height'] = $this->size[1]; return $meta; } /** * If needed sanitize each value before output * * @return void */ function sanitize() { $this->sanitize = true; } /** * Wrapper to utf8_encode() that avoids double encoding * * Regex adapted from http://www.w3.org/International/questions/qa-forms-utf-8.en.php * to determine if the given string is already UTF-8. mb_detect_encoding() is not * always available and is limited in accuracy * * @param string $str * @return string */ function utf8_encode( $str ) { $is_utf8 = preg_match( '%^(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*$%xs', $str ); if (!$is_utf8) { utf8_encode( $str ); } return $str; } } Legacy/lib/image.php000064400000003322150212230450010303 0ustar00meta_data = \Imagely\NGG\Util\Serializable::unserialize( $image->meta_data ); $this->_ngiw = new \Imagely\NGG\DataTypes\LegacyImage( $image, null, true ); } public function __set( $name, $value ) { $this->$name = $value; if ($this->_propogate) { $this->_ngiw->__set( $name, $value ); } } public function __isset( $name ) { return $this->_ngiw->__isset( $name ); } public function __unset( $name ) { return $this->_ngiw->__unset( $name ); } public function __get( $name ) { $this->_propogate = false; $this->$name = $this->_ngiw->__get( $name ); $this->_propogate = true; return $this->$name; } function get_thumbcode( $galleryname = '' ) { return $this->_ngiw->get_thumbcode( $galleryname ); } function get_href_link() { return $this->_ngiw->get_href_link(); } function get_href_thumb_link() { return $this->_ngiw->get_href_thumb_link(); } function cached_singlepic_file( $width = '', $height = '', $mode = '' ) { return $this->_ngiw->cached_singlepic_file( $width, $height, $mode ); } function get_tags() { return $this->_ngiw->get_tags(); } function get_permalink() { return $this->_ngiw->get_permalink(); } } Legacy/lib/post-thumbnail.php000064400000017333150212230450012176 0ustar00" * * @param string $content * @return string html output */ function admin_post_thumbnail( $content, $post_id = null ) { if ($post_id == null) { global $post; if ( !is_object( $post ) ) { return $content; } $post_id = $post->ID; } $thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true ); // in the case it's a ngg image it return ngg- if ( strpos( $thumbnail_id, 'ngg-' ) === false) { global $wp_version; if (version_compare( $wp_version, '3.5', '>=' ) && $thumbnail_id <= 0) { $iframe_src = get_upload_iframe_src( 'image', $post_id ); $iframe_src = remove_query_arg( 'TB_iframe', $iframe_src ); $iframe_src = add_query_arg( 'tab', 'nextgen', $iframe_src ); $iframe_src = add_query_arg( 'chromeless', '1', $iframe_src ); $iframe_src = add_query_arg( 'TB_iframe', '1', $iframe_src ); $set_thumbnail_link = '

    %s

    '; $content .= sprintf( $set_thumbnail_link, esc_html__( 'Set NextGEN featured image', 'nggallery' ) ); } return $content; } // cut off the 'ngg-' $thumbnail_id = substr( $thumbnail_id, 4 ); return $this->_wp_post_thumbnail_html( $thumbnail_id ); } /** * Filter for the post content * * @param string $html * @param int $post_id * @param int $post_thumbnail_id * @param string|array $size Optional. Image size. Defaults to 'thumbnail'. * @param string|array $attr Optional. Query string or array of attributes. * @return string html output */ function ngg_post_thumbnail( $html, $post_id, $post_thumbnail_id, $size = 'post-thumbnail', $attr = '' ) { global $post, $_wp_additional_image_sizes; // in the case it's a ngg image it return ngg- if ( strpos( $post_thumbnail_id, 'ngg-' ) === false) { return $html; } // cut off the 'ngg-' $post_thumbnail_id = substr( $post_thumbnail_id, 4 ); // get the options $ngg_options = nggGallery::get_option( 'ngg_options' ); // get the image data $image = nggdb::find_image( $post_thumbnail_id ); if (!$image) { return $html; } $img_src = false; $class = 'wp-post-image ngg-image-' . $image->pid . ' '; if (is_array( $size ) || is_array( $_wp_additional_image_sizes ) && isset( $_wp_additional_image_sizes[$size] )) { $class .= isset( $attr['class'] ) ? esc_attr( $attr['class'] ) : ''; if ( is_array( $size )) { // the parameters is given as an array rather than a predfined image $width = absint( $size[0] ); $height = absint( $size[1] ); if (isset( $size[2] ) && $size[2] === true) { $mode = 'crop'; } elseif (isset( $size[2] )) { $mode = $size[2]; } else { $mode = ''; } } else { $width = absint( $_wp_additional_image_sizes[$size]['width'] ); $height = absint( $_wp_additional_image_sizes[$size]['height'] ); $mode = ( $_wp_additional_image_sizes[$size]['crop'] ) ? 'crop' : ''; } // check fo cached picture if ( $post->post_status == 'publish' ) { $img_src = $image->cached_singlepic_file( $width, $height, $mode ); } // if we didn't use a cached image then we take the on-the-fly mode if ($img_src == false) { $img_src = trailingslashit( home_url() ) . 'index.php?callback=image&pid=' . $image->pid . '&width=' . $width . '&height=' . $height . '&mode=crop'; } } else { $img_src = $image->thumbURL; } $alttext = isset( $attr['alt'] ) ? $attr['alt'] : $image->alttext; $titletext = isset( $attr['title'] ) ? $attr['title'] : $image->title; $html = '' . esc_attr( $alttext ) . ''; return $html; } /** * nggPostThumbnail::ajax_set_post_thumbnail() * * @return void */ function ajax_set_post_thumbnail() { // This function does the following: // 1) Check if the user is logged in and has permission to edit the post // 2) Get the thumbnail id from the POST request. The thumbnail id is actually the NGG image id // 3)] global $post_ID; // check for correct capability if ( ! is_user_logged_in() ) { die( '-1' ); } if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( $_REQUEST['nonce'], 'ngg_set_post_thumbnails' ) ) { die( '-1' ); } // get the post id as global variable, otherwise the ajax_nonce failed later $post_ID = intval( $_REQUEST['post_id'] ); if ( ! current_user_can( 'edit_post', $post_ID ) ) { die( '-1' ); } $thumbnail_id = intval( $_REQUEST['thumbnail_id'] ); // delete the image if ( $thumbnail_id == '-1' ) { delete_post_meta( $post_ID, '_thumbnail_id' ); die( '1' ); } if ( ( $attachment_id = StorageManager::get_instance()->set_post_thumbnail( $post_ID, $thumbnail_id, TRUE ) ) ) { die( strval( $attachment_id ) ); } die( strval( 0 ) ); } /** * Output HTML for the post thumbnail meta-box. * * @see wp-admin\includes\post.php * @param int $thumbnail_id ID of the image used for thumbnail * @return string html output */ function _wp_post_thumbnail_html( $thumbnail_id = null ) { global $_wp_additional_image_sizes, $post_ID; $set_thumbnail_link = '

    %s

    '; $content = sprintf( $set_thumbnail_link, esc_html__( 'Set featured image', 'nggallery' ) ); $image = nggdb::find_image( $thumbnail_id ); $img_src = false; // get the options $ngg_options = nggGallery::get_option( 'ngg_options' ); if ( $image ) { if ( is_array( $_wp_additional_image_sizes ) && isset( $_wp_additional_image_sizes['post-thumbnail'] ) ) { // Use post thumbnail settings if defined $width = absint( $_wp_additional_image_sizes['post-thumbnail']['width'] ); $height = absint( $_wp_additional_image_sizes['post-thumbnail']['height'] ); $mode = $_wp_additional_image_sizes['post-thumbnail']['crop'] ? 'crop' : ''; // check fo cached picture $img_src = $image->cached_singlepic_file( $width, $height, $mode ); } // if we didn't use a cached image then we take the on-the-fly mode if ( $img_src == false ) { $img_src = trailingslashit( home_url() ) . 'index.php?callback=image&pid=' . $image->pid . '&width=' . $width . '&height=' . $height . '&mode=crop'; } $thumbnail_html = '' . $image->alttext . ''; if ( !empty( $thumbnail_html ) ) { $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$post_ID" ); $content = sprintf( $set_thumbnail_link, $thumbnail_html ); $content .= '

    ' . esc_html__( 'Remove featured image' ) . '

    '; } } return $content; } } $nggPostThumbnail = new nggPostThumbnail(); Legacy/lib/gd.thumbnail.inc.php000064400000067257150212230450012366 0ustar00errmsg = ''; $this->error = false; $this->currentDimensions = array(); $this->newDimensions = array(); $this->fileName = $fileName; $this->percent = 100; $this->maxWidth = 0; $this->maxHeight = 0; $this->watermarkImgPath = ''; $this->watermarkText = ''; // check to see if file exists if (!file_exists( $this->fileName )) { $this->errmsg = 'File not found'; $this->error = true; } // check to see if file is readable elseif (!is_readable( $this->fileName )) { $this->errmsg = 'File is not readable'; $this->error = true; } // if there are no errors, determine the file format if ($this->error == false) { @ini_set( 'memory_limit', -1 ); $data = @getimagesize( $this->fileName ); if (isset( $data ) && is_array( $data )) { $extensions = [ IMAGETYPE_GIF => 'GIF', IMAGETYPE_JPEG => 'JPG', IMAGETYPE_PNG => 'PNG', IMAGETYPE_WEBP => 'WEBP', ]; $extension = array_key_exists( $data[2], $extensions ) ? $extensions[$data[2]] : ''; if ($extension) { $this->format = $extension; } else { $this->errmsg = 'Unknown file format'; $this->error = true; } } else { $this->errmsg = 'File is not an image'; $this->error = true; } } // increase memory-limit if possible, GD needs this for large images // @ini_set('memory_limit', '128M'); if ($this->error == false) { // Check memory consumption if file exists $this->checkMemoryForImage( $this->fileName ); } // initialize resources if no errors if ($this->error == false) { switch ($this->format) { case 'GIF': $this->oldImage = ImageCreateFromGif( $this->fileName ); break; case 'JPG': $this->oldImage = ImageCreateFromJpeg( $this->fileName ); break; case 'PNG': $this->oldImage = ImageCreateFromPng( $this->fileName ); break; case 'WEBP': $this->oldImage = imagecreatefromwebp( $this->fileName ); } if (!$this->oldImage) { $this->errmsg = 'Create Image failed. Check memory limit'; $this->error = true; } else { $size = GetImageSize( $this->fileName ); $this->currentDimensions = array( 'width'=>$size[0], 'height'=>$size[1] ); $this->newImage = $this->oldImage; } } if ($this->error == true) { if (!$no_ErrorImage) { $this->showErrorImage(); } return; } } /** * Calculate the memory limit */ function checkMemoryForImage( $filename ) { if ( ( function_exists( 'memory_get_usage' ) ) && ( ini_get( 'memory_limit' ) ) ) { $imageInfo = getimagesize( $filename ); switch ($this->format) { case 'GIF': // measured factor 1 is better $CHANNEL = 1; break; case 'JPG': $CHANNEL = $imageInfo['channels']; break; case 'PNG': // didn't get the channel for png $CHANNEL = 3; break; case 'WEBP': $CHANNEL = $imageInfo['bits']; break; } $MB = 1048576; // number of bytes in 1M $K64 = 65536; // number of bytes in 64K $TWEAKFACTOR = 1.68; // Or whatever works for you $memoryNeeded = round( ( $imageInfo[0] * $imageInfo[1] * $imageInfo['bits'] * $CHANNEL / 8 + $K64 ) * $TWEAKFACTOR ); $memoryNeeded = memory_get_usage() + $memoryNeeded; // get memory limit $memory_limit = ini_get( 'memory_limit' ); // PHP docs : Note that to have no memory limit, set this directive to -1. if ($memory_limit == -1 ) { return; } // Just check megabyte limits, not higher if ( strtolower( substr( $memory_limit, -1 ) ) == 'm' ) { if ($memory_limit != '') { $memory_limit = substr( $memory_limit, 0, -1 ) * 1024 * 1024; } if ($memoryNeeded > $memory_limit) { $memoryNeeded = round( $memoryNeeded / 1024 / 1024, 2 ); $this->errmsg = 'Exceed Memory limit. Require : ' . $memoryNeeded . " MByte"; $this->error = true; } } } return; } /** * Must be called to free up allocated memory after all manipulations are done */ function destruct() { if (is_resource( $this->newImage ) || $this->newImage instanceof GdImage) { @imagedestroy( $this->newImage ); } if (is_resource( $this->oldImage ) || $this->oldImage instanceof GdImage) { @imagedestroy( $this->oldImage ); } if (is_resource( $this->workingImage ) || $this->workingImage instanceof GdImage) { @imagedestroy( $this->workingImage ); } } /** * Returns the current width of the image * * @return int */ function getCurrentWidth() { return $this->currentDimensions['width']; } /** * Returns the current height of the image * * @return int */ function getCurrentHeight() { return $this->currentDimensions['height']; } /** * Calculates new image width * * @param int $width * @param int $height * @return array */ function calcWidth( $width, $height ) { $newWp = ( 100 * $this->maxWidth ) / $width; $newHeight = ( $height * $newWp ) / 100; return array( 'newWidth'=>intval( $this->maxWidth ), 'newHeight'=>intval( $newHeight ) ); } /** * Calculates new image height * * @param int $width * @param int $height * @return array */ function calcHeight( $width, $height ) { $newHp = ( 100 * $this->maxHeight ) / $height; $newWidth = ( $width * $newHp ) / 100; return array( 'newWidth'=>intval( $newWidth ), 'newHeight'=>intval( $this->maxHeight ) ); } /** * Calculates new image size based on percentage * * @param int $width * @param int $height * @return array */ function calcPercent( $width, $height ) { $newWidth = ( $width * $this->percent ) / 100; $newHeight = ( $height * $this->percent ) / 100; return array( 'newWidth'=>intval( $newWidth ), 'newHeight'=>intval( $newHeight ) ); } /** * Calculates new image size based on width and height, while constraining to maxWidth and maxHeight * * @param int $width * @param int $height */ function calcImageSize( $width, $height ) { $newSize = array( 'newWidth'=>$width, 'newHeight'=>$height ); if ($this->maxWidth > 0) { $newSize = $this->calcWidth( $width, $height ); if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) { $newSize = $this->calcHeight( $newSize['newWidth'], $newSize['newHeight'] ); } // $this->newDimensions = $newSize; } if ($this->maxHeight > 0) { $newSize = $this->calcHeight( $width, $height ); if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) { $newSize = $this->calcWidth( $newSize['newWidth'], $newSize['newHeight'] ); } // $this->newDimensions = $newSize; } $this->newDimensions = $newSize; } /** * Calculates new image size based percentage * * @param int $width * @param int $height */ function calcImageSizePercent( $width, $height ) { if ($this->percent > 0) { $this->newDimensions = $this->calcPercent( $width, $height ); } } /** * Displays error image */ function showErrorImage() { header( 'Content-type: image/png' ); $errImg = ImageCreate( 220, 25 ); $bgColor = imagecolorallocate( $errImg, 0, 0, 0 ); $fgColor1 = imagecolorallocate( $errImg, 255, 255, 255 ); $fgColor2 = imagecolorallocate( $errImg, 255, 0, 0 ); imagestring( $errImg, 3, 6, 6, 'Error:', $fgColor2 ); imagestring( $errImg, 3, 55, 6, $this->errmsg, $fgColor1 ); imagepng( $errImg ); imagedestroy( $errImg ); } /** * Resizes image to fixed Width x Height * * @param int $Width * @param int $Height */ function resizeFix( $Width = 0, $Height = 0, $deprecated = 3 ) { $this->newWidth = $Width; $this->newHeight = $Height; if (function_exists( "ImageCreateTrueColor" )) { $this->workingImage = ImageCreateTrueColor( $this->newWidth, $this->newHeight ); } else { $this->workingImage = ImageCreate( $this->newWidth, $this->newHeight ); } // ImageCopyResampled( $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $this->newWidth; $this->currentDimensions['height'] = $this->newHeight; } /** * Resizes image to maxWidth x maxHeight * * @param int $maxWidth * @param int $maxHeight */ function resize( $maxWidth = 0, $maxHeight = 0, $deprecated = 3 ) { $this->maxWidth = $maxWidth; $this->maxHeight = $maxHeight; $this->calcImageSize( $this->currentDimensions['width'], $this->currentDimensions['height'] ); if (function_exists( "ImageCreateTrueColor" )) { $this->workingImage = ImageCreateTrueColor( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } else { $this->workingImage = ImageCreate( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } // ImageCopyResampled( $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $this->newDimensions['newWidth']; $this->currentDimensions['height'] = $this->newDimensions['newHeight']; } /** * Resizes the image by $percent percent * * @param int $percent */ function resizePercent( $percent = 0 ) { $this->percent = $percent; $this->calcImageSizePercent( $this->currentDimensions['width'], $this->currentDimensions['height'] ); if (function_exists( "ImageCreateTrueColor" )) { $this->workingImage = ImageCreateTrueColor( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } else { $this->workingImage = ImageCreate( $this->newDimensions['newWidth'], $this->newDimensions['newHeight'] ); } $this->ImageCopyResampled( $this->workingImage, $this->oldImage, 0, 0, 0, 0, $this->newDimensions['newWidth'], $this->newDimensions['newHeight'], $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $this->newDimensions['newWidth']; $this->currentDimensions['height'] = $this->newDimensions['newHeight']; } /** * Crops the image from calculated center in a square of $cropSize pixels * * @param int $cropSize */ function cropFromCenter( $cropSize ) { if ($cropSize > $this->currentDimensions['width']) { $cropSize = $this->currentDimensions['width']; } if ($cropSize > $this->currentDimensions['height']) { $cropSize = $this->currentDimensions['height']; } $cropX = intval( ( $this->currentDimensions['width'] - $cropSize ) / 2 ); $cropY = intval( ( $this->currentDimensions['height'] - $cropSize ) / 2 ); if (function_exists( "ImageCreateTrueColor" )) { $this->workingImage = ImageCreateTrueColor( $cropSize, $cropSize ); } else { $this->workingImage = ImageCreate( $cropSize, $cropSize ); } $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, $cropX, $cropY, $cropSize, $cropSize, $cropSize, $cropSize ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $cropSize; $this->currentDimensions['height'] = $cropSize; } /** * Advanced cropping function that crops an image using $startX and $startY as the upper-left hand corner. * * @param int $startX * @param int $startY * @param int $width * @param int $height */ function crop( $startX, $startY, $width, $height ) { // make sure the cropped area is not greater than the size of the image if ($width > $this->currentDimensions['width']) { $width = $this->currentDimensions['width']; } if ($height > $this->currentDimensions['height']) { $height = $this->currentDimensions['height']; } // make sure not starting outside the image if (( $startX + $width ) > $this->currentDimensions['width']) { $startX = ( $this->currentDimensions['width'] - $width ); } if (( $startY + $height ) > $this->currentDimensions['height']) { $startY = ( $this->currentDimensions['height'] - $height ); } if ($startX < 0) { $startX = 0; } if ($startY < 0) { $startY = 0; } if (function_exists( "ImageCreateTrueColor" )) { $this->workingImage = ImageCreateTrueColor( $width, $height ); } else { $this->workingImage = ImageCreate( $width, $height ); } $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, $startX, $startY, $width, $height, $width, $height ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $width; $this->currentDimensions['height'] = $height; } /** * Outputs the image to the screen, or saves to $name if supplied. Quality of JPEG images can be controlled with the $quality variable * * @param int $quality * @param string $name */ function show( $quality = 100, $name = '' ) { switch ($this->format) { case 'GIF': if ($name != '') { @ImageGif( $this->newImage, $name ) or $this->error = true; } else { header( 'Content-type: image/gif' ); ImageGif( $this->newImage ); } break; case 'JPG': if ($name != '') { @ImageJpeg( $this->newImage, $name, $quality ) or $this->error = true; } else { header( 'Content-type: image/jpeg' ); ImageJpeg( $this->newImage, null, $quality ); } break; case 'PNG': if ($name != '') { @ImagePng( $this->newImage, $name ) or $this->error = true; } else { header( 'Content-type: image/png' ); ImagePng( $this->newImage ); } break; case 'WEBP': if ($name != '') { $this->error = !@imagewebp( $this->newImage, $name ); } else { header( 'Content-type: image/webp' ); imagewebp( $this->newImage ); } break; } } /** * Saves image as $name (can include file path), with quality of # percent if file is a jpeg * * @param string $name * @param int $quality * @return bool errorstate */ function save( $name, $quality = 100 ) { $this->show( $quality, $name ); if ($this->error == true) { $this->errmsg = 'Create Image failed. Check safe mode settings'; return false; } if ( function_exists( 'do_action' ) ) { do_action( 'ngg_ajax_image_save', $name ); } return true; } /** * Creates Apple-style reflection under image, optionally adding a border to main image * * @param int $percent * @param int $reflection * @param int $white * @param bool $border * @param string $borderColor */ function createReflection( $percent, $reflection, $white, $border = true, $borderColor = '#a4a4a4' ) { $width = $this->currentDimensions['width']; $height = $this->currentDimensions['height']; $reflectionHeight = intval( $height * ( $reflection / 100 ) ); $newHeight = $height + $reflectionHeight; $reflectedPart = $height * ( $percent / 100 ); $this->workingImage = ImageCreateTrueColor( $width, $newHeight ); ImageAlphaBlending( $this->workingImage, true ); $colorToPaint = ImageColorAllocateAlpha( $this->workingImage, 255, 255, 255, 0 ); ImageFilledRectangle( $this->workingImage, 0, 0, $width, $newHeight, $colorToPaint ); imagecopyresampled( $this->workingImage, $this->newImage, 0, 0, 0, $reflectedPart, $width, $reflectionHeight, $width, ( $height - $reflectedPart ) ); $this->imageFlipVertical(); imagecopy( $this->workingImage, $this->newImage, 0, 0, 0, 0, $width, $height ); imagealphablending( $this->workingImage, true ); for ($i=0;$i<$reflectionHeight;$i++) { $colorToPaint = imagecolorallocatealpha( $this->workingImage, 255, 255, 255, ( $i/$reflectionHeight*-1+1 )*$white ); imagefilledrectangle( $this->workingImage, 0, $height+$i, $width, $height+$i, $colorToPaint ); } if ($border == true) { $rgb = $this->hex2rgb( $borderColor, false ); $colorToPaint = imagecolorallocate( $this->workingImage, $rgb[0], $rgb[1], $rgb[2] ); imageline( $this->workingImage, 0, 0, $width, 0, $colorToPaint ); // top line imageline( $this->workingImage, 0, $height, $width, $height, $colorToPaint ); // bottom line imageline( $this->workingImage, 0, 0, 0, $height, $colorToPaint ); // left line imageline( $this->workingImage, $width-1, 0, $width-1, $height, $colorToPaint ); // right line } $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; $this->currentDimensions['width'] = $width; $this->currentDimensions['height'] = $newHeight; } /** * Flip an image. * * @param bool $horz flip the image in horizontal mode * @param bool $vert flip the image in vertical mode */ function flipImage( $horz = false, $vert = false ) { $sx = $vert ? ( $this->currentDimensions['width'] - 1 ) : 0; $sy = $horz ? ( $this->currentDimensions['height'] - 1 ) : 0; $sw = $vert ? -$this->currentDimensions['width'] : $this->currentDimensions['width']; $sh = $horz ? -$this->currentDimensions['height'] : $this->currentDimensions['height']; $this->workingImage = imagecreatetruecolor( $this->currentDimensions['width'], $this->currentDimensions['height'] ); $this->imagecopyresampled( $this->workingImage, $this->oldImage, 0, 0, $sx, $sy, $this->currentDimensions['width'], $this->currentDimensions['height'], $sw, $sh ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; return true; } /** * Rotate an image clockwise or counter clockwise * * @param string $dir Either CW or CCW */ function rotateImage( $dir = 'CW' ) { $angle = ( $dir == 'CW' ) ? 90 : -90; if (function_exists( 'imagerotate' )) { $this->workingImage = imagerotate( $this->oldImage, 360 - $angle, 0 ); // imagerotate() rotates CCW $this->currentDimensions['width'] = imagesx( $this->workingImage ); $this->currentDimensions['height'] = imagesy( $this->workingImage ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; return true; } $this->workingImage = imagecreatetruecolor( $this->currentDimensions['height'], $this->currentDimensions['width'] ); imagealphablending( $this->workingImage, false ); imagesavealpha( $this->workingImage, true ); switch ($angle) { case 90: for ( $x = 0; $x < $this->currentDimensions['width']; $x++ ) { for ( $y = 0; $y < $this->currentDimensions['height']; $y++ ) { if ( !imagecopy( $this->workingImage, $this->oldImage, $this->currentDimensions['height'] - $y - 1, $x, $x, $y, 1, 1 ) ) { return false; } } } break; case -90: for ( $x = 0; $x < $this->currentDimensions['width']; $x++ ) { for ( $y = 0; $y < $this->currentDimensions['height']; $y++ ) { if ( !imagecopy( $this->workingImage, $this->oldImage, $y, $this->currentDimensions['width'] - $x - 1, $x, $y, 1, 1 ) ) { return false; } } } break; default: return false; } $this->currentDimensions['width'] = imagesx( $this->workingImage ); $this->currentDimensions['height'] = imagesy( $this->workingImage ); $this->oldImage = $this->workingImage; $this->newImage = $this->workingImage; return true; } /** * Inverts working image, used by reflection function * * @access private */ function imageFlipVertical() { $x_i = imagesx( $this->workingImage ); $y_i = imagesy( $this->workingImage ); for ($x = 0; $x < $x_i; $x++) { for ($y = 0; $y < $y_i; $y++) { imagecopy( $this->workingImage, $this->workingImage, $x, $y_i - $y - 1, $x, $y, 1, 1 ); } } } /** * Converts hexidecimal color value to rgb values and returns as array/string * * @param string $hex * @param bool $asString * @return array|string */ function hex2rgb( $hex, $asString = false ) { // strip off any leading # if (0 === strpos( $hex, '#' )) { $hex = substr( $hex, 1 ); } elseif (0 === strpos( $hex, '&H' )) { $hex = substr( $hex, 2 ); } // break into hex 3-tuple $cutpoint = ceil( strlen( $hex ) / 2 )-1; $rgb = explode( ':', wordwrap( $hex, $cutpoint, ':', $cutpoint ), 3 ); // convert each tuple to decimal $rgb[0] = ( isset( $rgb[0] ) ? hexdec( $rgb[0] ) : 0 ); $rgb[1] = ( isset( $rgb[1] ) ? hexdec( $rgb[1] ) : 0 ); $rgb[2] = ( isset( $rgb[2] ) ? hexdec( $rgb[2] ) : 0 ); return ( $asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb ); } /** * Based on the Watermark function by Marek Malcherek * http://www.malcherek.de * * @param string $color * @param string $wmFont * @param int $wmSize * @param int $wmOpaque */ function watermarkCreateText( $color, $wmFont, $wmSize = 10, $wmOpaque = 90 ) { if ( empty( $this->watermarkText ) ) { return; } if (!$color) { $color = '000000'; } // set font path $wmFontPath = NGGALLERY_ABSPATH . "fonts/" . $wmFont; if ( !is_readable( $wmFontPath )) { return; } // This function requires both the GD library and the FreeType library. if ( !function_exists( 'ImageTTFBBox' ) ) { return; } $TextSize = @ImageTTFBBox( $wmSize, 0, $wmFontPath, $this->watermarkText ) or die; $TextWidth = abs( $TextSize[2] ) + abs( $TextSize[0] ); $TextHeight = abs( $TextSize[7] ) + abs( $TextSize[1] ); // Create Image for Text $this->workingImage = ImageCreateTrueColor( $TextWidth, $TextHeight ); ImageSaveAlpha( $this->workingImage, true ); ImageAlphaBlending( $this->workingImage, false ); $bgText = imagecolorallocatealpha( $this->workingImage, 255, 255, 255, 127 ); imagefill( $this->workingImage, 0, 0, $bgText ); $wmTransp = 127 -( $wmOpaque * 1.27 ); $rgb = $this->hex2rgb( $color, false ); $TextColor = imagecolorallocatealpha( $this->workingImage, $rgb[0], $rgb[1], $rgb[2], $wmTransp ); // Create Text on image imagettftext( $this->workingImage, $wmSize, 0, 0, abs( $TextSize[5] ), $TextColor, $wmFontPath, $this->watermarkText ); $this->watermarkImgPath = $this->workingImage; return; } /** * Modfied Watermark function by Steve Peart * http://parasitehosting.com/ * * @param string $relPOS * @param int $xPOS * @param int $yPOS */ function watermarkImage( $relPOS = 'botRight', $xPOS = 0, $yPOS = 0 ) { // if it's a resource ID take it as watermark text image if (is_resource( $this->watermarkImgPath ) || $this->watermarkImgPath instanceof GdImage) { $this->workingImage = $this->watermarkImgPath; } else { // Would you really want to use anything other than a png? $this->workingImage = @imagecreatefrompng( $this->watermarkImgPath ); // if it's not a valid file die... if (empty( $this->workingImage ) or ( !$this->workingImage )) { return; } } imagealphablending( $this->workingImage, false ); imagesavealpha( $this->workingImage, true ); $sourcefile_width =imageSX( $this->oldImage ); $sourcefile_height =imageSY( $this->oldImage ); $watermarkfile_width =imageSX( $this->workingImage ); $watermarkfile_height =imageSY( $this->workingImage ); switch (substr( $relPOS, 0, 3 )) { case 'top': $dest_y = 0 + $yPOS; break; case 'mid': $dest_y = ( $sourcefile_height / 2 ) - ( $watermarkfile_height / 2 ); break; case 'bot': $dest_y = $sourcefile_height - $watermarkfile_height - $yPOS; break; default: $dest_y = 0; break; } switch (substr( $relPOS, 3 )) { case 'Left': $dest_x = 0 + $xPOS; break; case 'Center': $dest_x = ( $sourcefile_width / 2 ) - ( $watermarkfile_width / 2 ); break; case 'Right': $dest_x = $sourcefile_width - $watermarkfile_width - $xPOS; break; default: $dest_x = 0; break; } // debug // $this->errmsg = 'X '.$dest_x.' Y '.$dest_y; // $this->showErrorImage(); // if a gif, we have to upsample it to a truecolor image if ($this->format == 'GIF') { $tempimage = imagecreatetruecolor( $sourcefile_width, $sourcefile_height ); imagecopy( $tempimage, $this->oldImage, 0, 0, 0, 0, $sourcefile_width, $sourcefile_height ); $this->newImage = $tempimage; } imagecopy( $this->newImage, $this->workingImage, $dest_x, $dest_y, 0, 0, $watermarkfile_width, $watermarkfile_height ); } /** * Modfied imagecopyresampled function to save transparent images * See : http://www.akemapa.com/2008/07/10/php-gd-resize-transparent-image-png-gif/ * * @since 1.9.0 * * @param resource $dst_image * @param resource $src_image * @param int $dst_x * @param int $dst_y * @param int $src_x * @param int $src_y * @param int $dst_w * @param int $dst_h * @param int $src_w * @param int $src_h * @return bool */ function imagecopyresampled( &$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) { // Check if this image is PNG or GIF, then set if Transparent if ( $this->format == 'GIF' || $this->format == 'PNG') { imagealphablending( $dst_image, false ); imagesavealpha( $dst_image, true ); $transparent = imagecolorallocatealpha( $dst_image, 255, 255, 255, 127 ); imagefilledrectangle( $dst_image, 0, 0, $dst_w, $dst_h, $transparent ); } imagecopyresampled( $dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); return true; } } Legacy/lib/tags.php000064400000022747150212230450010173 0ustar00 'ok', 'message' => '', ); if ( trim( str_replace( ',', '', stripslashes( $new ) ) ) == '' ) { $return_value['message'] = __( 'No new tag specified!', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } // String to array $old_tags = explode( ',', $old ); $new_tags = explode( ',', $new ); // Remove empty element and trim $old_tags = array_filter( $old_tags, 'nggtags_delete_empty_element' ); $new_tags = array_filter( $new_tags, 'nggtags_delete_empty_element' ); // If old/new tag are empty => exit ! if ( empty( $old_tags ) || empty( $new_tags ) ) { $return_value['message'] = __( 'No new/old valid tag specified!', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } $counter = 0; if ( count( $old_tags ) == count( $new_tags ) ) { // Rename only foreach ( (array) $old_tags as $i => $old_tag ) { $new_name = $new_tags[$i]; // Get term by name $term = get_term_by( 'name', $old_tag, 'ngg_tag' ); if ( !$term ) { continue; } // Get objects from term ID $objects_id = get_objects_in_term( $term->term_id, 'ngg_tag', array( 'fields' => 'all_with_object_id' ) ); // Delete old term wp_delete_term( $term->term_id, 'ngg_tag' ); // Set objects to new term ! (Append no replace) foreach ( (array) $objects_id as $object_id ) { wp_set_object_terms( $object_id, $new_name, 'ngg_tag', true ); } // Clean cache clean_object_term_cache( $objects_id, 'ngg_tag' ); clean_term_cache( $term->term_id, 'ngg_tag' ); // Increment ++$counter; } if ( $counter == 0 ) { $return_value['message'] = __( 'No tag renamed.', 'nggallery' ); } else { $return_value['message'] = sprintf( __( 'Renamed tag(s) «%1$s» to «%2$s»', 'nggallery' ), $old, $new ); } } elseif ( count( $new_tags ) == 1 ) { // Merge // Set new tag $new_tag = $new_tags[0]; if ( empty( $new_tag ) ) { $return_value['message'] = __( 'No valid new tag.', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } // Get terms ID from old terms names $terms_id = array(); foreach ( (array) $old_tags as $old_tag ) { $term = get_term_by( 'name', addslashes( $old_tag ), 'ngg_tag' ); $terms_id[] = (int) $term->term_id; } // Get objects from terms ID $objects_id = get_objects_in_term( $terms_id, 'ngg_tag', array( 'fields' => 'all_with_object_id' ) ); // No objects ? exit ! if ( !$objects_id ) { $return_value['message'] = __( 'No objects (post/page) found for specified old tags.', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } // Delete old terms foreach ( (array) $terms_id as $term_id ) { wp_delete_term( $term_id, 'ngg_tag' ); } // Set objects to new term ! (Append no replace) foreach ( (array) $objects_id as $object_id ) { wp_set_object_terms( $object_id, $new_tag, 'ngg_tag', true ); ++$counter; } // Test if term is also a category if ( term_exists( $new_tag, 'category' ) ) { // Edit the slug to use the new term $slug = sanitize_title( $new_tag ); self::edit_tag_slug( $new_tag, $slug ); unset( $slug ); } // Clean cache clean_object_term_cache( $objects_id, 'ngg_tag' ); clean_term_cache( $terms_id, 'ngg_tag' ); if ( $counter == 0 ) { $return_value['message'] = __( 'No tag merged.', 'nggallery' ); } else { $return_value['message'] = sprintf( __( 'Merge tag(s) «%1$s» to «%2$s». %3$s objects edited.', 'nggallery' ), $old, $new, $counter ); } } else { // Error $return_value['message'] = sprintf( __( 'Error. Not enough tags provided to rename or merge.', 'nggallery' ), $old ); $return_value['status'] = 'error'; } do_action( 'ngg_manage_tags', $new_tags ); return $return_value; } /** * Delete tags */ static function delete_tags( $delete ) { $return_value = array( 'status' => 'ok', 'message' => '', ); if ( trim( str_replace( ',', '', stripslashes( $delete ) ) ) == '' ) { $return_value['message'] = __( 'No tag specified!', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } // In array + filter $delete_tags = explode( ',', $delete ); $delete_tags = array_filter( $delete_tags, 'nggtags_delete_empty_element' ); // Delete tags $counter = 0; foreach ( (array) $delete_tags as $tag ) { $term = get_term_by( 'name', $tag, 'ngg_tag' ); $term_id = (int) $term->term_id; if ( $term_id != 0 ) { wp_delete_term( $term_id, 'ngg_tag' ); clean_term_cache( $term_id, 'ngg_tag' ); ++$counter; } } if ( $counter == 0 ) { $return_value['message'] = __( 'No tag deleted.', 'nggallery' ); } else { $return_value['message'] = sprintf( __( '%1s tag(s) deleted.', 'nggallery' ), $counter ); } do_action( 'ngg_manage_tags', $delete_tags ); return $return_value; } /** * Edit tag slug given the name of the tag */ static function edit_tag_slug( $names = '', $slugs = '' ) { $return_value = array( 'status' => 'ok', 'message' => '', ); if ( trim( str_replace( ',', '', stripslashes( $slugs ) ) ) == '' ) { $return_value['message'] = __( 'No new slug(s) specified!', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } $match_names = explode( ',', $names ); $new_slugs = explode( ',', $slugs ); $match_names = array_filter( $match_names, 'nggtags_delete_empty_element' ); $new_slugs = array_filter( $new_slugs, 'nggtags_delete_empty_element' ); if ( count( $match_names ) != count( $new_slugs ) ) { $return_value['message'] = __( 'Tags number and slugs number isn\'t the same!', 'nggallery' ); $return_value['status'] = 'error'; return $return_value; } else { $counter = 0; foreach ( (array) $match_names as $i => $match_name ) { // Sanitize slug + Escape $new_slug = sanitize_title( $new_slugs[$i] ); // Get term by name $term = get_term_by( 'name', $match_name, 'ngg_tag' ); if ( !$term ) { continue; } // Increment ++$counter; // Update term wp_update_term( $term->term_id, 'ngg_tag', array( 'slug' => $new_slug ) ); // Clean cache clean_term_cache( $term->term_id, 'ngg_tag' ); } } if ( $counter == 0 ) { $return_value['message'] = __( 'No slug edited.', 'nggallery' ); } else { $return_value['message'] = sprintf( __( '%s slug(s) edited.', 'nggallery' ), $counter ); } return $return_value; } /** * Get a list of the tags used by the images */ static function find_all_tags() { return get_terms( 'ngg_tag', '' ); } /** * */ static function find_tags( $args = '', $skip_cache = false ) { $taxonomy = 'ngg_tag'; if ( $skip_cache == true ) { $terms = get_terms( $taxonomy, $args ); } else { $key = md5( serialize( $args ) ); // Get cache if exist // -- if ( $cache = wp_cache_get( 'ngg_get_tags', 'nggallery' ) ) { if ( isset( $cache[$key] ) ) { return apply_filters( 'get_tags', $cache[$key], $args ); } } // Get tags // -- $terms = get_terms( $taxonomy, $args ); if ( empty( $terms ) ) { return array(); } $cache[$key] = $terms; wp_cache_set( 'ngg_get_tags', $cache, 'nggallery' ); } $terms = apply_filters( 'get_tags', $terms, $args ); return $terms; } /** * Get images corresponding to a list of tags * * nggTags::find_images_for_tags() * * @param mixed $taglist * @param string $mode could be 'ASC', 'DESC' or 'RAND' * * @return array of images */ static function find_images_for_tags( $taglist, $mode = "ASC" ) { // return the images based on the tag global $wpdb; // extract it into a array $taglist = explode( ",", $taglist ); if ( ! is_array( $taglist ) ) { $taglist = array( $taglist ); } $taglist = array_map( 'trim', $taglist ); $new_slugarray = array_map( 'sanitize_title', $taglist ); $sluglist = implode( "', '", $new_slugarray ); // Treat % as a literal in the database, for unicode support $sluglist = str_replace( "%", "%%", $sluglist ); // first get all $term_ids with this tag $term_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug IN (%s) ORDER BY term_id ASC ", $sluglist ) ); $picids = get_objects_in_term( $term_ids, 'ngg_tag' ); if ( $mode == 'RAND' ) { shuffle( $picids ); } // Now lookup in the database $mapper = \Imagely\NGG\DataMappers\Image::get_instance(); $images = array(); foreach ( $picids as $image_id ) { $images[] = $mapper->find( $image_id ); } if ( 'DESC' == $mode ) { $images = array_reverse( $images ); } return $images; } } /** * trim and remove empty element * * @param string $element * @return null|string */ if (!function_exists( 'nggtags_delete_empty_element' )) { function nggtags_delete_empty_element( $element ) { $element = stripslashes( $element ); $element = trim( $element ); if (!empty( $element )) { return $element; } return null; } } Legacy/lib/sitemap.php000064400000006633150212230450010673 0ustar00images = $images; // first get the content of the post/page $p = get_post( $post_id ); // Backward check for older images $p->post_content = NextGEN_shortcodes::convert_shortcode( $p->post_content ); // Don't process the images in the normal way remove_all_shortcodes(); // We cannot parse at this point a album, just galleries & single images \Imagely\NGG\Display\Shortcodes::add( 'singlepic', array( &$this, 'add_images' ) ); \Imagely\NGG\Display\Shortcodes::add( 'thumb', array( &$this, 'add_images' ) ); \Imagely\NGG\Display\Shortcodes::add( 'nggallery', array( &$this, 'add_gallery' ) ); \Imagely\NGG\Display\Shortcodes::add( 'imagebrowser', array( &$this, 'add_gallery' ) ); \Imagely\NGG\Display\Shortcodes::add( 'slideshow', array( &$this, 'add_gallery' ) ); // Search now for shortcodes do_shortcode( $p->post_content ); return $this->images; } /** * Parse the gallery/imagebrowser/slideshow shortcode and return all images into an array * * @TODO: replace or remove this function, it's return value isn't even linked to the queries it performs * @param string $atts * @return string */ function add_gallery( $atts ) { global $wpdb; $tmp = shortcode_atts( array( 'id' => 0 ), $atts, 'ngg' ); extract( $tmp ); $gallery_mapper = \Imagely\NGG\DataMappers\Gallery::get_instance(); if (!is_numeric( $id )) { $tmp = $gallery_mapper->select()->where( array( 'name = %s', $id ) )->limit( 1 )->run_query(); if (( $gallery = array_shift( $tmp ) )) { $id = $gallery->{$gallery->id_field}; } else { $id = null; } } if ($id) { $gallery_storage = \Imagely\NGG\DataStorage\Manager::get_instance(); $image_mapper = \Imagely\NGG\DataMappers\Image::get_instance(); foreach ($image_mapper->find_all_for_gallery( $id ) as $image) { $this->images[] = array( 'src' => $gallery_storage->get_image_url( $image ), 'title' => $image->title, 'alt' => $image->alttext, ); } } return ''; } /** * Parse the single image shortcode and return all images into an array * * @param array $atts * @return string */ function add_images( $atts ) { $tmp = shortcode_atts( array( 'id' => 0 ), $atts, 'ngg' ); extract( $tmp ); // make an array out of the ids (for thumbs shortcode)) $pids = explode( ',', $id ); // Some error checks if ( count( $pids ) == 0 ) { return ''; } $images = nggdb::find_images_in_list( $pids ); foreach ($images as $image) { $newimage = array(); $newimage['src'] = $newimage['sc'] = $image->imageURL; if ( !empty( $image->title ) ) { $newimage['title'] = $image->title; } if ( !empty( $image->alttext ) ) { $newimage['alt'] = $image->alttext; } $this->images[] = $newimage; } return ''; } } $nggSitemaps = new nggSitemaps(); Legacy/lib/media-rss.php000064400000021215150212230450011106 0ustar00\n"; } /** * Get the URL of the general media RSS */ public static function get_mrss_url(): string { return NGGALLERY_URLPATH . 'xml/media-rss.php'; } /** * Get the URL of a gallery media RSS */ public static function get_gallery_mrss_url( $gid, $prev_next = false ): string { return self::get_mrss_url() . '?' . ( 'gid=' . $gid . ( $prev_next ? '&prev_next=true' : '' ) . '&mode=gallery' ); } /** * Get the URL of the media RSS for last pictures */ public static function get_last_pictures_mrss_url( $page = 0, $show = 30 ): string { return self::get_mrss_url() . '?' . ( 'show=' . $show . '&page=' . $page . '&mode=last_pictures' ); } /** * Get the XML node corresponding to the last pictures registered * * @param int $page The current page (defaults to 0) * @param int $show The number of pictures to include in one field (default 30) */ public static function get_last_pictures_mrss( $page = 0, $show = 30 ) { $images = nggdb::find_last_images( $page, $show ); $title = stripslashes( get_option( 'blogname' ) ); $description = stripslashes( get_option( 'blogdescription' ) ); $link = site_url(); $prev_link = ( $page > 0 ) ? self::get_last_pictures_mrss_url( $page-1, $show ) : ''; $next_link = count( $images )!=0 ? self::get_last_pictures_mrss_url( $page+1, $show ) : ''; return self::get_mrss_root_node( $title, $description, $link, $prev_link, $next_link, $images ); } /** * Get the XML node corresponding to a gallery * * @param $gallery (object) The gallery to include in RSS * @param $prev_gallery (object) The previous gallery to link in RSS (null if none) * @param $next_gallery (object) The next gallery to link in RSS (null if none) */ public static function get_gallery_mrss( $gallery, $prev_gallery = null, $next_gallery = null ) { $ngg_options = nggGallery::get_option( 'ngg_options' ); // Set sort order value, if not used (upgrade issue) $ngg_options['galSort'] = ( $ngg_options['galSort'] ) ? $ngg_options['galSort'] : 'pid'; $ngg_options['galSortDir'] = ( $ngg_options['galSortDir'] == 'DESC' ) ? 'DESC' : 'ASC'; $title = stripslashes( \Imagely\NGG\Display\I18N::translate( $gallery->title ) ); $description = stripslashes( \Imagely\NGG\Display\I18N::translate( $gallery->galdesc ) ); $link = self::get_permalink( $gallery->pageid ); $prev_link = ( $prev_gallery != null ) ? self::get_gallery_mrss_url( $prev_gallery->gid, true ) : ''; $next_link = ( $next_gallery != null ) ? self::get_gallery_mrss_url( $next_gallery->gid, true ) : ''; $images = nggdb::get_gallery( $gallery->gid, $ngg_options['galSort'], $ngg_options['galSortDir'] ); return self::get_mrss_root_node( $title, $description, $link, $prev_link, $next_link, $images ); } /** * Get the XML node corresponding to an album * * @param object $album The album to include in RSS */ public static function get_album_mrss( $album ) { $nggdb = new nggdb(); $title = stripslashes( \Imagely\NGG\Display\I18N::translate( $album->name ) ); $description = ''; $link = self::get_permalink( 0 ); $prev_link = ''; $next_link = ''; $images = $nggdb->find_images_in_album( $album->id ); return self::get_mrss_root_node( $title, $description, $link, $prev_link, $next_link, $images ); } /** * Get the XML node */ public static function get_mrss_root_node( $title, $description, $link, $prev_link, $next_link, $images ) { if ($prev_link != '' || $next_link != '') { $out = "\n"; } else { $out = "\n"; } $out .= "\t\n"; $out .= self::get_generator_mrss_node(); $out .= self::get_title_mrss_node( $title ); $out .= self::get_description_mrss_node( $description ); $out .= self::get_link_mrss_node( $link ); if ($prev_link != '' || $next_link != '') { $out .= self::get_self_node( self::get_mrss_url() ); } if ($prev_link!='') { $out .= self::get_previous_link_mrss_node( $prev_link ); } if ($next_link!='') { $out .= self::get_next_link_mrss_node( $next_link ); } foreach ($images as $image) { $out .= self::get_image_mrss_node( $image ); } $out .= "\t\n"; $out .= "\n"; return $out; } /** * Get the XML node */ public static function get_generator_mrss_node( $indent = "\t\t" ) { return $indent . "\n"; } /** * Get the XML node */ public static function get_title_mrss_node( $title, $indent = "\t\t" ) { return $indent . "<title>" . $title . "\n"; } /** * Get the XML node */ public static function get_description_mrss_node( $description, $indent = "\t\t" ) { return $indent . "" . $description . "\n"; } /** * Get the XML node */ public static function get_link_mrss_node( $link, $indent = "\t\t" ) { return $indent . "\n"; } /** * Get the XML node */ public static function get_self_node( $link, $indent = "\t\t" ) { return $indent . "\n"; } /** * Get the XML node */ public static function get_previous_link_mrss_node( $link, $indent = "\t\t" ) { return $indent . "\n"; } /** * Get the XML node */ public static function get_next_link_mrss_node( $link, $indent = "\t\t" ) { return $indent . "
    ' . "\n"; } /** * Show a system messages */ static function show_message( $message, $message_id = null ) { echo '

    ' . $message . '

    ' . "\n"; } /** * nggGallery::get_option() - get the options and overwrite them with custom meta settings * * @param string $key * @return array $options */ static function get_option( $key ) { global $post; // get first the options from the database $options = get_option( $key ); if ( $post == null ) { return $options; } // Get all key/value data for the current post. $meta_array = get_post_custom(); // Ensure that this is a array if ( !is_array( $meta_array ) ) { $meta_array = array( $meta_array ); } // assign meta key to db setting key $meta_tags = array( 'string' => array( 'ngg_gal_ShowOrder' => 'galShowOrder', 'ngg_gal_Sort' => 'galSort', 'ngg_gal_SortDirection' => 'galSortDir', 'ngg_gal_ShowDescription' => 'galShowDesc', 'ngg_ir_Audio' => 'irAudio', 'ngg_ir_Overstretch' => 'irOverstretch', 'ngg_ir_Transition' => 'irTransition', 'ngg_ir_Backcolor' => 'irBackcolor', 'ngg_ir_Frontcolor' => 'irFrontcolor', 'ngg_ir_Lightcolor' => 'irLightcolor', 'ngg_slideshowFX' => 'slideFx', ), 'int' => array( 'ngg_gal_Images' => 'galImages', 'ngg_gal_Columns' => 'galColumns', 'ngg_paged_Galleries' => 'galPagedGalleries', 'ngg_ir_Width' => 'irWidth', 'ngg_ir_Height' => 'irHeight', 'ngg_ir_Rotatetime' => 'irRotatetime', ), 'bool' => array( 'ngg_gal_ShowSlide' => 'galShowSlide', 'ngg_gal_ImageBrowser' => 'galImgBrowser', 'ngg_gal_HideImages' => 'galHiddenImg', 'ngg_ir_Shuffle' => 'irShuffle', 'ngg_ir_LinkFromDisplay' => 'irLinkfromdisplay', 'ngg_ir_ShowNavigation' => 'irShownavigation', 'ngg_ir_ShowWatermark' => 'irWatermark', 'ngg_ir_Kenburns' => 'irKenburns', ), ); foreach ($meta_tags as $typ => $meta_keys) { foreach ($meta_keys as $key => $db_value) { // if the kex exist overwrite it with the custom field if (array_key_exists( $key, $meta_array )) { switch ($typ) { case 'string': $options[$db_value] = (string) esc_attr( $meta_array[$key][0] ); break; case 'int': $options[$db_value] = (int) $meta_array[$key][0]; break; case 'bool': $options[$db_value] = (bool) $meta_array[$key][0]; break; } } } } return $options; } /** * Renders a section of user display code. The code is first checked for in the current theme display directory * before defaulting to the plugin * Call the function : nggGallery::render ('template_name', array ('var1' => $var1, 'var2' => $var2)); * * @autor John Godley * @param string $template_name Name of the template file (without extension) * @param string $vars Array of variable name=>value that is available to the display code (optional) * @param bool $callback In case we check we didn't find template we tested it one time more (optional) * @return void **/ static function render( $template_name, $vars = array(), $callback = false ) { $vars['template'] = $template_name; echo \Imagely\NGG\DisplayedGallery\Renderer::get_instance()->display_images( $vars ); } /** * Captures an section of user display code. * * @autor John Godley * @param string $template_name Name of the template file (without extension) * @param string $vars Array of variable name=>value that is available to the display code (optional) * @deprecated Use Imagely\NGG\DisplayedGallery\Renderer class * @return string **/ static function capture( $template_name, $vars = array() ) { $vars['template'] = $template_name; return \Imagely\NGG\DisplayedGallery\Renderer::get_instance()->display_images( $vars ); } /** * Returns the path to lib/gd.thumbnail.inc.php * * @return string Path to the selected library */ static function graphic_library() { return NGGALLERY_ABSPATH . '/lib/gd.thumbnail.inc.php'; } /** * Support for i18n with wpml, polyglot or qtrans * * @param string $in * @param string $name (optional) required for wpml to determine the type of translation * @return string $in localized */ static function i18n( $in, $name = null ) { if ( function_exists( 'langswitch_filter_langs_with_message' ) ) { $in = langswitch_filter_langs_with_message( $in ); } if ( function_exists( 'polyglot_filter' )) { $in = polyglot_filter( $in ); } if ( function_exists( 'qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage' )) { $in = qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage( $in ); } if (is_string( $name ) && !empty( $name ) && function_exists( 'icl_translate' )) { $in = icl_translate( 'plugin_ngg', $name, $in, true ); } $in = apply_filters( 'localization', $in ); return $in; } /** * Check the memory_limit and calculate a recommended memory size * * @since V1.2.0 * @return string message about recommended image size */ static function check_memory_limit() { if ( ( function_exists( 'memory_get_usage' ) ) && ( ini_get( 'memory_limit' ) ) ) { // get memory limit $memory_limit = ini_get( 'memory_limit' ); if ($memory_limit != '') { $memory_limit = substr( $memory_limit, 0, -1 ) * 1024 * 1024; } // calculate the free memory $freeMemory = $memory_limit - memory_get_usage(); // build the test sizes $sizes = array(); $sizes[] = array( 'width' => 800, 'height' => 600 ); $sizes[] = array( 'width' => 1024, 'height' => 768 ); $sizes[] = array( 'width' => 1280, 'height' => 960 ); // 1MP $sizes[] = array( 'width' => 1600, 'height' => 1200 ); // 2MP $sizes[] = array( 'width' => 2016, 'height' => 1512 ); // 3MP $sizes[] = array( 'width' => 2272, 'height' => 1704 ); // 4MP $sizes[] = array( 'width' => 2560, 'height' => 1920 ); // 5MP // test the classic sizes foreach ($sizes as $size) { // very, very rough estimation if ($freeMemory < round( $size['width'] * $size['height'] * 5.09 )) { $result = sprintf( __( 'Note : Based on your server memory limit you should not upload larger images then %d x %d pixel', 'nggallery' ), $size['width'], $size['height'] ); return $result; } } } return ''; } /** * Check for extended capabilites. Must previously registers with add_ngg_capabilites() * * @since 1.5.0 * @param string $capability * @return bool $result of capability check */ static function current_user_can( $capability ) { global $_ngg_capabilites; if ( is_array( $_ngg_capabilites ) ) { if ( in_array( $capability, $_ngg_capabilites ) ) { return current_user_can( $capability ); } } return true; } } Legacy/xml/media-rss.php000064400000007260150212230450011144 0ustar00find_all(); if ( count( $galleries ) == 0 ) { header( 'content-type:text/plain;charset=utf-8' ); print esc_html( __( 'No galleries have been yet created.', 'nggallery' ) ); exit; } // Get additional parameters $gid = isset( $_GET['gid'] ) ? (int) $_GET['gid'] : 0; // if no gid is present, take the first gallery if ( $gid == 0 ) { $first = current( $galleries ); $gid = $first->gid; } // account for the the odd logic used in selecting galleries here if ( $gid == 1 ) { $gid = 0; } elseif ( $gid > 1 ) { --$gid; } // Set the main gallery object $gallery = $galleries[ $gid ]; if ( ! isset( $gallery ) || $gallery == null ) { header( 'content-type:text/plain;charset=utf-8' ); print esc_html( sprintf( __( 'The gallery ID=%s does not exist.', 'nggallery' ), intval( $gid ) ) ); exit; } // show other galleries if needed $prev_next = 'true' === $_GET['prev_next']; $prev_gallery = $next_gallery = null; // Get previous and next galleries if required if ( $prev_next ) { reset( $galleries ); while ( current( $galleries ) ) { if ( key( $galleries ) == $gid ) { break; } next( $galleries ); } // one step back $prev_gallery = prev( $galleries ); // two step forward... Could be easier ? How ? next( $galleries ); $next_gallery = next( $galleries ); } $rss = nggMediaRss::get_gallery_mrss( $gallery, $prev_gallery, $next_gallery ); } elseif ( $mode == 'album' ) { // Get additional parameters $aid = isset( $_GET['aid'] ) ? (int) $_GET['aid'] : 0; if ( $aid == 0 ) { header( 'content-type:text/plain;charset=utf-8' ); print esc_html( __( 'No album ID has been provided as parameter', 'nggallery' ) ); exit; } // Get the album object $nggdb = new nggdb(); $album = $nggdb->find_album( $aid ); if ( ! isset( $album ) || $album == null ) { header( 'content-type:text/plain;charset=utf-8' ); printf( __( 'The album ID=%s does not exist.', 'nggallery' ), intval( $aid ) ); exit; } $rss = nggMediaRss::get_album_mrss( $album ); } else { header( 'content-type:text/plain;charset=utf-8' ); echo __( 'Invalid MediaRSS command', 'nggallery' ); exit; } // Output header for media RSS header( 'content-type:text/xml;charset=utf-8' ); echo "\n"; echo $rss; Legacy/admin/wpmu.php000064400000010414150212230450010533 0ustar00set( $option_name, $option_value ); } if ( isset( $_POST['gallerypath'] ) ) { $new_gallerypath = trailingslashit( $_POST['gallerypath'] ); $fs = \Imagely\NGG\Util\Filesystem::get_instance(); $root = $fs->get_document_root( 'galleries' ); if ( $root[0] != DIRECTORY_SEPARATOR ) { $root = DIRECTORY_SEPARATOR . $root; } $gallery_abspath = $fs->get_absolute_path( $fs->join_paths( $root, $new_gallerypath ) ); if ( $gallery_abspath[0] != DIRECTORY_SEPARATOR ) { $gallery_abspath = DIRECTORY_SEPARATOR . $gallery_abspath; } if ( strpos( $gallery_abspath, $root ) === false ) { $messagetext[] = sprintf( __( 'Gallery path must be located in %s.', 'nggallery' ), $root ); } elseif ( preg_match( '\.+[/\\]', $new_gallerypath ) ) { $messagetext[] = __( 'Gallery path cannot include relative paths.', 'nggallery' ); } else { $ngg_options->set( 'gallerypath', $new_gallerypath ); $ngg_options->save(); } } $ngg_options->save(); $messagetext[] = __( 'Updated successfully.', 'nggallery' ); $messagetext = implode( ' ', $messagetext ); } // message windows. if ( ! empty( $messagetext ) ) { echo '

    ' . esc_html( $messagetext ) . '

    '; } ?>


    wp-content/uploads/sites/%BLOG_ID%/nggallery/', __( 'The default setting should be %s', 'nggallery' ) ); ?>
    : get( 'wpmuQuotaCheck' ) ); ?> />
    : get( 'wpmuZipUpload' ) ); ?> />
    : get( 'wpmuImportFolder' ) ); ?> />
    : get( 'wpmuRoles' ) ); ?> />
    id ) ) { $image = $image->id; } elseif ( isset( $image->pid ) ) { $image = $image->pid; } } $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); // XXX NextGEN Legacy wasn't handling watermarks or reflections at this stage, so we're forcefully disabling them to maintain compatibility. $params = [ 'watermark' => false, 'reflection' => false, ]; $result = $storage->generate_thumbnail( $image, $params ); if ( ! $result ) { // XXX there isn't any error handling unfortunately at the moment in the generate_thumbnail functions, need a way to return proper error status. return __( 'Error while creating thumbnail.', 'nggallery' ); } // success. return '1'; } /** * nggAdmin::resize_image() - create a new image, based on the height /width * * @class nggAdmin * @param object|int $image Contain all information about the image or the id * @param integer $width optional * @param integer $height optional * @return string result code */ static function resize_image( $image, $width = 0, $height = 0 ) { if ( is_object( $image ) ) { if ( isset( $image->id ) ) { $image = $image->id; } elseif ( isset( $image->pid ) ) { $image = $image->pid; } } $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); // XXX maybe get rid of this...it's needed to get width/height defaults, placing these directly in generate_image_size could have unwanted consequences. $settings = \Imagely\NGG\Settings\Settings::get_instance(); // XXX NextGEN Legacy wasn't handling watermarks or reflections at this stage, so we're forcefully disabling them to maintain compatibility. $params = [ 'watermark' => false, 'reflection' => false, ]; if ( $width > 0 ) { $params['width'] = $width; } else { $params['width'] = $settings->get( 'imgWidth' ); } if ( $height > 0 ) { $params['height'] = $height; } else { $params['height'] = $settings->get( 'imgHeight' ); } $result = $storage->generate_image_size( $image, 'full', $params ); if ( ! $result ) { // XXX there isn't any error handling unfortunately at the moment in the generate_thumbnail functions, need a way to return proper error status. return __( 'Error while resizing image.', 'nggallery' ); } // success. return '1'; } /** * Rotated/Flip an image based on the orientation flag or a definded angle * * @param int|object $image * @param string|bool $dir (optional) CW (clockwise)or CCW (counter clockwise), if set to false, the exif flag will be used * @param string|bool $flip (optional) Either false | V (flip vertical) | H (flip horizontal) * @return string result code */ static function rotate_image( $image, $dir = false, $flip = false ) { if ( is_object( $image ) ) { if ( isset( $image->id ) ) { $image = $image->id; } elseif ( isset( $image->pid ) ) { $image = $image->pid; } } $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); // XXX NextGEN Legacy wasn't handling watermarks or reflections at this stage, so we're forcefully disabling them to maintain compatibility. $params = [ 'watermark' => false, 'reflection' => false, ]; $rotation = null; if ( $dir === 'CW' ) { $rotation = 90; } elseif ( $dir === 'CCW' ) { $rotation = -90; } // if you didn't define a rotation, we look for the orientation flag in EXIF. elseif ( $dir === false ) { $meta = new nggMeta( $image ); $exif = $meta->get_EXIF(); if ( isset( $exif['Orientation'] ) ) { switch ( $exif['Orientation'] ) { case 5: // vertical flip + 90 rotate right. $flip = 'V'; case 6: // 90 rotate right $rotation = 90; break; case 7: // horizontal flip + 90 rotate right. $flip = 'H'; case 8: // 90 rotate left. $rotation = -90; break; case 4: // vertical flip. $flip = 'V'; break; case 3: // 180 rotate left. $rotation = -180; break; case 2: // horizontal flip. $flip = 'H'; break; case 1: // no action in the case it doesn't need a rotation. default: return '0'; break; } } else { return '0'; } } if ( $rotation != null ) { $params['rotation'] = $rotation; } if ( $flip != null ) { $params['flip'] = $flip; } $result = $storage->generate_image_size( $image, 'full', $params ); if ( ! $result ) { // XXX there isn't any error handling unfortunately at the moment in the generate_thumbnail functions, need a way to return proper error status. return __( 'Error while rotating image.', 'nggallery' ); } // success. return '1'; } /** * nggAdmin::set_watermark() - set the watermark for the image * * @class nggAdmin * @param object|int $image Contain all information about the image or the id * @return string result code */ static function set_watermark( $image ) { if ( is_object( $image ) ) { if ( isset( $image->id ) ) { $image = $image->id; } elseif ( isset( $image->pid ) ) { $image = $image->pid; } } $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); // XXX NextGEN Legacy was only handling watermarks at this stage, so we're forcefully disabling all else. $params = [ 'watermark' => true, 'reflection' => false, 'crop' => false, ]; $result = $storage->generate_image_size( $image, 'full', $params ); if ( ! $result ) { // XXX there isn't any error handling unfortunately at the moment in the generate_thumbnail functions, need a way to return proper error status. return __( 'Error while applying watermark to image.', 'nggallery' ); } // success. return '1'; } /** * Recover image from backup copy and reprocess it * * @class nggAdmin * @since 1.5.0 * @param object|int $image Contain all information about the image or the id * @return string result code */ static function recover_image( $image ) { return \Imagely\NGG\DataStorage\Manager::get_instance()->recover_image( $image ); } /** * Add images to database * * @class nggAdmin * @param int $galleryID * @param array $imageslist * @return array $image_ids IDs which have been successfully added */ public static function add_Images( $galleryID, $imageslist ) { global $ngg; $image_ids = []; if ( is_array( $imageslist ) ) { foreach ( $imageslist as $picture ) { // filter function to rename/change/modify image before. $picture = apply_filters( 'ngg_pre_add_new_image', $picture, $galleryID ); // strip off the extension of the filename. $path_parts = \Imagely\NGG\Display\I18N::mb_pathinfo( $picture ); $alttext = ( ! isset( $path_parts['filename'] ) ) ? substr( $path_parts['basename'], 0, strpos( $path_parts['basename'], '.' ) ) : $path_parts['filename']; // save it to the database. $pic_id = nggdb::add_image( $galleryID, $picture, '', $alttext ); if ( \Imagely\NGG\Settings\Settings::get_instance()->imgBackup && ! empty( $pic_id ) ) { $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); $storage->backup_image( $pic_id ); } if ( ! empty( $pic_id ) ) { $image_ids[] = $pic_id; } // add the metadata. self::import_MetaData( $pic_id ); // auto rotate. self::rotate_image( $pic_id ); // Autoresize image if required. if ( $ngg->options['imgAutoResize'] ) { $imagetmp = nggdb::find_image( $pic_id ); $sizetmp = @getimagesize( $imagetmp->imagePath ); $widthtmp = $ngg->options['imgWidth']; $heighttmp = $ngg->options['imgHeight']; if ( ( $sizetmp[0] > $widthtmp && $widthtmp ) || ( $sizetmp[1] > $heighttmp && $heighttmp ) ) { self::resize_image( $pic_id ); } } // action hook for post process after the image is added to the database. $image = [ 'id' => $pic_id, 'filename' => $picture, 'galleryID' => $galleryID, ]; do_action( 'ngg_added_new_image', $image ); } } // delete dirsize after adding new images. delete_transient( 'dirsize_cache' ); do_action( 'ngg_after_new_images_added', $galleryID, $image_ids ); return $image_ids; } /** * Import some meta data into the database (if avialable) * * @class nggAdmin * @param array|int $imagesIds * @return string result code */ static function import_MetaData( $imagesIds ) { global $wpdb; require_once NGGALLERY_ABSPATH . '/lib/image.php'; if ( ! is_array( $imagesIds ) ) { $imagesIds = [ $imagesIds ]; } foreach ( $imagesIds as $imageID ) { // Get the image. $image = null; if ( is_int( $imageID ) ) { $image = \Imagely\NGG\DataMappers\Image::get_instance()->find( $imageID ); } else { $image = $imageID; } if ( $image ) { $meta = self::get_MetaData( $image ); // get the title. $alttext = empty( $meta['title'] ) ? $image->alttext : $meta['title']; // get the caption / description field. $description = empty( $meta['caption'] ) ? $image->description : $meta['caption']; // get the file date/time from exif. $timestamp = $meta['timestamp']; // first update database. $result = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->nggpictures SET alttext = %s, description = %s, imagedate = %s WHERE pid = %d", $alttext, $description, $timestamp, $image->pid ) ); if ( $result === false ) { return ' ' . esc_html( $image->filename ) . ' ' . __( '(Error : Couldn\'t not update data base)', 'nggallery' ) . ''; } // this flag will inform us that the import is already one time performed. $meta['common']['saved'] = true; $result = nggdb::update_image_meta( $image->pid, $meta['common'] ); if ( $result === false ) { return ' ' . esc_html( $image->filename ) . ' ' . __( '(Error : Couldn\'t not update meta data)', 'nggallery' ) . ''; } // add the tags if we found some. if ( $meta['keywords'] ) { $taglist = explode( ',', $meta['keywords'] ); wp_set_object_terms( $image->pid, $taglist, 'ngg_tag' ); } } else { return ' ' . esc_html( $image->filename ) . ' ' . __( '(Error : Couldn\'t not find image)', 'nggallery' ) . ''; // error check. } } return '1'; } /** * nggAdmin::get_MetaData() * * @class nggAdmin * @require NextGEN Meta class * @param int|object $image_or_id * @return array metadata */ static function get_MetaData( $image_or_id ) { require_once NGGALLERY_ABSPATH . '/lib/meta.php'; $meta = []; $pdata = new nggMeta( $image_or_id ); $meta['title'] = trim( $pdata->get_META( 'title' ) ); $meta['caption'] = trim( $pdata->get_META( 'caption' ) ); $meta['keywords'] = trim( $pdata->get_META( 'keywords' ) ); $meta['timestamp'] = $pdata->get_date_time(); // this contain other useful meta information. $meta['common'] = $pdata->get_common_meta(); // hook for addon plugin to add more meta fields. $meta = apply_filters( 'ngg_get_image_metadata', $meta, $pdata ); return $meta; } /** * nggAdmin::import_gallery() * TODO: Check permission of existing thumb folder & images * * @param string $galleryfolder contains relative path to the gallery itself * @param int $gallery_id * @return void */ public static function import_gallery( $galleryfolder, $gallery_id = null ) { global $wpdb, $user_ID; // get the current user ID. wp_get_current_user(); $created_msg = ''; // remove trailing slash at the end, if somebody use it. $galleryfolder = untrailingslashit( $galleryfolder ); $fs = \Imagely\NGG\Util\Filesystem::get_instance(); if ( is_null( $gallery_id ) ) { $gallerypath = $fs->join_paths( $fs->get_document_root( 'content' ), $galleryfolder ); } else { $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); $gallerypath = $storage->get_gallery_abspath( $gallery_id ); } if ( ! is_dir( $gallerypath ) ) { nggGallery::show_error( sprintf( __( 'Directory %s doesn`t exist!', 'nggallery' ), esc_html( $gallerypath ) ) ); return; } // read list of images. $new_imageslist = self::scandir( $gallerypath ); if ( empty( $new_imageslist ) ) { nggGallery::show_message( sprintf( __( 'Directory %s contains no pictures', 'nggallery' ), esc_html( $gallerypath ) ) ); return; } // take folder name as gallery name. $galleryname = basename( $galleryfolder ); $galleryname = apply_filters( 'ngg_gallery_name', $galleryname ); // check for existing gallery folder. if ( is_null( $gallery_id ) ) { $gallery_id = $wpdb->get_var( $wpdb->prepare( "SELECT gid FROM {$wpdb->nggallery} WHERE path = %s", [ $galleryfolder ] ) ); } if ( ! $gallery_id ) { // now add the gallery to the database. $gallery_id = nggdb::add_gallery( $galleryname, $galleryfolder, '', 0, 0, $user_ID ); if ( ! $gallery_id ) { nggGallery::show_error( __( 'Database error. Could not add gallery!', 'nggallery' ) ); return; } else { do_action( 'ngg_created_new_gallery', $gallery_id ); } $created_msg = sprintf( _n( 'Gallery %s successfully created!', 'Galleries %s successfully created!', 1, 'nggallery' ), esc_html( $galleryname ) ); } // Look for existing image list. $old_imageslist = $wpdb->get_col( $wpdb->prepare( "SELECT `filename` FROM {$wpdb->nggpictures} WHERE `galleryid` = %d", [ $gallery_id, ] ) ); // if no images are there, create empty array. if ( $old_imageslist == null ) { $old_imageslist = []; } // check difference. $new_images = array_diff( $new_imageslist, $old_imageslist ); // all images must be valid files. foreach ( $new_images as $key => $picture ) { // filter function to rename/change/modify image before. $picture = apply_filters( 'ngg_pre_add_new_image', $picture, $gallery_id ); $new_images[ $key ] = $picture; if ( ! @getimagesize( $gallerypath . '/' . $picture ) ) { unset( $new_images[ $key ] ); @unlink( $gallerypath . '/' . $picture ); } } // add images to database. $image_ids = self::add_Images( $gallery_id, $new_images ); do_action( 'ngg_after_new_images_added', $gallery_id, $image_ids ); // add the preview image if needed. self::set_gallery_preview( $gallery_id ); // now create thumbnails. self::do_ajax_operation( 'create_thumbnail', $image_ids, __( 'Create new thumbnails', 'nggallery' ) ); // TODO:Message will not shown, because AJAX routine require more time, message should be passed to AJAX. $message = $created_msg . sprintf( _n( '%s picture successfully added', '%s pictures successfully added', count( $image_ids ), 'nggallery' ), count( $image_ids ) ); $message .= ' ['; $message .= __( 'Edit gallery', 'nggallery' ); $message .= ']'; nggGallery::show_message( $message ); return; } /** * Capability check. Check is the ID fit's to the user_ID * * @class nggAdmin * @param int $check_ID is the user_id * @return bool $result */ static function can_manage_this_gallery( $check_ID ) { global $user_ID, $wp_roles; if ( ! current_user_can( 'NextGEN Manage others gallery' ) ) { // get the current user ID. wp_get_current_user(); if ( $user_ID != $check_ID ) { return false; } } return true; } /** * Initate the Ajax operation * * @class nggAdmin * @param string $operation name of the function which should be executed * @param array $image_array * @param string $title name of the operation * @return string the javascript output */ static function do_ajax_operation( $operation, $image_array, $title = '' ) { if ( ! is_array( $image_array ) || empty( $image_array ) ) { return ''; } $js_array = implode( '","', $image_array ); // send out some JavaScript, which initate the ajax operation. ob_start(); ?> find( $galleryID ) ) ) { if ( ! $gallery->previewpic ) { $image_mapper = \Imagely\NGG\DataMappers\Image::get_instance(); $image = $image_mapper->select() ->where( [ 'galleryid = %d', $galleryID ] ) ->where( [ 'exclude != 1' ] ) ->order_by( $image_mapper->get_primary_key_column() ) ->limit( 1 ) ->run_query(); if ( $image ) { $gallery->previewpic = $image->{$image->id_field}; $gallery_mapper->save( $gallery ); } } } } /** * Return a JSON coded array of Image ids for a requested gallery * * @class nggAdmin * @param int $galleryID * @return string|int (JSON) */ static function get_image_ids( $galleryID ) { if ( ! function_exists( 'json_encode' ) ) { return( -2 ); } $gallery = nggdb::get_ids_from_gallery( $galleryID, 'pid', 'ASC', false ); header( 'Content-Type: text/plain; charset=' . get_option( 'blog_charset' ), true ); return json_encode( $gallery ); } /** * Deprecated function, restored to fix compatibility with "NextGen Public Uploader" * * @deprecated * @class nggAdmin * @param string $filename * @return bool $result */ function chmod( $filename = '' ) { $stat = @stat( dirname( $filename ) ); $perms = $stat['mode'] & 0000666; if ( @chmod( $filename, $perms ) ) { return true; } return false; } } // END class nggAdmin // XXX temporary...used as a quick fix to refresh I_Settings_Manager when the nextgen option is updated manually in order to run Hooks etc. function ngg_refreshSavedSettings(): bool { $settings = \Imagely\NGG\Settings\Settings::get_instance(); if ( $settings != null ) { $width = $settings->get( 'thumbwidth' ); $height = $settings->get( 'thumbheight' ); $new_dimension = "{$width}x{$height}"; $dimensions = (array) $settings->get( 'thumbnail_dimensions' ); if ( ! in_array( $new_dimension, $dimensions ) ) { $dimensions[] = $new_dimension; $settings->set( 'thumbnail_dimensions', $dimensions ); $settings->save(); return true; } } return false; } Legacy/admin/css/jquery.ui.tabs.min.css000064400000005456150212230450014013 0ustar00@media projection,screen{.ui-tabs-hide{display:none}}@media print{.ui-tabs-nav{display:none}}#slider{border-color:#ebebeb #ccc #ccc #ebebeb;border-style:solid;border-width:1px;margin:15px 15% 0 15px;padding:2px}#tabs{display:block;background:#f1f1f1 none repeat scroll 0;font-size:14px;overflow:hidden}.ui-tabs-nav{list-style:none;margin:0;padding:0 0 0 10px}.ui-tabs-nav:after{display:block;clear:both;content:" "}.ui-tabs-nav li{float:left;padding:6px 5px;min-width:84px;margin:2px 2px 0 1px!important;text-decoration:none;list-style:none}.ui-tabs-nav a,.ui-tabs-nav a span{display:block;padding:0 1px}.ui-tabs-nav a{margin:1px 0 0;padding-left:0;color:#2583ad;line-height:1.2;text-align:center;text-decoration:none;white-space:nowrap;outline:0}.ui-tabs-nav .ui-tabs-selected{background:#6d6d6d url(../images/menu-bits.gif) repeat-x scroll left top;border-color:#6d6d6d;color:#fff;text-shadow:0 -1px 0 #666;-moz-border-radius-topright:6px;-khtml-border-top-right-radius:6px;-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-moz-border-radius-topleft:6px;-khtml-border-top-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px}.ui-tabs-selected a,.ui-tabs-selected a:hover{color:#fff!important}.ui-tabs-nav .ui-tabs-selected a,.ui-tabs-nav .ui-tabs-selected a:hover{position:relative;top:1px;z-index:2;margin-top:0}.ui-tabs-nav li a:hover{color:#d54e21}.ui-tabs-nav a span{width:64px;min-width:64px;height:18px;min-height:18px;padding-top:6px;padding-right:0}*>.ui-tabs-nav a span{width:auto;height:auto}.ui-tabs-nav .ui-tabs-selected a span{padding-bottom:1px}.ui-tabs-nav .ui-tabs-selected a,.ui-tabs-nav a:active,.ui-tabs-nav a:focus,.ui-tabs-nav a:hover{background-position:100% -150px}.ui-tabs-nav .ui-tabs-disabled a:active,.ui-tabs-nav .ui-tabs-disabled a:focus,.ui-tabs-nav .ui-tabs-disabled a:hover,.ui-tabs-nav a{background-position:100% -100px}.ui-tabs-nav .ui-tabs-selected a span,.ui-tabs-nav a:active span,.ui-tabs-nav a:focus span,.ui-tabs-nav a:hover span{background-position:0 -50px}.ui-tabs-nav .ui-tabs-disabled a:active span,.ui-tabs-nav .ui-tabs-disabled a:focus span,.ui-tabs-nav .ui-tabs-disabled a:hover span,.ui-tabs-nav a span{background-position:0 0}.ui-tabs-nav .ui-tabs-disabled a:link,.ui-tabs-nav .ui-tabs-disabled a:visited,.ui-tabs-nav .ui-tabs-selected a:link,.ui-tabs-nav .ui-tabs-selected a:visited{cursor:text}.ui-tabs-nav .ui-tabs-unselect a:active,.ui-tabs-nav .ui-tabs-unselect a:focus,.ui-tabs-nav .ui-tabs-unselect a:hover,.ui-tabs-nav a:active,.ui-tabs-nav a:focus,.ui-tabs-nav a:hover{cursor:pointer}.ui-tabs-disabled{opacity:.4}.ui-tabs-panel{border-top:1px solid #97a5b0!important;padding:1em 8px;background:#fff;border:none!important;height:100%!important;margin:0!important;overflow:visible!important}.ui-tabs-panel a{display:inline}* html .ui-tabs-nav{display:inline-block}Legacy/admin/css/nggSorter.min.css000064400000001307150212230450013071 0ustar00.imageBox,.imageBoxHighlighted{width:130px;height:160px;float:left}.imageBox_theImage{width:110px;height:125px;background-position:center;background-repeat:no-repeat;margin:0 auto;margin-bottom:2px}.imageBox .imageBox_theImage{border:1px solid #ddd;padding:2px}.imageBoxHighlighted .imageBox_theImage{border:3px solid #316ac5;padding:0}.imageBoxHighlighted span{background-color:#316ac5;color:#fff;padding:2px}.imageBox_label{text-align:center;font-family:arial;font-size:11px;padding-top:2px;margin:0 auto}#insertionMarker{height:150px;width:6px;position:absolute}#insertionMarkerLine{width:6px;height:145px}#insertionMarker img{float:left}#dragDropContent{opacity:.4;position:absolute;z-index:10;display:none}Legacy/admin/css/nggadmin.css000064400000102210150212230450012114 0ustar00/* ** NextGEN Gallery Style for Wordpress 3.3 */ #iframely h2.title { display: none; } /* OVERVIEW PAGES */ .toplevel_page_nextgen-gallery #ngg_page_content { width: 98%; } .toplevel_page_nextgen-gallery #ngg_page_content .about-wrap.ngg_overview { width: 100%; } .toplevel_page_nextgen-gallery #ngg_page_content .ngg_page_content_main { padding-right: 40px !important; } #newversion { border-color:#CCCCCC; border-style:solid; border-width:1px; margin-right:7px; margin-top:10px; padding:2px; } .ngg-dashboard-widget ul.settings span { padding-left : 10px; color:#2583AD; font-weight:bold; } .ngg-overview .postbox .handlediv { float:right; height:24px; width:24px; } #ngg_page_content .ngg_overview .ngg_page_content_header h2 { padding-top: 2px; } #ngg_page_content .ngg_overview .ngg_page_content_main h2 { text-align: left; font-size: 22px; font-weight: 400; color: black; margin: 20px 0 20px; text-transform: uppercase; letter-spacing: 2px; } #ngg_page_content .ngg_overview .ngg_page_content_main .about-text { font-size: 17px; max-width: none; margin: 20px 0; color: black; font-weight: 400; } #ngg-gallery-wizard { min-height: auto; position: absolute; top: 0; right: 0; text-align: right; margin: 0 20px 0 0; line-height: 80px; color: #fff; font-size: 14px; margin-right: 0; color: black; font-weight: 400; letter-spacing: .5px; } #ngg_page_content #ngg-gallery-wizard a { font-weight: bold; text-decoration: none; margin-left: 20px; height: 50px !important; line-height: 50px; } .warning { color: #9F6000; background-color: #FEEFB3; border: 1px solid; margin: 5px 0px; padding:5px; } #donator_message { margin:5px 0 15px; background-color:#BDE5F8; border-color:#00529B; -moz-border-radius-bottomleft:3px; -moz-border-radius-bottomright:3px; -moz-border-radius-topleft:3px; -moz-border-radius-topright:3px; border-style:solid; border-width:1px; margin:5px 15px 2px; padding:0 0.6em; } #donator_message p{ line-height:1; margin:0.5em 0; padding:2px; padding-bottom:10px; } #donator_message span{ padding-top:10px; float:right; } #plugin_check img { float: right; } #plugin_check p.message { font-size: 90%; color: #666; } .toplevel_page_nextgen-gallery .feature-video iframe { box-shadow: 0 0 8px 4px rgba(0,0,0,.03); width: 800px; height: 450px; max-width: 100%; } div[data-id="welcome-link"] .about-text { margin: 0 0 40px !important; } div[data-id="pro-link"] .feature-section { position: relative; margin: 40px 0; padding-bottom: 56.25%; } div[data-id="pro-link"] .feature-section iframe { width: 900px; height: 506px; max-width: 100%; position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #ngg_page_content .button-primary.ngg-pro-upgrade { height: 50px !important; padding: 0 40px !important; line-height: 50px; } div[data-id="videos-link"] .feature-section, div[data-id="videos-link"] .feature-section .col, div[data-id="genesis-link"] .feature-section, div[data-id="genesis-link"] .feature-section .col { padding: 0; margin: 0; } /* COMMON STYLING FOR DIALOGS */ .ngg-admin .ui-dialog { max-width: 100%; } /* OPTIONS TABLE */ .ngg-options th { width:22%; } a.switch-expert { text-decoration:none; } /* WATERMARK */ #wm-preview { float:right; font-size:90%; width:35%; border-color:#EBEBEB rgb(204, 204, 204) rgb(204, 204, 204) rgb(235, 235, 235); border-style:solid; border-width:1px; margin-bottom:10px; margin-left:10px; margin-right:8px; padding:2px; } #wm-preview h3{ background:#F9F9F9 none repeat scroll 0%; font-size:14px; font-weight:bold; margin:0pt 0pt 10px; padding:8px 5px; } #wm-position { width:100%; margin-left:40px; } .wm-table { border-collapse:collapse; margin-top:1em; width: 60%; clear:none; } .wm-table td { border-bottom:8px solid #FFFFFF; line-height:20px; margin-bottom:9px; padding:10px; } .wm-table th { border-bottom:8px solid #FFFFFF; padding:10px; text-align:left; } .wm-table tr { background:#F9F9F9 none repeat scroll 0%; } /* MANAGE GALLERY */ .ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content .notice, .ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content div.updated, .ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content div.error { margin: 10px 0 40px 0; } .ngg_admin_notice ul { list-style: circle inside; margin: 0; padding: 0; } .gallery_page_nggallery-manage-gallery #ngg_page_content .ngg_page_content_main { padding-top: 30px; } .ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content div.updated#message { margin-bottom: 35px; } .gallery_page_nggallery-manage-gallery #ngg_page_content > .wrap > h2 { display:none; } #ngg_page_content .ngg_manage_galleries .tablenav { margin: 0 0 30px; } #ngg_page_content .ngg_manage_images .handlediv { float: none; width: 100%; height: 50px; } #gallerydiv h3 { margin-left: 10px; display: inline-block; height: 50px; float: left; margin: 0; line-height: 50px; text-transform: uppercase; font-size: 16px; letter-spacing: 1.5px; } #gallerydiv span.toggle-indicator { display: inline-block; float: left; line-height: 50px; } #gallerydiv span.toggle-indicator:before { font-size: 24px; margin: 12px 20px 0 10px; } #gallerydiv span.toggle-indicator:hover { cursor: pointer; } #gallerydiv h3:active, #gallerydiv h3:focus, #gallerydiv span.toggle-indicator:active, #gallerydiv span.toggle-indicator:focus { outline: 0; border: none; -moz-outline-style: none; } #ngg_page_content .ngg_manage_images .tablenav { margin: 50px 0 30px; } #ngg_page_content .ngg_manage_galleries .tablenav.top > div, #ngg_page_content .ngg_manage_images .tablenav.top > div { margin-bottom: 10px; } #ngg_page_content .ngg_manage_galleries .search-box-wrapper { display: flex; flex-direction: row; justify-content: center; width: 100%; } #ngg_page_content .ngg_manage_galleries div.search-box { display: flex; flex-direction: row; justify-content: center; } #ngg_page_content .ngg_manage_galleries div.search-box:last-of-type { } #ngg_page_content .ngg_manage_galleries .search-box input[type=text] { width: calc(100% - 150px) !important; height: 35px !important; margin-right: 4px !important; } #ngg_page_content .ngg_manage_galleries .search-box input[type=submit].button-primary { width: 150px !important; height: 35px !important; padding: 0 !important; } #ngg_page_content .ngg_manage_galleries form.search-form { width: 100%; } #ngg_page_content .ngg_manage_galleries form.search-form:first-of-type { padding-right: 25px; } #ngg_page_content #editgalleries .displaying-num { margin-right: 7px !important; font-size: 14px; letter-spacing: 1px; } #ngg_page_content #editgalleries #bulkaction { min-height: 35px; max-height: 35px; } #ngg_page_content .ngg_manage_galleries .tablenav.bottom { margin: 15px 0 0; } #ngg_page_content .ngg_manage_images .tablenav.bottom { margin: 25px 0 0; } .ngg-admin #ngg_page_content .ngg_manage_images td { vertical-align: top; } #ngg_page_content .ngg_manage_galleries .tablenav input { height: 28px; width: 50px; padding: 0 3px; } #ngg_page_content .ngg_manage_galleries .tablenav input.current-page { width: 50px !important; } #ngg_page_content .ngg_manage_images .tablenav .tablenav-pages { margin-top: 0; } #ngg_page_content .ngg_manage_galleries .tablenav .tablenav-pages { margin-top: 6px; } #ngg_page_content .ngg_manage_galleries .tablenav .tablenav-pages a, #ngg_page_content .ngg_manage_images .tablenav .tablenav-pages a { background: black; border: none; color: #fff !important; margin: 0 2px; text-decoration: none; font-size: 20px; padding: 4px; line-height: 20px; padding: 2px 8px 6px 8px; } #ngg_page_content .ngg_manage_images .tablenav input, #ngg_page_content .ngg_manage_images .tablenav select { width: auto; margin-top: 0; } #ngg_page_content .ngg_manage_images .tablenav input.current-page, #ngg_page_content #ngg-manage-images-items-per-page { padding: 4px !important; text-align-last: center; background-image: none; } #ngg_page_content .ngg_manage_galleries table { box-shadow: none; border: 1px solid rgba(159, 187, 26, 0.08)!important } #ngg_page_content .ngg_manage_galleries table thead, #ngg_page_content .ngg_manage_galleries table tfoot { background-color: black; } #ngg_page_content .ngg_manage_galleries table thead th, #ngg_page_content .ngg_manage_galleries table thead td, #ngg_page_content .ngg_manage_galleries table tfoot th, #ngg_page_content .ngg_manage_galleries table tfoot td { background-color: transparent; border: none; } #ngg_page_content .ngg_manage_galleries table th, #ngg_page_content .ngg_manage_galleries table td { padding: 12px 10px; font-size: 14px; } #ngg_page_content .ngg_manage_galleries table th { font-weight: bold !important; color: #fff; } .ngg_manage_galleries th#id { width: 33px; } .ngg_manage_galleries th#title { min-width: 140px; } .ngg_manage_galleries td.title { text-transform: uppercase; font-weight: 400; font-size: 13px !important; } .ngg_manage_galleries th#author { min-width: 80px; } .ngg_manage_galleries th#page_id { min-width: 60px; } #ngg_page_content .ngg_manage_galleries table tr.alternate { background-color: #f7f7f7; } #ngg_page_content .ngg_manage_galleries th a { padding: 0 !important; color: #fff; } div#poststuff { min-width: auto; } div#poststuff #gallerydiv { cursor:pointer; } p#ngg-inlinebutton { float:right; margin:0pt; position:relative; top:-25pt; } #gallery_fields { width: 100%; } #gallery_fields td{ padding: 5px; min-width: 105px; } #gallery_fields tr td:nth-of-type(2) { padding-right: 60px; } #gallery_fields input[type=text], #gallery_fields textarea, #gallery_fields select { min-width: 220px; width: 99%; color: #888; } table#ngg-listimages { border: 1px solid #f7f7f7; } #ngg-listimages thead, #ngg-listimages tfoot { background: black; } #ngg-listimages tfoot { background: black; } #ngg-listimages.widefat thead th, .ngg-admin #ngg_page_content .widefat tfoot th { padding: 12px 10px !important; } #ngg-listimages tr.alternate { background-color: #f7f7f7; } #ngg-listimages td { padding: 15px 5px !important; } #ngg-listimages .iedit, #ngg-listimages .iedit td, #ngg-listimages th { border: none; } #ngg-listimages th, #ngg-listimages .iedit td { padding: 15px 5px; } #ngg-listimages th { font-size: 12px; font-weight: bold; } #ngg-listimages .column select { width: 100% !important; } #ngg-listimages .column-1 input { margin: 0 0 0 8px; } #ngg-listimages .column-1 { width: 24px; } #ngg-listimages .column-2 { width: 30px; } #ngg-listimages .column-3 { min-width: 80px; width: 15%; } #ngg-listimages .column-3 .thumb { max-height: 100%; max-width: 100%; } #ngg-listimages .column-4 { width: 15%; max-width: 220px; } #ngg-listimages .column-4 { font-size: 12px; } #ngg-listimages .column-4 .meta, #ngg-listimages .column-4 label { font-size: 10px; color: #888; } #ngg-listimages .column-4 label input[type=checkbox] { margin: -2px 4px 0 0; } #ngg-listimages .column-5 input[type=text], #ngg-listimages .column-5 textarea, #ngg-listimages .column-6 textarea { width: 100%; padding: 3px 5px; font-size: 12px; color: #888; border: 1px solid #eee; margin: 1px 0; box-shadow: none; } #ngg-listimages .column-5 input[type=text] { height: 25px; } #ngg-listimages .column-5 textarea { height: 70px; } #ngg-listimages .column-6 textarea { height: 97px; } #ngg-listimages .column-7 select { font-size: 12px; } #ngg-listimages .row-actions { padding: 0 0 6px 4px; margin-bottom: -2px; position: relative; bottom: 4px; left: 0; right: 0; } #ngg-listimages .row_actions, #ngg-listimages .row_actions td { border-top: none; padding: 0 !important; } #ngg-listimages .row-actions a { font-size: 12px; } /* Updating Imagify for color consistency. * To Imagify: hope you guys don't mind, * but given our redesign, we'd like the colors * to be consitent on these pages. */ #ngg-listimages ul.imagify-datas-list .big { color: #9fbb1a; } #ngg-listimages .imagify-datas-more-action a { background: #9fbb1a; color: #fff; } .gallery_page_nggallery-manage-gallery .ui-dialog { border: none; padding: 0; max-width: 95% !important; z-index: 10000 !important; margin: 0 auto !important; } .gallery_page_nggallery-manage-album .ui-dialog { border: none; padding: 0; z-index: 10000 !important; width: 650px !important; max-width: 98% !important; } .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom button, .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-primary, .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-secondary, .gallery_page_nggallery-manage-gallery .ui-dialog button, .gallery_page_nggallery-manage-gallery .ui-dialog .button-primary, .gallery_page_nggallery-manage-gallery .ui-dialog .button-secondary, .gallery_page_nggallery-manage-album .ui-dialog .button-primary, .gallery_page_nggallery-manage-album .ui-dialog .button-secondary { background-color: #9fbb1a !important; color: #fff !important; border: none !important; box-shadow: none !important; text-shadow: none !important; height: 35px !important; padding: 0 15px !important; line-height: 35px; width: auto !important; margin-right: 10px; text-transform: uppercase; letter-spacing: 1px; } .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom button:hover, .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-primary:hover, .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-secondary:hover, .gallery_page_nggallery-manage-gallery .ui-dialog button:hover .gallery_page_nggallery-manage-gallery .ui-dialog .button-primary:hover, .gallery_page_nggallery-manage-gallery .ui-dialog .button-secondary:hover, .gallery_page_nggallery-manage-album .ui-dialog .button-primary:hover, .gallery_page_nggallery-manage-album .ui-dialog .button-secondary:hover { background-color: #A9C524 !important; } .gallery_page_nggallery-manage-gallery .ui-dialog-titlebar, .gallery_page_nggallery-manage-album .ui-dialog-titlebar{ background: black; padding: 10px; } .gallery_page_nggallery-manage-gallery .ui-dialog-titlebar .ui-dialog-title, .gallery_page_nggallery-manage-album .ui-dialog-titlebar .ui-dialog-title { text-transform: uppercase; letter-spacing: 1px; } .gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button, .gallery_page_nggallery-manage-album .ui-dialog-titlebar button { background: #fff !important; border: none !important; box-shadow: none !important; text-shadow: none !important; height: 24px !important; width: 24px !important; padding: 0 !important; line-height: 1; float: none; margin-right: 0; border-radius: 50%; top: 17px; right: 10px; } .gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button:hover, .gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button:active, .gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button:focus, .gallery_page_nggallery-manage-album .ui-dialog-titlebar button:hover, .gallery_page_nggallery-manage-album .ui-dialog-titlebar button:active, .gallery_page_nggallery-manage-album .ui-dialog-titlebar button:focus { background: #fff !important; } .gallery_page_nggallery-manage-gallery .ui-dialog .ngg-overlay-dialog, .gallery_page_nggallery-manage-album .ui-dialog .ngg-overlay-dialog { padding: 30px 20px; box-sizing: border-box; width: 100% !important; } .gallery_page_nggallery-manage-gallery .ngg-overlay-dialog table { border: none; } .gallery_page_nggallery-manage-gallery .ngg-overlay-dialog #ngg-overlay-dialog-main, .gallery_page_nggallery-manage-album .ngg-overlay-dialog #ngg-overlay-dialog-main { width: 70%; padding: 20px 20px 0; } .gallery_page_nggallery-manage-gallery .ngg-overlay-dialog td small { margin-left: 10px; display: block; text-align: center; width: 200px; margin: 0 auto 20px; } .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom { text-align: center; padding: 30px 0 0 0; } .gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom input[type="button"] { float:none; margin-right: 0; } .gallery_page_nggallery-manage-gallery .ngg-overlay-dialog #thumbMsg { color: #669933; display: none; font-size: 11px; width: 100%; display: inline-block; height: 35px; line-height: 35px; margin: 10px 0; } .gallery_page_nggallery-manage-gallery .ui-dialog form { margin-top: 30px; margin-left: 30px; } .gallery_page_nggallery-manage-gallery .ngg-overlay-dialog input[type=radio]:focus { border: 1px solid #b4b9be; box-shadow: none; } .gallery_page_nggallery-manage-gallery input[type=checkbox]:checked:before { color: #9fbb1a; } .gallery_page_nggallery-manage-gallery .ngg-overlay-dialog input[type=radio]:checked:before { background: #9fbb1a; width: 14px; height: 14px; margin: 0; } /* SETTINGS FOR PROGRESS BAR */ div .progressborder { border:1px solid #DDDDDD; display: block; height: 30px; background-color: #464646; width: 100%; margin-top: 15px; margin-bottom: 15px; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } div .progressbar { border: medium none ; display: block; height: 30px; background-color: #9fbb1a; width: 0%; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } div .progressbar span { display: inline; position: absolute; color: white; font-weight: bold; padding: 5px 0 0 5px; } .show_details { height: 16px; line-height: 20px; overflow: hidden; min-width: 8em; padding: 3px; cursor:pointer; } .show_details span { border-bottom:1px solid #999; white-space:pre; } .show_details:hover { height: auto; overflow: visible; border: 1px solid #999; } /* SETTINGS FOR ALBUM PAGE */ .gallery_page_nggallery-manage-album .wrap>h2:first-child { display:none; } .gallery_page_nggallery-manage-album #ngg_page_content div.updated { margin: 0 0 15px 0; } .gallery_page_nggallery-manage-album #ngg_page_content div.updated#message { margin-bottom: 35px; } .ngg_manage_albums .widget { box-sizing: border-box; border: 1px solid #eee; padding: 10px 10px 20px; margin: 0 1% 0 0; width: 100%; } .ngg_manage_albums .widget:last-of-type { margin-right: 0; } .container { margin-top: 10px; } .ngg_manage_albums .container { margin-top: 30px; display: flex; flex-direction: row; justify-content: center; } .ngg_select_album { margin: 0 50px 0 2px; vertical-align: middle; } #newalbum, .ngg_new_album { vertical-align: middle; } .albumnav select[name="act_album"] { width:150px; } #editalbum select[name='pageid'] { width: 95%; } #ngg_page_content .ngg_manage_albums .widget-top { box-shadow: none; background: transparent; border: none; margin: -10px -10px 20px -10px; background: #f7f7f7; } div .groupItem { cursor: move; padding: 2px; line-height: 1.5; width: 100%; margin: 0; box-sizing: border-box; } div .innerhandle { background-color:#FBFBFB; } .groupItem .item_top { background-color:#9fbb1a; color: #FFFFFF; font-weight:400; line-height: 28px; height: 28px; padding: 0 5px; border-radius: 0; height: 40px; padding: 0 10px; line-height: 40px; } #ngg_page_content .groupItem .album_obj { background-color: black; } #ngg_page_content .groupItem .item_top a { color:#FFFFFF; float:right; text-decoration: none; } .groupItem .item_top a:hover { color:#FFFFFF; } .itemContent { border-color:#DFDFDF; border-style:none solid solid; border-width:0 1px 1px; padding:2px 0 20px 2px; } .itemContent p { border: 0; margin: 0; padding: 0; } .inlinepicture { float:left; display:inline; margin:0pt; padding:0pt 3px 1px; } .inlinepicture img { margin:3px; max-height:60px; } .sort_placeholder { border:1px dashed #bba !important; margin: 5px; background: #F9F9F9; } .widget-holder { min-height: 400px; padding-top:1px; } .target { background-color: transparent; } div.widget-top h3 { text-align:center; line-height:25px; margin: 0; padding: 5px 12px; font-size: 13px; letter-spacing: .5px; text-transform: uppercase; } div.widget-top { text-shadow:0 1px 0 #FFFFFF; background-repeat: repeat-x; background-position: 0 0; font-size: 13px; } .ui-autocomplete-start { background-position: 99% center; } /* SETTINGS FOR SORT GALLERY */ #ngg_page_content .ngg_gallery_sort .tablenav { margin: 15px 0; } #ngg_page_content .ngg_gallery_sort ul.subsubsub { margin: 10px 0 15px; } #ngg_page_content .ngg_gallery_sort .imageBox_theImage { width: auto; } #sortGallery { position:relative; } p#sortButton{ margin:0; position:absolute; right:0; top:0; } #ngg-sort-gallery-container { display: flex; flex-wrap: wrap; } .imageBox,.imageBoxHighlighted { width:130px; /* Total width of each image box */ height:160px; /* Total height of each image box */ overflow: hidden; text-overflow: ellipsis; padding: 5px; } .imageBox_theImage{ width:110px; /* Width of image */ height:125px; /* Height of image */ background-position: center; background-repeat: no-repeat; margin: 0 auto; margin-bottom:2px; } .imageBox_label{ /* Title of images - both selected and not selected */ text-align:center; font-family: arial; font-size:11px; padding-top:2px; margin: 0 auto; } /* DIV that indicates where the dragged image will be placed */ #insertionMarker{ height:150px; width:6px; position:absolute; } #insertionMarkerLine{ width:6px; /* No need to change this value */ height:145px; /* To adjust the height of the div that indicates where the dragged image will be dropped */ } #insertionMarker img{ float:left; } /* DIV that shows the image as you drag it */ #dragDropContent{ opacity:0.4; /* 40 % opacity */ filter:alpha(opacity=40); /* 40 % opacity */ /* No need to change these three values */ position:absolute; z-index:10; display:none; } /* UPGRADE PAGE */ .error_inline { background:#FFEBE8 none repeat scroll 0%; border:1px solid #CC0000; margin:5px auto; padding:10px; } /* ABOUT PAGE */ .ngg-list { font-size:11px; margin-left:15px; list-style-position:inside; list-style-type:disc; } #ngg-manage-images-items-per-page-label { float: right; line-height: 35px; margin-right: 5px; } #ngg-manage-images-items-per-page { float: right; margin-right: 30px; } /* Media Queries */ @media (max-width: 1200px) { div[data-id="details-link"] .two-col .col { width: 100%; min-width: 100%; } } @media (max-width: 1420px) { } @media (max-width: 1100px) { } @media (max-width: 1080px) { #ngg-gallery-wizard > span { display: none; } /* Manage Galleries */ .ngg_manage_galleries .tablenav.bottom { display: none; } .ngg_manage_images #gallery_fields td:nth-of-type(even) { margin-bottom: 8px; } .ngg_manage_images #gallery_fields td:nth-of-type(odd) { background: #f7f7f7; padding-left: 10px; font-weight: bold; } .ngg_manage_images #gallery_fields, .ngg_manage_images #gallery_fields tbody, .ngg_manage_images #gallery_fields tr, .ngg_manage_images #gallery_fields td { display:block; width: 100%; box-sizing: border-box; } .ngg_manage_images #gallery_fields td { padding: 10px 5px; border: 1px solid rgb(247, 248, 243); margin: 0; } } @media (max-width: 900px) { .ngg_manage_galleries tfoot { display:none; } .ngg_manage_galleries .wp-list-table tr:not(.inline-edit-row):not(.no-items) td:not(.check-column) { display: table-cell; } .ngg_manage_galleries th#id, .ngg_manage_galleries th#author, .ngg_manage_galleries th#page_id, .ngg_manage_galleries td.id, .ngg_manage_galleries td.author, .ngg_manage_galleries td.page_id { display: none !important; } #ngg-listimages thead .column-1, #ngg-listimages thead .column-2, #ngg-listimages thead .column-4, #ngg-listimages thead .column-5, #ngg-listimages thead .column-6, #ngg-listimages thead .column-7, #ngg-listimages thead .column-8, #ngg-listimages tfoot, #ngg-listimages td.column.column-2, #ngg-listimages td.column.column-8, #ngg-listimages td.column.column-6 { display: none; } #ngg-listimages .column-3 { min-width: 200px; } table#ngg-listimages, table#ngg-listimages thead { display: block; } #ngg-listimages .iedit td { padding-bottom: 30px !important; } } @media (max-width: 800px) { /* Manage Galleries */ table#ngg-listimages, table#ngg-listimages tbody, table#ngg-listimages tr, table#ngg-listimages td { display: block; } table#ngg-listimages tr { padding: 10px 5px !important; } #ngg-listimages thead, #ngg-listimages thead th { display: block; width: 100%; box-sizing: border-box; } #ngg-listimages .row_actions td:first-of-type { display:none; } #ngg-listimages tfoot { display:none; } #ngg-listimages .row_actions { display:none; display:block; clear: both; padding: 0 8px 10px !important; border-bottom: 1px solid #c1c97c; } .ngg-listimages tr.iedit td { display: block !important; float: left; box-sizing: border-box; padding-bottom: 10px !important; } #ngg-listimages td.column-1, #ngg-listimages td.column-2 { width: 10% !important; height: 150px; float: left; box-sizing: border-box; display:none; } #ngg-listimages td.column-3 { width: 55%; max-width: 300px; float: left; box-sizing: border-box; padding-bottom: 10px !important; } #ngg-listimages td.column-4 { width: 40% !important; float: left; box-sizing: border-box; } #ngg-listimages td.column-5, #ngg-listimages td.column-6, #ngg-listimages td.column-7 { padding: 0 5px !important; } #ngg-listimages td.column-6 { margin-top: -5px; margin-bottom: -8px; } .ngg-listimages td.column-7 { padding-bottom: 15px; } #ngg-manage-images-items-per-page, #ngg-manage-images-items-per-page-label { display: none; } #ngg-listimages .column-6 textarea { height: 60px; } .ngg_manage_images .tablenav.bottom .displaying-num { display:none; } } @media (max-width: 782px) { #ngg-gallery-wizard { display: none; } #ngg_page_content .ngg_manage_galleries .tablenav.top > div { display: block; width: 100%; } #ngg_page_content .ngg_manage_galleries .tablenav .tablenav-pages { margin-top: 20px; margin-bottom: 28px !important; } #ngg_page_content .ngg_manage_galleries .search-box input[type=text] { width: calc(100% - 150px) !important; } #ngg_page_content .ngg_manage_galleries .search-box input[type=submit].button-primary { height: 40px !important; } #ngg_page_content .ngg_manage_galleries .search-box-wrapper { flex-direction: column; } #ngg_page_content .ngg_manage_galleries form.search-form { width: 100%; } #ngg_page_content #editgalleries div.tablenav.top div.alignleft.actions input.button-primary { width: auto !important; display: inline-block; } #ngg_page_content #editgalleries div.tablenav.top div.alignleft.actions input.button-primary:first-of-type { margin-left: 5px; } #ngg_page_content #editgalleries div.tablenav.top div.tablenav-pages { display: none; } #ngg_page_content #editgalleries #bulkaction { width: auto !important; } } @media (max-width: 737px) { .gallery_page_nggallery-manage-gallery input[type=checkbox]:checked:before { font-size: 22px; } .ngg-overlay-dialog input[type="radio"] { height: 16px; width: 16px; } #ngg-gallery-wizard { display: none; } } @media (max-width: 640px) { /* Manage Galleries */ .ngg_manage_galleries th#description, .ngg_manage_galleries td.description { display: none !important; } /* Manage Albums */ .ngg_manage_albums .tablenav .actions { width: 100%; float: none; } .ngg_manage_albums .tablenav span { display: block; } .ngg_manage_albums .target-album, .ngg_manage_albums .widget.widget-right { width: 32% !important; margin: .5% !important; padding: 5px 5px 10px; } .groupItem .item_top { height: auto !important; line-height: 1.5; padding: 8px; font-size: 12px; } #ngg_page_content .groupItem .item_top a { display: none; } .ngg_manage_albums div[style="float:right;"] { float: none !important; } .gallery_page_nggallery-manage-gallery .ui-dialog { width: 95% !important; left: 2.5% !important; } .gallery_page_nggallery-manage-gallery .ui-dialog .ngg-overlay-dialog { padding: 30px 10px; } .ngg-overlay-dialog td { display: block; width: 100% !important; padding: 0 !important; } .ngg-overlay-dialog input[type="radio"] { margin: 2px 5px; height: 16px; width: 16px; } } /** * @TODO : Remove all of the following Thickbox specific rules once the Manage Gallery page no longer uses Thickbox. * This whole section was added as an annoying hack workaround to the fact that the Manage Gallery page seemingly cannot * be forced to correctly enqueue thickbox.css when inside of the attach-to-post controller once the latter was refactored * to no longer rely on POPE. */ #TB_overlay { background: #000; opacity: 0.7; filter: alpha(opacity=70); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100050; /* Above DFW. */ } #TB_window { position: fixed; background-color: #fff; z-index: 100050; /* Above DFW. */ visibility: hidden; text-align: left; top: 50%; left: 50%; -webkit-box-shadow: 0 3px 6px rgba( 0, 0, 0, 0.3 ); box-shadow: 0 3px 6px rgba( 0, 0, 0, 0.3 ); } #TB_window img#TB_Image { display: block; margin: 15px 0 0 15px; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; border-top: 1px solid #666; border-left: 1px solid #666; } #TB_caption{ height: 25px; padding: 7px 30px 10px 25px; float: left; } #TB_closeWindow { height: 25px; padding: 11px 25px 10px 0; float: right; } #TB_closeWindowButton { position: absolute; left: auto; right: 0; width: 29px; height: 29px; border: 0; padding: 0; background: none; cursor: pointer; outline: none; -webkit-transition: color .1s ease-in-out, background .1s ease-in-out; transition: color .1s ease-in-out, background .1s ease-in-out; } #TB_ajaxWindowTitle { float: left; font-weight: 600; line-height: 29px; overflow: hidden; padding: 0 29px 0 10px; text-overflow: ellipsis; white-space: nowrap; width: calc( 100% - 39px ); } #TB_title { background: #fcfcfc; border-bottom: 1px solid #ddd; height: 29px; } #TB_ajaxContent { clear: both; padding: 2px 15px 15px 15px; overflow: auto; text-align: left; line-height: 1.4em; } #TB_ajaxContent.TB_modal { padding: 15px; } #TB_ajaxContent p { padding: 5px 0px 5px 0px; } #TB_load { position: fixed; display: none; z-index: 100050; top: 50%; left: 50%; background-color: #E8E8E8; border: 1px solid #555; margin: -45px 0 0 -125px; padding: 40px 15px 15px; } #TB_HideSelect { z-index: 99; position: fixed; top: 0; left: 0; background-color: #fff; border: none; filter: alpha(opacity=0); opacity: 0; height: 100%; width: 100%; } #TB_iframeContent { clear: both; border: none; } .tb-close-icon { display: block; color: #666; text-align: center; line-height: 29px; width: 29px; height: 29px; position: absolute; top: 0; right: 0; } .tb-close-icon:before { content: "\f158"; font: normal 20px/29px dashicons; speak: never; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } #TB_closeWindowButton:hover .tb-close-icon, #TB_closeWindowButton:focus .tb-close-icon { color: #006799; } #TB_closeWindowButton:focus .tb-close-icon { -webkit-box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); box-shadow: 0 0 0 1px #5b9dd9, 0 0 2px 1px rgba(30, 140, 190, .8); } Legacy/admin/css/images/ui-icons_cccccc_256x240.png000064400000010421150212230450015614 0ustar00PNG  IHDRIJPLTENtRNS2P."Tp@f` <BHJZ&0R,4j8D|($ blߝF>n~hhHIDATx]b۶H儒-{iZK:glkn-tIqq? E$dK>$>;PZsVh!Sy0E0}H)-t koܪKp\RϠ .E7 ) *V;~Pe Bx*,=$zDؾ JҸٻ9{ ǸHpqW@"2'B[$ @TiH/b٥96!XHq`DE*R HV!%;" i] dddddddd4y5  Rb@(8CdŪݡ,@T@ibrq0alX!pe, =4bW { 5Ƭhu~(Q^@3="b5XC@JCT76q_5 @,r šɩD)T|O@ ON-ՙ [n@RXIm݋(F @?=0puL;g$@6η K`>п @h գKVn"a" %l@.v$/U^ G:#`` uTtK~ŋZ5T%kxk]\*Q ,҇B44 OXK|yg+_M(lоEO V$T1BXb-|?@ fBXr%'@ҹA\IJ,}BBc\V rh(]tI^}oצo S3 ";ʙb}"߰ ){b$Gwwݾab")T@pF_er6JvШ"mޭM-d76x˰6ӥ;/`>KrP\_^u1%OTM.}Q3.Nس})>-w`a+sy$t)NbFFFFBejnNVn4,A*X*5>PGa 3 {oB &<L[ Nc.öi=`Q@d ͆I.Il`\t[< Cit484-r +f쑱BCB MH iy }>rxp|z;BǏ;burcK4tz1G~`ؚK| ̔>ۡO$~ Ao)0pzz }i`;ADm8n:cfA@s7L Z/..h8or? N93B~o_'`opO- :TG L;7]`B%˛>*wTpM0H}&t ^1'Oqr'2P͡+z,tIW''|en=dzgRm[NStK{҉mؓVt6ҲR`ζN&}B U(rۗ&1%Q''?l׸+&r{jN಻4) `N狌. ߭ ǣ)q 2?n3Hb`} .`pqY1e_bu7e+N_F(DT,L}LLrmP5|x芥1cx DAb`M(7NED~Mz +4BXd.Mzv͈Pd8p<6?8N*x.6ڍ6GFZ)O !lSshssNp8`'0/<s}.@Ǩs7ξO۟VDa5av]m1+3y6۠>@u50Ps51==p *KVҫ܂ݻc$N4(Xr2###c- 賟Lδ>]5.sYs1f0;'̨Yg銛{@9 `aC(=%bo2=n1 jBoS$n#m=i0ci9}oI qT]W%.(؅]z\x f"]o'u䫵tk{v;AC3ֆwwR_#X (xҋ/q%W hpk_IX'b/fXKi"#####QCLi2t 5L0 QiH2;yTOok;ע ٶ`RNg{zy!Kxm?A(vU~mL(`o/!nmX-{v[ dw=n「sdwzn(}Oy~ m ?XU;,V'+ V&JRZ]᧭:zC'-߆@y 4u `Vۓwъ#zP@Q N>2/{\o)W~a3xLw :_Q;=pּdt\'8~3SRP6y+XQ*޺r ̗ѭ*޺r gl/\U^u$|mbVnw \V|D͊NVNy7k<;/E}?E*dzgO ~g/96f cD}% g$QG7o)U Jo,O@0߾Q(;bw:5 NwRN5Iy'K?}:9mֽ*@f@jU9mҫÍ{$ؗ}dFp|%!DdF>}G{@FFFFFFƦQܞH 3 u Mo~vy}mwz<7nP9rWku=|_nz쿳}@IXn?sn~hhHIDATx]b۶H儒-{iZK:glkn-tIqq? E$dK>$>;PZsVh!Sy0E0}H)-t koܪKp\RϠ .E7 ) *V;~Pe Bx*,=$zDؾ JҸٻ9{ ǸHpqW@"2'B[$ @TiH/b٥96!XHq`DE*R HV!%;" i] dddddddd4y5  Rb@(8CdŪݡ,@T@ibrq0alX!pe, =4bW { 5Ƭhu~(Q^@3="b5XC@JCT76q_5 @,r šɩD)T|O@ ON-ՙ [n@RXIm݋(F @?=0puL;g$@6η K`>п @h գKVn"a" %l@.v$/U^ G:#`` uTtK~ŋZ5T%kxk]\*Q ,҇B44 OXK|yg+_M(lоEO V$T1BXb-|?@ fBXr%'@ҹA\IJ,}BBc\V rh(]tI^}oצo S3 ";ʙb}"߰ ){b$Gwwݾab")T@pF_er6JvШ"mޭM-d76x˰6ӥ;/`>KrP\_^u1%OTM.}Q3.Nس})>-w`a+sy$t)NbFFFFBejnNVn4,A*X*5>PGa 3 {oB &<L[ Nc.öi=`Q@d ͆I.Il`\t[< Cit484-r +f쑱BCB MH iy }>rxp|z;BǏ;burcK4tz1G~`ؚK| ̔>ۡO$~ Ao)0pzz }i`;ADm8n:cfA@s7L Z/..h8or? N93B~o_'`opO- :TG L;7]`B%˛>*wTpM0H}&t ^1'Oqr'2P͡+z,tIW''|en=dzgRm[NStK{҉mؓVt6ҲR`ζN&}B U(rۗ&1%Q''?l׸+&r{jN಻4) `N狌. ߭ ǣ)q 2?n3Hb`} .`pqY1e_bu7e+N_F(DT,L}LLrmP5|x芥1cx DAb`M(7NED~Mz +4BXd.Mzv͈Pd8p<6?8N*x.6ڍ6GFZ)O !lSshssNp8`'0/<s}.@Ǩs7ξO۟VDa5av]m1+3y6۠>@u50Ps51==p *KVҫ܂ݻc$N4(Xr2###c- 賟Lδ>]5.sYs1f0;'̨Yg銛{@9 `aC(=%bo2=n1 jBoS$n#m=i0ci9}oI qT]W%.(؅]z\x f"]o'u䫵tk{v;AC3ֆwwR_#X (xҋ/q%W hpk_IX'b/fXKi"#####QCLi2t 5L0 QiH2;yTOok;ע ٶ`RNg{zy!Kxm?A(vU~mL(`o/!nmX-{v[ dw=n「sdwzn(}Oy~ m ?XU;,V'+ V&JRZ]᧭:zC'-߆@y 4u `Vۓwъ#zP@Q N>2/{\o)W~a3xLw :_Q;=pּdt\'8~3SRP6y+XQ*޺r ̗ѭ*޺r gl/\U^u$|mbVnw \V|D͊NVNy7k<;/E}?E*dzgO ~g/96f cD}% g$QG7o)U Jo,O@0߾Q(;bw:5 NwRN5Iy'K?}:9mֽ*@f@jU9mҫÍ{$ؗ}dFp|%!DdF>}G{@FFFFFFƦQܞH 3 u Mo~vy}mwz<7nP9rWku=|_nz쿳}@IXn?s R!!,c $PxB +*-[dඁ+i@ )`L ?'I`JGb Ph XB)0׸XQ# } No "tI+ZI!!,\ $P`8* 1h0rx8BQaV  !MDl!4%BBe PDY00!!,] $$I>Q] d"28 GqH9 A2ȀB", DH('4C \0`UL"r(!! ,d $dI`ìkBB m A72, (PX鲪 8@R%a K*D2E {$ft5C%!;Legacy/admin/css/images/ui-icons_ffffff_256x240.png000064400000010421150212230450015636 0ustar00PNG  IHDRIJPLTE NtRNS2P."Tp@f` <BHJZ&0R,4j8D|($ blߝF>n~hhHIDATx]b۶H儒-{iZK:glkn-tIqq? E$dK>$>;PZsVh!Sy0E0}H)-t koܪKp\RϠ .E7 ) *V;~Pe Bx*,=$zDؾ JҸٻ9{ ǸHpqW@"2'B[$ @TiH/b٥96!XHq`DE*R HV!%;" i] dddddddd4y5  Rb@(8CdŪݡ,@T@ibrq0alX!pe, =4bW { 5Ƭhu~(Q^@3="b5XC@JCT76q_5 @,r šɩD)T|O@ ON-ՙ [n@RXIm݋(F @?=0puL;g$@6η K`>п @h գKVn"a" %l@.v$/U^ G:#`` uTtK~ŋZ5T%kxk]\*Q ,҇B44 OXK|yg+_M(lоEO V$T1BXb-|?@ fBXr%'@ҹA\IJ,}BBc\V rh(]tI^}oצo S3 ";ʙb}"߰ ){b$Gwwݾab")T@pF_er6JvШ"mޭM-d76x˰6ӥ;/`>KrP\_^u1%OTM.}Q3.Nس})>-w`a+sy$t)NbFFFFBejnNVn4,A*X*5>PGa 3 {oB &<L[ Nc.öi=`Q@d ͆I.Il`\t[< Cit484-r +f쑱BCB MH iy }>rxp|z;BǏ;burcK4tz1G~`ؚK| ̔>ۡO$~ Ao)0pzz }i`;ADm8n:cfA@s7L Z/..h8or? N93B~o_'`opO- :TG L;7]`B%˛>*wTpM0H}&t ^1'Oqr'2P͡+z,tIW''|en=dzgRm[NStK{҉mؓVt6ҲR`ζN&}B U(rۗ&1%Q''?l׸+&r{jN಻4) `N狌. ߭ ǣ)q 2?n3Hb`} .`pqY1e_bu7e+N_F(DT,L}LLrmP5|x芥1cx DAb`M(7NED~Mz +4BXd.Mzv͈Pd8p<6?8N*x.6ڍ6GFZ)O !lSshssNp8`'0/<s}.@Ǩs7ξO۟VDa5av]m1+3y6۠>@u50Ps51==p *KVҫ܂ݻc$N4(Xr2###c- 賟Lδ>]5.sYs1f0;'̨Yg銛{@9 `aC(=%bo2=n1 jBoS$n#m=i0ci9}oI qT]W%.(؅]z\x f"]o'u䫵tk{v;AC3ֆwwR_#X (xҋ/q%W hpk_IX'b/fXKi"#####QCLi2t 5L0 QiH2;yTOok;ע ٶ`RNg{zy!Kxm?A(vU~mL(`o/!nmX-{v[ dw=n「sdwzn(}Oy~ m ?XU;,V'+ V&JRZ]᧭:zC'-߆@y 4u `Vۓwъ#zP@Q N>2/{\o)W~a3xLw :_Q;=pּdt\'8~3SRP6y+XQ*޺r ̗ѭ*޺r gl/\U^u$|mbVnw \V|D͊NVNy7k<;/E}?E*dzgO ~g/96f cD}% g$QG7o)U Jo,O@0߾Q(;bw:5 NwRN5Iy'K?}:9mֽ*@f@jU9mҫÍ{$ؗ}dFp|%!DdF>}G{@FFFFFFƦQܞH 3 u Mo~vy}mwz<7nP9rWku=|_nz쿳}@IXn?sh2:first-child{display:none}.gallery_page_nggallery-tags #ngg_page_content div.updated{margin:0 0 15px 0}.gallery_page_nggallery-tags #ngg_page_content div.updated#message{margin-bottom:35px}.ngg_manage_tags,.ngg_manage_tags label{color:#666}.ngg_wrap .auto_list{width:98%;margin:3px 0;padding:3px 5px}.ngg_wrap .list_tags{width:280px;vertical-align:top;padding:20px!important;background:#f7f7f7}.ngg_wrap .list_tags #search{width:200px}.ngg_wrap .list_tags .navigation{margin:25px 0 20px}#ngg_page_content .list_tags .navigation .button-primary{width:48%!important;text-align:center;margin:.5%;font-size:9px;padding:0!important}.ngg_wrap .forms_manage{vertical-align:top;padding-left:30px}.ngg_wrap .forms_manage h3{margin-bottom:5px;margin-top:30px}.ngg_wrap .forms_manage td{padding:0}.ngg_wrap .forms_manage td p{margin-bottom:20px}.ngg_wrap .forms_manage .form-table{margin-top:0}.ngg_wrap .forms_manage .form-table td,.ngg_wrap .forms_manage .form-table th{vertical-align:middle;padding:0}.ngg_wrap .sort_order h3{margin:30px 0 10px}.ngg_wrap #ajax_area_tagslist ul{list-style:square;margin:10px 0 10px 20px;padding:0}.ngg_wrap #ajax_area_tagslist ul li{margin:0;padding:0;line-height:1.4}.ngg_wrap #ajax_area_tagslist ul li span{cursor:pointer}@media (max-width:640px){.ngg_wrap .list_tags{width:100%;display:block;box-sizing:border-box}.ngg_wrap .forms_manage{width:100%;display:block;box-sizing:border-box;padding:20px}.ngg_wrap .list_tags #search{width:200px;width:100%}}Legacy/admin/css/tags-admin.css000064400000004074150212230450012365 0ustar00.gallery_page_nggallery-tags .wrap>h2:first-child { display:none; } .gallery_page_nggallery-tags #ngg_page_content div.updated { margin: 0 0 15px 0; } .gallery_page_nggallery-tags #ngg_page_content div.updated#message { margin-bottom: 35px; } .ngg_manage_tags, .ngg_manage_tags label { color: #666; } .ngg_wrap .auto_list{ width: 98%; margin: 3px 0; padding: 3px 5px; } .ngg_wrap .list_tags { width: 280px; vertical-align: top; padding: 20px !important; background: #f7f7f7; } .ngg_wrap .list_tags #search{ width: 200px; } .ngg_wrap .list_tags .navigation { margin: 25px 0 20px; } #ngg_page_content .list_tags .navigation .button-primary { width: 48% !important; text-align: center; margin: 0.5%; font-size: 9px; padding: 0 !important; } .ngg_wrap .forms_manage { vertical-align: top; padding-left: 30px; } .ngg_wrap .forms_manage h3 { margin-bottom: 5px; margin-top: 30px; } .ngg_wrap .forms_manage td { padding: 0; } .ngg_wrap .forms_manage td p { margin-bottom: 20px; } .ngg_wrap .forms_manage .form-table { margin-top: 0; } .ngg_wrap .forms_manage .form-table th, .ngg_wrap .forms_manage .form-table td { vertical-align: middle; padding: 0; } /*.ngg_wrap .forms_manage .form-table tr:nth-of-type(2) th, .ngg_wrap .forms_manage .form-table tr:nth-of-type(3) th { padding-left: 20px; }*/ .ngg_wrap .sort_order h3 { margin: 30px 0 10px; } .ngg_wrap #ajax_area_tagslist ul { list-style: square; margin: 10px 0 10px 20px; padding: 0; } .ngg_wrap #ajax_area_tagslist ul li { margin: 0; padding: 0; line-height: 1.4; } .ngg_wrap #ajax_area_tagslist ul li span { cursor: pointer; } /* Media Queries */ @media (max-width: 640px) { .ngg_wrap .list_tags { width: 100%; display: block; box-sizing: border-box; } .ngg_wrap .forms_manage { width: 100%; display: block; box-sizing: border-box; padding: 20px; } .ngg_wrap .list_tags #search { width: 200px; width: 100%; } }Legacy/admin/css/nggSorter.css000064400000003057150212230450012313 0ustar00.imageBox,.imageBoxHighlighted{ width:130px; /* Total width of each image box */ height:160px; /* Total height of each image box */ float:left; } .imageBox_theImage{ width:110px; /* Width of image */ height:125px; /* Height of image */ /* Don't change these values * */ background-position: center; background-repeat: no-repeat; margin: 0 auto; margin-bottom:2px; } .imageBox .imageBox_theImage{ border:1px solid #DDD; /* Border color for not selected images */ padding:2px; } .imageBoxHighlighted .imageBox_theImage{ border:3px solid #316AC5; /* Border color for selected image */ padding:0px; } .imageBoxHighlighted span{ /* Title of selected image */ background-color: #316AC5; color:#FFFFFF; padding:2px; } .imageBox_label{ /* Title of images - both selected and not selected */ text-align:center; font-family: arial; font-size:11px; padding-top:2px; margin: 0 auto; } /* DIV that indicates where the dragged image will be placed */ #insertionMarker{ height:150px; width:6px; position:absolute; } #insertionMarkerLine{ width:6px; /* No need to change this value */ height:145px; /* To adjust the height of the div that indicates where the dragged image will be dropped */ } #insertionMarker img{ float:left; } /* DIV that shows the image as you drag it */ #dragDropContent{ opacity:0.4; /* 40 % opacity */ filter:alpha(opacity=40); /* 40 % opacity */ /* No need to change these three values */ position:absolute; z-index:10; display:none; }Legacy/admin/css/jquery.ui.tabs.css000064400000010747150212230450013230 0ustar00/* Caution! Ensure accessibility in print and other media types... */ @media projection, screen { /* Use class for showing/hiding tab content, so that visibility can be better controlled in different media types... */ .ui-tabs-hide { display: none; } } /* Hide useless elements in print layouts... */ @media print { .ui-tabs-nav { display: none; } } /* Skin */ #slider { border-color:#EBEBEB rgb(204, 204, 204) rgb(204, 204, 204) rgb(235, 235, 235); border-style:solid; border-width:1px; margin:15px 15% 0pt 15px; padding:2px; } #tabs{ display: block; background:#F1F1F1 none repeat scroll 0%; font-size:14px; overflow:hidden; } .ui-tabs-nav { list-style: none; margin: 0; padding: 0 0 0 10px; } .ui-tabs-nav:after { /* clearing without presentational markup, IE gets extra treatment */ display: block; clear: both; content: " "; } .ui-tabs-nav li { float: left; padding: 6px 5px; min-width: 84px; /* be nice to Opera */ margin: 2px 2px 0px 1px !important; text-decoration: none; list-style: none; } .ui-tabs-nav a, .ui-tabs-nav a span { display: block; padding: 0 1px; } .ui-tabs-nav a { margin: 1px 0 0; /* position: relative makes opacity fail for disabled tab in IE */ padding-left: 0; color: #2583AD; line-height: 1.2; text-align: center; text-decoration: none; white-space: nowrap; /* required in IE 6 */ outline: 0; /* prevent dotted border in Firefox */ } .ui-tabs-nav .ui-tabs-selected{ background: #6D6D6D url(../images/menu-bits.gif) repeat-x scroll left top; border-color: #6D6D6D; color: #FFFFFF; text-shadow:0 -1px 0 #666666; -moz-border-radius-topright: 6px; -khtml-border-top-right-radius: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; -moz-border-radius-topleft: 6px; -khtml-border-top-left-radius: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; } .ui-tabs-selected a, .ui-tabs-selected a:hover { color:#FFFFFF !important; } .ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav .ui-tabs-selected a:hover { position: relative; top: 1px; z-index: 2; margin-top: 0; } .ui-tabs-nav li a:hover { color:#D54E21; } .ui-tabs-nav a span { width: 64px; /* IE 6 treats width as min-width */ min-width: 64px; height: 18px; /* IE 6 treats height as min-height */ min-height: 18px; padding-top: 6px; padding-right: 0; } *>.ui-tabs-nav a span { /* hide from IE 6 */ width: auto; height: auto; } .ui-tabs-nav .ui-tabs-selected a span { padding-bottom: 1px; } .ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active { background-position: 100% -150px; } .ui-tabs-nav a, .ui-tabs-nav .ui-tabs-disabled a:hover, .ui-tabs-nav .ui-tabs-disabled a:focus, .ui-tabs-nav .ui-tabs-disabled a:active { background-position: 100% -100px; } .ui-tabs-nav .ui-tabs-selected a span, .ui-tabs-nav a:hover span, .ui-tabs-nav a:focus span, .ui-tabs-nav a:active span { background-position: 0 -50px; } .ui-tabs-nav a span, .ui-tabs-nav .ui-tabs-disabled a:hover span, .ui-tabs-nav .ui-tabs-disabled a:focus span, .ui-tabs-nav .ui-tabs-disabled a:active span { background-position: 0 0; } .ui-tabs-nav .ui-tabs-selected a:link, .ui-tabs-nav .ui-tabs-selected a:visited, .ui-tabs-nav .ui-tabs-disabled a:link, .ui-tabs-nav .ui-tabs-disabled a:visited { /* @ Opera, use pseudo classes otherwise it confuses cursor... */ cursor: text; } .ui-tabs-nav a:hover, .ui-tabs-nav a:focus, .ui-tabs-nav a:active, .ui-tabs-nav .ui-tabs-unselect a:hover, .ui-tabs-nav .ui-tabs-unselect a:focus, .ui-tabs-nav .ui-tabs-unselect a:active { /* @ Opera, we need to be explicit again here now... */ cursor: pointer; } .ui-tabs-disabled { opacity: .4; filter: alpha(opacity=40); } .ui-tabs-panel { border-top: 1px solid #97a5b0 !important; padding: 1em 8px; background: #fff; /* declare background color for container to avoid distorted fonts in IE while fading */ /* overwrite wp-admin */ border:none !important; height:100% !important; margin:0pt 0pt 0pt 0px !important; overflow:visible !important; } .ui-tabs-panel a { display:inline; } /* Additional IE specific bug fixes... */ * html .ui-tabs-nav { /* auto clear, @ IE 6 & IE 7 Quirks Mode */ display: inline-block; } *:first-child+html .ui-tabs-nav { /* @ IE 7 Standards Mode - do not group selectors, otherwise IE 6 will ignore complete rule (because of the unknown + combinator)... */ display: inline-block; } Legacy/admin/css/nggColorPicker.css000064400000000473150212230450013250 0ustar00#colorSelector{ background:transparent url(../images/select.png) repeat scroll 0 0; height:36px; position:relative; width:36px; } #colorSelector div{ background:transparent url(../images/select.png) repeat scroll center center; height:30px; left:3px; position:absolute; top:3px; width:30px; }Legacy/admin/css/nggadmin.min.css000064400000062605150212230450012713 0ustar00#iframely h2.title{display:none}.toplevel_page_nextgen-gallery #ngg_page_content{width:98%}.toplevel_page_nextgen-gallery #ngg_page_content .about-wrap.ngg_overview{width:100%}.toplevel_page_nextgen-gallery #ngg_page_content .ngg_page_content_main{padding-right:40px!important}#newversion{border-color:#ccc;border-style:solid;border-width:1px;margin-right:7px;margin-top:10px;padding:2px}.ngg-dashboard-widget ul.settings span{padding-left:10px;color:#2583ad;font-weight:700}.ngg-overview .postbox .handlediv{float:right;height:24px;width:24px}#ngg_page_content .ngg_overview .ngg_page_content_header h2{padding-top:2px}#ngg_page_content .ngg_overview .ngg_page_content_main h2{text-align:left;font-size:22px;font-weight:400;color:#000;margin:20px 0 20px;text-transform:uppercase;letter-spacing:2px}#ngg_page_content .ngg_overview .ngg_page_content_main .about-text{font-size:17px;max-width:none;margin:20px 0;color:#000;font-weight:400}#ngg-gallery-wizard{min-height:auto;position:absolute;top:0;right:0;text-align:right;margin:0 20px 0 0;line-height:80px;color:#fff;font-size:14px;margin-right:0;color:#000;font-weight:400;letter-spacing:.5px}#ngg_page_content #ngg-gallery-wizard a{font-weight:700;text-decoration:none;margin-left:20px;height:50px!important;line-height:50px}.warning{color:#9f6000;background-color:#feefb3;border:1px solid;margin:5px 0;padding:5px}#donator_message{margin:5px 0 15px;background-color:#bde5f8;border-color:#00529b;-moz-border-radius-bottomleft:3px;-moz-border-radius-bottomright:3px;-moz-border-radius-topleft:3px;-moz-border-radius-topright:3px;border-style:solid;border-width:1px;margin:5px 15px 2px;padding:0 .6em}#donator_message p{line-height:1;margin:.5em 0;padding:2px;padding-bottom:10px}#donator_message span{padding-top:10px;float:right}#plugin_check img{float:right}#plugin_check p.message{font-size:90%;color:#666}.toplevel_page_nextgen-gallery .feature-video iframe{box-shadow:0 0 8px 4px rgba(0,0,0,.03);width:800px;height:450px;max-width:100%}div[data-id=welcome-link] .about-text{margin:0 0 40px!important}div[data-id=pro-link] .feature-section{position:relative;margin:40px 0;padding-bottom:56.25%}div[data-id=pro-link] .feature-section iframe{width:900px;height:506px;max-width:100%;position:absolute;top:0;left:0;width:100%;height:100%}#ngg_page_content .button-primary.ngg-pro-upgrade{height:50px!important;padding:0 40px!important;line-height:50px}div[data-id=genesis-link] .feature-section,div[data-id=genesis-link] .feature-section .col,div[data-id=videos-link] .feature-section,div[data-id=videos-link] .feature-section .col{padding:0;margin:0}.ngg-admin .ui-dialog{max-width:100%}.ngg-options th{width:22%}a.switch-expert{text-decoration:none}#wm-preview{float:right;font-size:90%;width:35%;border-color:#ebebeb #ccc #ccc #ebebeb;border-style:solid;border-width:1px;margin-bottom:10px;margin-left:10px;margin-right:8px;padding:2px}#wm-preview h3{background:#f9f9f9 none repeat scroll 0;font-size:14px;font-weight:700;margin:0 0 10px;padding:8px 5px}#wm-position{width:100%;margin-left:40px}.wm-table{border-collapse:collapse;margin-top:1em;width:60%;clear:none}.wm-table td{border-bottom:8px solid #fff;line-height:20px;margin-bottom:9px;padding:10px}.wm-table th{border-bottom:8px solid #fff;padding:10px;text-align:left}.wm-table tr{background:#f9f9f9 none repeat scroll 0}.ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content .notice,.ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content div.error,.ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content div.updated{margin:10px 0 40px 0}.ngg_admin_notice ul{list-style:circle inside;margin:0;padding:0}.gallery_page_nggallery-manage-gallery #ngg_page_content .ngg_page_content_main{padding-top:30px}.ngg-admin.gallery_page_nggallery-manage-gallery #ngg_page_content div.updated#message{margin-bottom:35px}.gallery_page_nggallery-manage-gallery #ngg_page_content>.wrap>h2{display:none}#ngg_page_content .ngg_manage_galleries .tablenav{margin:0 0 30px}#ngg_page_content .ngg_manage_images .handlediv{float:none;width:100%;height:50px}#gallerydiv h3{margin-left:10px;display:inline-block;height:50px;float:left;margin:0;line-height:50px;text-transform:uppercase;font-size:16px;letter-spacing:1.5px}#gallerydiv span.toggle-indicator{display:inline-block;float:left;line-height:50px}#gallerydiv span.toggle-indicator:before{font-size:24px;margin:12px 20px 0 10px}#gallerydiv span.toggle-indicator:hover{cursor:pointer}#gallerydiv h3:active,#gallerydiv h3:focus,#gallerydiv span.toggle-indicator:active,#gallerydiv span.toggle-indicator:focus{outline:0;border:none;-moz-outline-style:none}#ngg_page_content .ngg_manage_images .tablenav{margin:50px 0 30px}#ngg_page_content .ngg_manage_galleries .tablenav.top>div,#ngg_page_content .ngg_manage_images .tablenav.top>div{margin-bottom:10px}#ngg_page_content .ngg_manage_galleries .search-box-wrapper{display:flex;flex-direction:row;justify-content:center;width:100%}#ngg_page_content .ngg_manage_galleries div.search-box{display:flex;flex-direction:row;justify-content:center}#ngg_page_content .ngg_manage_galleries .search-box input[type=text]{width:calc(100% - 150px)!important;height:35px!important;margin-right:4px!important}#ngg_page_content .ngg_manage_galleries .search-box input[type=submit].button-primary{width:150px!important;height:35px!important;padding:0!important}#ngg_page_content .ngg_manage_galleries form.search-form{width:100%}#ngg_page_content .ngg_manage_galleries form.search-form:first-of-type{padding-right:25px}#ngg_page_content #editgalleries .displaying-num{margin-right:7px!important;font-size:14px;letter-spacing:1px}#ngg_page_content #editgalleries #bulkaction{min-height:35px;max-height:35px}#ngg_page_content .ngg_manage_galleries .tablenav.bottom{margin:15px 0 0}#ngg_page_content .ngg_manage_images .tablenav.bottom{margin:25px 0 0}.ngg-admin #ngg_page_content .ngg_manage_images td{vertical-align:top}#ngg_page_content .ngg_manage_galleries .tablenav input{height:28px;width:50px;padding:0 3px}#ngg_page_content .ngg_manage_galleries .tablenav input.current-page{width:50px!important}#ngg_page_content .ngg_manage_images .tablenav .tablenav-pages{margin-top:0}#ngg_page_content .ngg_manage_galleries .tablenav .tablenav-pages{margin-top:6px}#ngg_page_content .ngg_manage_galleries .tablenav .tablenav-pages a,#ngg_page_content .ngg_manage_images .tablenav .tablenav-pages a{background:#000;border:none;color:#fff!important;margin:0 2px;text-decoration:none;font-size:20px;padding:4px;line-height:20px;padding:2px 8px 6px 8px}#ngg_page_content .ngg_manage_images .tablenav input,#ngg_page_content .ngg_manage_images .tablenav select{width:auto;margin-top:0}#ngg_page_content #ngg-manage-images-items-per-page,#ngg_page_content .ngg_manage_images .tablenav input.current-page{padding:4px!important;text-align-last:center;background-image:none}#ngg_page_content .ngg_manage_galleries table{box-shadow:none;border:1px solid rgba(159,187,26,.08)!important}#ngg_page_content .ngg_manage_galleries table tfoot,#ngg_page_content .ngg_manage_galleries table thead{background-color:#000}#ngg_page_content .ngg_manage_galleries table tfoot td,#ngg_page_content .ngg_manage_galleries table tfoot th,#ngg_page_content .ngg_manage_galleries table thead td,#ngg_page_content .ngg_manage_galleries table thead th{background-color:transparent;border:none}#ngg_page_content .ngg_manage_galleries table td,#ngg_page_content .ngg_manage_galleries table th{padding:12px 10px;font-size:14px}#ngg_page_content .ngg_manage_galleries table th{font-weight:700!important;color:#fff}.ngg_manage_galleries th#id{width:33px}.ngg_manage_galleries th#title{min-width:140px}.ngg_manage_galleries td.title{text-transform:uppercase;font-weight:400;font-size:13px!important}.ngg_manage_galleries th#author{min-width:80px}.ngg_manage_galleries th#page_id{min-width:60px}#ngg_page_content .ngg_manage_galleries table tr.alternate{background-color:#f7f7f7}#ngg_page_content .ngg_manage_galleries th a{padding:0!important;color:#fff}div#poststuff{min-width:auto}div#poststuff #gallerydiv{cursor:pointer}p#ngg-inlinebutton{float:right;margin:0;position:relative;top:-25pt}#gallery_fields{width:100%}#gallery_fields td{padding:5px;min-width:105px}#gallery_fields tr td:nth-of-type(2){padding-right:60px}#gallery_fields input[type=text],#gallery_fields select,#gallery_fields textarea{min-width:220px;width:99%;color:#888}table#ngg-listimages{border:1px solid #f7f7f7}#ngg-listimages tfoot,#ngg-listimages thead{background:#000}#ngg-listimages tfoot{background:#000}#ngg-listimages.widefat thead th,.ngg-admin #ngg_page_content .widefat tfoot th{padding:12px 10px!important}#ngg-listimages tr.alternate{background-color:#f7f7f7}#ngg-listimages td{padding:15px 5px!important}#ngg-listimages .iedit,#ngg-listimages .iedit td,#ngg-listimages th{border:none}#ngg-listimages .iedit td,#ngg-listimages th{padding:15px 5px}#ngg-listimages th{font-size:12px;font-weight:700}#ngg-listimages .column select{width:100%!important}#ngg-listimages .column-1 input{margin:0 0 0 8px}#ngg-listimages .column-1{width:24px}#ngg-listimages .column-2{width:30px}#ngg-listimages .column-3{min-width:80px;width:15%}#ngg-listimages .column-3 .thumb{max-height:100%;max-width:100%}#ngg-listimages .column-4{width:15%;max-width:220px}#ngg-listimages .column-4{font-size:12px}#ngg-listimages .column-4 .meta,#ngg-listimages .column-4 label{font-size:10px;color:#888}#ngg-listimages .column-4 label input[type=checkbox]{margin:-2px 4px 0 0}#ngg-listimages .column-5 input[type=text],#ngg-listimages .column-5 textarea,#ngg-listimages .column-6 textarea{width:100%;padding:3px 5px;font-size:12px;color:#888;border:1px solid #eee;margin:1px 0;box-shadow:none}#ngg-listimages .column-5 input[type=text]{height:25px}#ngg-listimages .column-5 textarea{height:70px}#ngg-listimages .column-6 textarea{height:97px}#ngg-listimages .column-7 select{font-size:12px}#ngg-listimages .row-actions{padding:0 0 6px 4px;margin-bottom:-2px;position:relative;bottom:4px;left:0;right:0}#ngg-listimages .row_actions,#ngg-listimages .row_actions td{border-top:none;padding:0!important}#ngg-listimages .row-actions a{font-size:12px}#ngg-listimages ul.imagify-datas-list .big{color:#9fbb1a}#ngg-listimages .imagify-datas-more-action a{background:#9fbb1a;color:#fff}.gallery_page_nggallery-manage-gallery .ui-dialog{border:none;padding:0;max-width:95%!important;z-index:10000!important;margin:0 auto!important}.gallery_page_nggallery-manage-album .ui-dialog{border:none;padding:0;z-index:10000!important;width:650px!important;max-width:98%!important}.gallery_page_nggallery-manage-album .ui-dialog .button-primary,.gallery_page_nggallery-manage-album .ui-dialog .button-secondary,.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-primary,.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-secondary,.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom button,.gallery_page_nggallery-manage-gallery .ui-dialog .button-primary,.gallery_page_nggallery-manage-gallery .ui-dialog .button-secondary,.gallery_page_nggallery-manage-gallery .ui-dialog button{background-color:#9fbb1a!important;color:#fff!important;border:none!important;box-shadow:none!important;text-shadow:none!important;height:35px!important;padding:0 15px!important;line-height:35px;width:auto!important;margin-right:10px;text-transform:uppercase;letter-spacing:1px}.gallery_page_nggallery-manage-album .ui-dialog .button-primary:hover,.gallery_page_nggallery-manage-album .ui-dialog .button-secondary:hover,.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-primary:hover,.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom .button-secondary:hover,.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom button:hover,.gallery_page_nggallery-manage-gallery .ui-dialog .button-secondary:hover,.gallery_page_nggallery-manage-gallery .ui-dialog button:hover .gallery_page_nggallery-manage-gallery .ui-dialog .button-primary:hover{background-color:#a9c524!important}.gallery_page_nggallery-manage-album .ui-dialog-titlebar,.gallery_page_nggallery-manage-gallery .ui-dialog-titlebar{background:#000;padding:10px}.gallery_page_nggallery-manage-album .ui-dialog-titlebar .ui-dialog-title,.gallery_page_nggallery-manage-gallery .ui-dialog-titlebar .ui-dialog-title{text-transform:uppercase;letter-spacing:1px}.gallery_page_nggallery-manage-album .ui-dialog-titlebar button,.gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button{background:#fff!important;border:none!important;box-shadow:none!important;text-shadow:none!important;height:24px!important;width:24px!important;padding:0!important;line-height:1;float:none;margin-right:0;border-radius:50%;top:17px;right:10px}.gallery_page_nggallery-manage-album .ui-dialog-titlebar button:active,.gallery_page_nggallery-manage-album .ui-dialog-titlebar button:focus,.gallery_page_nggallery-manage-album .ui-dialog-titlebar button:hover,.gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button:active,.gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button:focus,.gallery_page_nggallery-manage-gallery .ui-dialog-titlebar button:hover{background:#fff!important}.gallery_page_nggallery-manage-album .ui-dialog .ngg-overlay-dialog,.gallery_page_nggallery-manage-gallery .ui-dialog .ngg-overlay-dialog{padding:30px 20px;box-sizing:border-box;width:100%!important}.gallery_page_nggallery-manage-gallery .ngg-overlay-dialog table{border:none}.gallery_page_nggallery-manage-album .ngg-overlay-dialog #ngg-overlay-dialog-main,.gallery_page_nggallery-manage-gallery .ngg-overlay-dialog #ngg-overlay-dialog-main{width:70%;padding:20px 20px 0}.gallery_page_nggallery-manage-gallery .ngg-overlay-dialog td small{margin-left:10px;display:block;text-align:center;width:200px;margin:0 auto 20px}.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom{text-align:center;padding:30px 0 0 0}.gallery_page_nggallery-manage-gallery #ngg-overlay-dialog-bottom input[type=button]{float:none;margin-right:0}.gallery_page_nggallery-manage-gallery .ngg-overlay-dialog #thumbMsg{color:#693;display:none;font-size:11px;width:100%;display:inline-block;height:35px;line-height:35px;margin:10px 0}.gallery_page_nggallery-manage-gallery .ui-dialog form{margin-top:30px;margin-left:30px}.gallery_page_nggallery-manage-gallery .ngg-overlay-dialog input[type=radio]:focus{border:1px solid #b4b9be;box-shadow:none}.gallery_page_nggallery-manage-gallery input[type=checkbox]:checked:before{color:#9fbb1a}.gallery_page_nggallery-manage-gallery .ngg-overlay-dialog input[type=radio]:checked:before{background:#9fbb1a;width:14px;height:14px;margin:0}div .progressborder{border:1px solid #ddd;display:block;height:30px;background-color:#464646;width:100%;margin-top:15px;margin-bottom:15px;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}div .progressbar{border:medium none;display:block;height:30px;background-color:#9fbb1a;width:0%;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}div .progressbar span{display:inline;position:absolute;color:#fff;font-weight:700;padding:5px 0 0 5px}.show_details{height:16px;line-height:20px;overflow:hidden;min-width:8em;padding:3px;cursor:pointer}.show_details span{border-bottom:1px solid #999;white-space:pre}.show_details:hover{height:auto;overflow:visible;border:1px solid #999}.gallery_page_nggallery-manage-album .wrap>h2:first-child{display:none}.gallery_page_nggallery-manage-album #ngg_page_content div.updated{margin:0 0 15px 0}.gallery_page_nggallery-manage-album #ngg_page_content div.updated#message{margin-bottom:35px}.ngg_manage_albums .widget{box-sizing:border-box;border:1px solid #eee;padding:10px 10px 20px;margin:0 1% 0 0;width:100%}.ngg_manage_albums .widget:last-of-type{margin-right:0}.container{margin-top:10px}.ngg_manage_albums .container{margin-top:30px;display:flex;flex-direction:row;justify-content:center}.ngg_select_album{margin:0 50px 0 2px;vertical-align:middle}#newalbum,.ngg_new_album{vertical-align:middle}.albumnav select[name=act_album]{width:150px}#editalbum select[name=pageid]{width:95%}#ngg_page_content .ngg_manage_albums .widget-top{box-shadow:none;background:0 0;border:none;margin:-10px -10px 20px -10px;background:#f7f7f7}div .groupItem{cursor:move;padding:2px;line-height:1.5;width:100%;margin:0;box-sizing:border-box}div .innerhandle{background-color:#fbfbfb}.groupItem .item_top{background-color:#9fbb1a;color:#fff;font-weight:400;line-height:28px;height:28px;padding:0 5px;border-radius:0;height:40px;padding:0 10px;line-height:40px}#ngg_page_content .groupItem .album_obj{background-color:#000}#ngg_page_content .groupItem .item_top a{color:#fff;float:right;text-decoration:none}.groupItem .item_top a:hover{color:#fff}.itemContent{border-color:#dfdfdf;border-style:none solid solid;border-width:0 1px 1px;padding:2px 0 20px 2px}.itemContent p{border:0;margin:0;padding:0}.inlinepicture{float:left;display:inline;margin:0;padding:0 3px 1px}.inlinepicture img{margin:3px;max-height:60px}.sort_placeholder{border:1px dashed #bba!important;margin:5px;background:#f9f9f9}.widget-holder{min-height:400px;padding-top:1px}.target{background-color:transparent}div.widget-top h3{text-align:center;line-height:25px;margin:0;padding:5px 12px;font-size:13px;letter-spacing:.5px;text-transform:uppercase}div.widget-top{text-shadow:0 1px 0 #fff;background-repeat:repeat-x;background-position:0 0;font-size:13px}.ui-autocomplete-start{background-position:99% center}#ngg_page_content .ngg_gallery_sort .tablenav{margin:15px 0}#ngg_page_content .ngg_gallery_sort ul.subsubsub{margin:10px 0 15px}#ngg_page_content .ngg_gallery_sort .imageBox_theImage{width:auto}#sortGallery{position:relative}p#sortButton{margin:0;position:absolute;right:0;top:0}#ngg-sort-gallery-container{display:flex;flex-wrap:wrap}.imageBox,.imageBoxHighlighted{width:130px;height:160px;overflow:hidden;text-overflow:ellipsis;padding:5px}.imageBox_theImage{width:110px;height:125px;background-position:center;background-repeat:no-repeat;margin:0 auto;margin-bottom:2px}.imageBox_label{text-align:center;font-family:arial;font-size:11px;padding-top:2px;margin:0 auto}#insertionMarker{height:150px;width:6px;position:absolute}#insertionMarkerLine{width:6px;height:145px}#insertionMarker img{float:left}#dragDropContent{opacity:.4;position:absolute;z-index:10;display:none}.error_inline{background:#ffebe8 none repeat scroll 0;border:1px solid #c00;margin:5px auto;padding:10px}.ngg-list{font-size:11px;margin-left:15px;list-style-position:inside;list-style-type:disc}#ngg-manage-images-items-per-page-label{float:right;line-height:35px;margin-right:5px}#ngg-manage-images-items-per-page{float:right;margin-right:30px}@media (max-width:1200px){div[data-id=details-link] .two-col .col{width:100%;min-width:100%}}@media (max-width:1080px){#ngg-gallery-wizard>span{display:none}.ngg_manage_galleries .tablenav.bottom{display:none}.ngg_manage_images #gallery_fields td:nth-of-type(even){margin-bottom:8px}.ngg_manage_images #gallery_fields td:nth-of-type(odd){background:#f7f7f7;padding-left:10px;font-weight:700}.ngg_manage_images #gallery_fields,.ngg_manage_images #gallery_fields tbody,.ngg_manage_images #gallery_fields td,.ngg_manage_images #gallery_fields tr{display:block;width:100%;box-sizing:border-box}.ngg_manage_images #gallery_fields td{padding:10px 5px;border:1px solid #f7f8f3;margin:0}}@media (max-width:900px){.ngg_manage_galleries tfoot{display:none}.ngg_manage_galleries .wp-list-table tr:not(.inline-edit-row):not(.no-items) td:not(.check-column){display:table-cell}.ngg_manage_galleries td.author,.ngg_manage_galleries td.id,.ngg_manage_galleries td.page_id,.ngg_manage_galleries th#author,.ngg_manage_galleries th#id,.ngg_manage_galleries th#page_id{display:none!important}#ngg-listimages td.column.column-2,#ngg-listimages td.column.column-6,#ngg-listimages td.column.column-8,#ngg-listimages tfoot,#ngg-listimages thead .column-1,#ngg-listimages thead .column-2,#ngg-listimages thead .column-4,#ngg-listimages thead .column-5,#ngg-listimages thead .column-6,#ngg-listimages thead .column-7,#ngg-listimages thead .column-8{display:none}#ngg-listimages .column-3{min-width:200px}table#ngg-listimages,table#ngg-listimages thead{display:block}#ngg-listimages .iedit td{padding-bottom:30px!important}}@media (max-width:800px){table#ngg-listimages,table#ngg-listimages tbody,table#ngg-listimages td,table#ngg-listimages tr{display:block}table#ngg-listimages tr{padding:10px 5px!important}#ngg-listimages thead,#ngg-listimages thead th{display:block;width:100%;box-sizing:border-box}#ngg-listimages .row_actions td:first-of-type{display:none}#ngg-listimages tfoot{display:none}#ngg-listimages .row_actions{display:none;display:block;clear:both;padding:0 8px 10px!important;border-bottom:1px solid #c1c97c}.ngg-listimages tr.iedit td{display:block!important;float:left;box-sizing:border-box;padding-bottom:10px!important}#ngg-listimages td.column-1,#ngg-listimages td.column-2{width:10%!important;height:150px;float:left;box-sizing:border-box;display:none}#ngg-listimages td.column-3{width:55%;max-width:300px;float:left;box-sizing:border-box;padding-bottom:10px!important}#ngg-listimages td.column-4{width:40%!important;float:left;box-sizing:border-box}#ngg-listimages td.column-5,#ngg-listimages td.column-6,#ngg-listimages td.column-7{padding:0 5px!important}#ngg-listimages td.column-6{margin-top:-5px;margin-bottom:-8px}.ngg-listimages td.column-7{padding-bottom:15px}#ngg-manage-images-items-per-page,#ngg-manage-images-items-per-page-label{display:none}#ngg-listimages .column-6 textarea{height:60px}.ngg_manage_images .tablenav.bottom .displaying-num{display:none}}@media (max-width:782px){#ngg-gallery-wizard{display:none}#ngg_page_content .ngg_manage_galleries .tablenav.top>div{display:block;width:100%}#ngg_page_content .ngg_manage_galleries .tablenav .tablenav-pages{margin-top:20px;margin-bottom:28px!important}#ngg_page_content .ngg_manage_galleries .search-box input[type=text]{width:calc(100% - 150px)!important}#ngg_page_content .ngg_manage_galleries .search-box input[type=submit].button-primary{height:40px!important}#ngg_page_content .ngg_manage_galleries .search-box-wrapper{flex-direction:column}#ngg_page_content .ngg_manage_galleries form.search-form{width:100%}#ngg_page_content #editgalleries div.tablenav.top div.alignleft.actions input.button-primary{width:auto!important;display:inline-block}#ngg_page_content #editgalleries div.tablenav.top div.alignleft.actions input.button-primary:first-of-type{margin-left:5px}#ngg_page_content #editgalleries div.tablenav.top div.tablenav-pages{display:none}#ngg_page_content #editgalleries #bulkaction{width:auto!important}}@media (max-width:737px){.gallery_page_nggallery-manage-gallery input[type=checkbox]:checked:before{font-size:22px}.ngg-overlay-dialog input[type=radio]{height:16px;width:16px}#ngg-gallery-wizard{display:none}}@media (max-width:640px){.ngg_manage_galleries td.description,.ngg_manage_galleries th#description{display:none!important}.ngg_manage_albums .tablenav .actions{width:100%;float:none}.ngg_manage_albums .tablenav span{display:block}.ngg_manage_albums .target-album,.ngg_manage_albums .widget.widget-right{width:32%!important;margin:.5%!important;padding:5px 5px 10px}.groupItem .item_top{height:auto!important;line-height:1.5;padding:8px;font-size:12px}#ngg_page_content .groupItem .item_top a{display:none}.ngg_manage_albums div[style="float:right;"]{float:none!important}.gallery_page_nggallery-manage-gallery .ui-dialog{width:95%!important;left:2.5%!important}.gallery_page_nggallery-manage-gallery .ui-dialog .ngg-overlay-dialog{padding:30px 10px}.ngg-overlay-dialog td{display:block;width:100%!important;padding:0!important}.ngg-overlay-dialog input[type=radio]{margin:2px 5px;height:16px;width:16px}}#TB_overlay{background:#000;opacity:.7;position:fixed;top:0;right:0;bottom:0;left:0;z-index:100050}#TB_window{position:fixed;background-color:#fff;z-index:100050;visibility:hidden;text-align:left;top:50%;left:50%;-webkit-box-shadow:0 3px 6px rgba(0,0,0,.3);box-shadow:0 3px 6px rgba(0,0,0,.3)}#TB_window img#TB_Image{display:block;margin:15px 0 0 15px;border-right:1px solid #ccc;border-bottom:1px solid #ccc;border-top:1px solid #666;border-left:1px solid #666}#TB_caption{height:25px;padding:7px 30px 10px 25px;float:left}#TB_closeWindow{height:25px;padding:11px 25px 10px 0;float:right}#TB_closeWindowButton{position:absolute;left:auto;right:0;width:29px;height:29px;border:0;padding:0;background:0 0;cursor:pointer;outline:0;-webkit-transition:color .1s ease-in-out,background .1s ease-in-out;transition:color .1s ease-in-out,background .1s ease-in-out}#TB_ajaxWindowTitle{float:left;font-weight:600;line-height:29px;overflow:hidden;padding:0 29px 0 10px;text-overflow:ellipsis;white-space:nowrap;width:calc(100% - 39px)}#TB_title{background:#fcfcfc;border-bottom:1px solid #ddd;height:29px}#TB_ajaxContent{clear:both;padding:2px 15px 15px 15px;overflow:auto;text-align:left;line-height:1.4em}#TB_ajaxContent.TB_modal{padding:15px}#TB_ajaxContent p{padding:5px 0 5px 0}#TB_load{position:fixed;display:none;z-index:100050;top:50%;left:50%;background-color:#e8e8e8;border:1px solid #555;margin:-45px 0 0 -125px;padding:40px 15px 15px}#TB_HideSelect{z-index:99;position:fixed;top:0;left:0;background-color:#fff;border:none;opacity:0;height:100%;width:100%}#TB_iframeContent{clear:both;border:none}.tb-close-icon{display:block;color:#666;text-align:center;line-height:29px;width:29px;height:29px;position:absolute;top:0;right:0}.tb-close-icon:before{content:"\f158";font:normal 20px/29px dashicons;speak:never;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#TB_closeWindowButton:focus .tb-close-icon,#TB_closeWindowButton:hover .tb-close-icon{color:#006799}#TB_closeWindowButton:focus .tb-close-icon{-webkit-box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8);box-shadow:0 0 0 1px #5b9dd9,0 0 2px 1px rgba(30,140,190,.8)}Legacy/admin/overview.php000064400000034333150212230450011417 0ustar00 '', 'status' => 'ok', ]; \Imagely\NGG\Display\DisplayManager::enqueue_fontawesome(); if ( $action_status['message'] != '' ) { ?>

    ' . __('Launch Gallery Wizard', 'nggallery') . ''; ?>
    */ ?>

    NextGEN Gallery University on YouTube to see all available vidoes.', 'nggallery' ), esc_url( 'https://www.youtube.com/playlist?list=PL9cmsdHslD0vIcJjBggJ-XMjtwvqrRgoM' ) ); ?>

    NextGEN Gallery University on YouTube.', 'nggallery' ), esc_url( 'https://www.youtube.com/playlist?list=PL9cmsdHslD0vIcJjBggJ-XMjtwvqrRgoM' ) ); ?>

    [ __( 'Filmstrip Gallery', 'nggallery' ) => [ true, false ], __( 'Masonry Gallery', 'nggallery' ) => [ true, false ], __( 'Mosaic Gallery', 'nggallery' ) => [ true, false ], __( 'Tiled Gallery', 'nggallery' ) => [ true, false ], __( 'Film Gallery', 'nggallery' ) => [ true, false ], __( 'Blogstyle Gallery', 'nggallery' ) => [ true, false ], ], __( 'Ecommerce', 'nggallery' ) => [ __( 'Ecommerce', 'nggallery' ) => [ true, false ], __( 'Paid Digital Downloads', 'nggallery' ) => [ true, false ], __( 'Coupons', 'nggallery' ) => [ true, false ], __( 'Price Lists', 'nggallery' ) => [ true, false ], __( 'Automated Tax Calculations', 'nggallery' ) => [ true, false ], __( 'Automated Print Fulfillment', 'nggallery' ) => [ true, false ], __( 'Proofing', 'nggallery' ) => [ true, false ], ], __( 'Interface', 'nggallery' ) => [ __( 'Hover Captions', 'nggallery' ) => [ true, false ], __( 'Lazy Loading', 'nggallery' ) => [ true, false ], __( 'Infinite Scroll', 'nggallery' ) => [ true, false ], ], __( 'Image Upload / Processing', 'nggallery' ) => [ __( 'Lightroom Plugin', 'nggallery' ) => [ true, false ], ], __( 'Other', 'nggallery' ) => [ __( 'Digital Downloads', 'nggallery' ) => [ true, false ], __( 'Image Protection', 'nggallery' ) => [ true, false ], __( 'Image Commenting', 'nggallery' ) => [ true, false ], __( 'Image Deeplinking', 'nggallery' ) => [ true, false ], __( 'Full-Screen Lightbox', 'nggallery' ) => [ true, false ], __( 'Image Social Sharing', 'nggallery' ) => [ true, false ], __( 'Lightbox Slideshow', 'nggallery' ) => [ true, false ], ], ]; ?> $block ) { ?> $supports ) { ?>

    Get NextGEN Pro Today and Unlock all the Powerful Features

    Bonus: NextGEN Gallery users get 50% off the regular price using in the link above.

    $preset ) { if ( $current === 1 ) { ?>
    get_saved_meta(); $exifdata = $meta->get_EXIF(); $iptcdata = $meta->get_IPTC(); $xmpdata = $meta->get_XMP(); $class = ''; ?>

    $value ) { if ( in_array( $key, [ 'created_timestamp', 'timestamp' ] ) && is_numeric( $value ) ) { $value = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $value ); } if ( is_array( $value ) ) { continue; } $class = ( $class == 'class="alternate"' ) ? '' : 'class="alternate"'; echo ''; } ?>
    ' . esc_html( $meta->i18n_name( $key ) ) . ' ' . esc_html( $value ) . '
    ' . esc_html__( 'No meta data saved', 'nggallery' ) . '';} ?>

    $value ) { if ( in_array( $key, [ 'created_timestamp', 'timestamp' ] ) && is_numeric( $value ) ) { $value = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $value ); } if ( $key == 'created_date' ) { $value = date_i18n( get_option( 'date_format' ), strtotime( $value ) ); } $class = ( $class == 'class="alternate"' ) ? '' : 'class="alternate"'; echo ''; } ?>
    ' . esc_html( $meta->i18n_name( $key ) ) . ' ' . esc_html( $value ) . '
    ' . esc_html__( 'No exif data', 'nggallery' ) . '';} ?>

    $value ) { if ( in_array( $key, [ 'created_timestamp', 'timestamp' ] ) && is_numeric( $value ) ) { $value = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $value ); } $class = ( $class == 'class="alternate"' ) ? '' : 'class="alternate"'; echo ''; } ?>
    ' . esc_html( $meta->i18n_name( $key ) ) . ' ' . esc_html( $value ) . '

    $value ) { if ( in_array( $key, [ 'created_timestamp', 'timestamp' ] ) && is_numeric( $value ) ) { $value = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $value ); } $class = ( $class == 'class="alternate"' ) ? '' : 'class="alternate"'; echo ''; } ?>
    ' . esc_html( $meta->i18n_name( $key ) ) . ' ' . esc_html( $value ) . '
    Legacy/admin/ajax.php000064400000011743150212230450010474 0ustar00reimport_metadata( $id ) ? '1' : '0'; break; case 'get_image_ids': $result = nggAdmin::get_image_ids( $id ); break; // This will read the EXIF and then write it with the Orientation tag reset. case 'strip_orientation_tag': $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); $image_path = $storage->get_image_abspath( $id ); $backup_path = $image_path . '_backup'; $exif_abspath = @file_exists( $backup_path ) ? $backup_path : $image_path; $exif_iptc = @\Imagely\NGG\DataStorage\EXIFWriter::read_metadata( $exif_abspath ); foreach ( $storage->get_image_sizes( $id ) as $size ) { if ( $size === 'backup' ) { continue; } @\Imagely\NGG\DataStorage\EXIFWriter::write_metadata( $storage->get_image_abspath( $id, $size ), $exif_iptc ); } $result = '1'; break; default: do_action( 'ngg_ajax_' . $_POST['operation'] ); die( '-1' ); break; } // A success should return a '1'. die( $result ); } // The script should never stop here. die( '0' ); } add_action( 'wp_ajax_createNewThumb', 'createNewThumb' ); function createNewThumb() { // check for correct capability. if ( ! is_user_logged_in() ) { die( '-1' ); } // check for correct NextGEN capability. if ( ! current_user_can( 'NextGEN Manage gallery' ) ) { die( '-1' ); } if ( ! wp_verify_nonce( $_POST['nonce'], 'ngg_update_thumbnail' ) ) { die( '-1' ); } $id = (int) $_POST['id']; $x = round( $_POST['x'] * $_POST['rr'], 0 ); $y = round( $_POST['y'] * $_POST['rr'], 0 ); $w = round( $_POST['w'] * $_POST['rr'], 0 ); $h = round( $_POST['h'] * $_POST['rr'], 0 ); $crop_frame = [ 'x' => $x, 'y' => $y, 'width' => $w, 'height' => $h, ]; $storage = \Imagely\NGG\DataStorage\Manager::get_instance(); // XXX NextGEN Legacy wasn't handling watermarks or reflections at this stage, so we're forcefully disabling them to maintain compatibility. $params = [ 'watermark' => false, 'reflection' => false, 'crop' => true, 'crop_frame' => $crop_frame, ]; $result = $storage->generate_thumbnail( $id, $params ); if ( $result ) { echo 'OK'; } else { header( 'HTTP/1.1 500 Internal Server Error' ); echo 'KO'; } exit(); } add_action( 'wp_ajax_rotateImage', 'ngg_rotateImage' ); function ngg_rotateImage() { // check for correct capability. if ( ! is_user_logged_in() ) { die( '-1' ); } if ( ! wp_verify_nonce( $_POST['nonce'], 'ngg-rotate-image' ) ) { die( '-1' ); } // check for correct NextGEN capability. if ( ! current_user_can( 'NextGEN Manage gallery' ) ) { die( '-1' ); } require_once dirname( __DIR__ ) . '/ngg-config.php'; // include the ngg function. include_once __DIR__ . '/functions.php'; $id = (int) $_POST['id']; $result = '-1'; switch ( $_POST['ra'] ) { case 'cw': $result = nggAdmin::rotate_image( $id, 'CW' ); break; case 'ccw': $result = nggAdmin::rotate_image( $id, 'CCW' ); break; case 'fv': // Note: H/V have been inverted here to make it more intuitive. $result = nggAdmin::rotate_image( $id, 0, 'H' ); break; case 'fh': // Note: H/V have been inverted here to make it more intuitive. $result = nggAdmin::rotate_image( $id, 0, 'V' ); break; } // recreate the thumbnail. nggAdmin::create_thumbnail( $id ); if ( $result == 1 ) { die( '1' ); } header( 'HTTP/1.1 500 Internal Server Error' ); die( $result ); } Legacy/admin/images/facebook.png000064400000002072150212230450012557 0ustar00PNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<IDATxWKhQI&ĚDPt#h[S7* hJ*sa? hA "[)e)ZIic1R]͛yyof=5~sl _^C:ް~(v3NӦ:XJ dž@&G!tr݊;20|ZH&5xWd <Q`)7.uBn]cihbaZ\7JMK@{Es18*l0?:4RĘB` Bޫ,yӜeX2@UsUØbxBdj.9p YsQѢ⁸3J_01: Ma4tL@Y:sLtLbSE$ڹ?;ؑͤW^2L 1<l[ehj:(2L΀րE)SzP wҙ Հar P !X<~q-I0mQԄ 6Cc81?='-KԀaKW-X-Cn}nE0 R+ݓP%A0XR%1 xSTFݹ'==Or !Xޜ7öCEq]=rOxu?~q4JGG0g|!Hu7 e:I&} ,=k1ZIG8<IK@X_x^=<--/}-C[maIGstM| DHIJj#**Wi'0LVlW4M(6Cr)L璺J U5,ֺol;nnسrٓG!!S1fР}@qmBR1L> D;`3nz\;ሹ ye F'`7b,B+ &Gx+r 0<k {!y`KWZuP}U+3dуd\ L[ xdj̏ɵ&dý4S`vz!ى_PNAýAECt7>.ɺWyamwmbxtxރ ~/pa?D5A|ͭԕP: fO}vÝd/qUUTUյvFlmm]2ƬXk;u]wʲ4UUMx Adobe Photoshop CC 2015 (Macintosh) 2019-03-15T15:09:41-06:00 2019-03-15T15:14:16-06:00 2019-03-15T15:14:16-06:00 image/png 3 xmp.iid:f347c3b3-221f-441c-9330-4de0f7b2d965 adobe:docid:photoshop:b0d8d0ad-87f5-117c-9530-dc0cd962cc77 xmp.did:847520e6-7b88-417e-8583-b2fb23206b30 created xmp.iid:847520e6-7b88-417e-8583-b2fb23206b30 2019-03-15T15:09:41-06:00 Adobe Photoshop CC 2015 (Macintosh) saved xmp.iid:4e5ee218-6462-4e96-a64d-1f8638544487 2019-03-15T15:14:16-06:00 Adobe Photoshop CC 2015 (Macintosh) / saved xmp.iid:f347c3b3-221f-441c-9330-4de0f7b2d965 2019-03-15T15:14:16-06:00 Adobe Photoshop CC 2015 (Macintosh) / 1 10000/10000 10000/10000 2 65535 120 120 O cHRMz%u0`:o_FIDATx{Uu?{֭ Q1Y:"N0k1L2f0q%G`sʈOP2"T| Qh^MWս;;n=G[]pZVխ_8쳷IbD^*.x+2I5Ff;%-vV2CX$ j`A`DYA`rA6R4?rc.NMQ22 lh-vLS&1݅6;n#*迷Cd(2DE,Y "f DJj#I)3 7:u78g{ 0CcKI{f v=ƆVM6W!j'' Lh.E/ l lp7|#`׺BA`g(iGz_ۀS~>SBׁ)LWS#f&Lg"6!{p=S%;9uP#~JO*g!*@΍shLK&|'bs]K\`둪] L{+%3G /5a|Uو KG.lHgJL,Z c鋒 }=_{ɿ`Bs.ٟ<P! kd}/ΦP_ {s$)Q\\IN><_Cŗ#?"+߬{W"3 .>lDP 8" ;ރ^UEz.Xo*/ sR:ˠTQ|j:`ZHQ 0:\9o7[/9EF*axJ8zA\i# n*?:_ .i,"KFTe'>td\~^p;tgO~Z{ޮZEkOyq9{v2< ,4ރ\-~%l֍#p[&\wswvݗC8 lNt)e@{?5=q~N2~I~;_Jy_neXNzjޘotA=u2cwWrsy̞?4o҈:fǍrhjiXʣCمUbRҝ9v77#<$7nŏ(#hi8*$ᖸn} tQɍoOq!Zڄ[7冣{ȱvB -&aY`6kV8y0Pg3zTk3B/2X!I枌Y t-6w)sf *9<%Xte0|E3ѝn?33>N)S =}HǗsksEjnX, –HqTtZaj>\C9}xnnjT:]!$N[ND0[^>}[V)qԘx xJgЈ=⽓QR!P V Fk6b_li-?NZS%IA7VYo\;E ڭJ|YlPU<3ڪh̩6tM6S/k〭~HnΨ,x6X9s_AotbV905ΉVIkMv 1ЫZ/#T J*bS,񓳁Ӈ `_.tJrWO[c0f"89Xu0pfvjmrNO,yb)[\4/r {򼐵luN>Sb$5+xVax6 y3ab?`?j=<Ջ Zl+Ҵ@Q#OUO_yY9a%Q9E6HՃ9 ]S^g%缣~Y^mi(͏S3Gig]'fZBQzb!ϘWs߮Ol3r˳ _M,vDѡ;Í')4/*]ج-G?MH:XdXg`ۑ=`hfBx`]leS}܃b.ðWadAI[f2i[MX6U:(iMh4iњ2) =4!ZV{1L+5z2~ V6IU-C&izm10aܻޘm?1W/yKNU !;z΋q4WJe|č4EՁ( {H?D+0};4!BF]O6V ,ca6Vd9bMSVZ`s*ڬeQΠ)ѿ}QC#:hHH#fxڈ?z^ Bط$ݨBTdBo15a i'`q]_9kgH6`#! oZDeٻ) MKgGo_zPN->E~nh\]x=fчxωHe }sؠB;zѷwOr/~r[zw #6:*&ۧtaLKFuԹ.s.vsкXgwm sS678}Kwin?It{D1dD,( \QC \T>AJCcE&0IݲO6cE`RKд}' k>{[~?UNݱJjjR:s&C9⮡,Dhǜ wɆ>@1v}+ծRiRkvFvff#Bþ I K:u-^S! V"ZyH;c9,=6 C0[QklмLie㾣&J`{;0&xid!2`l>!n@GMw)൏ R-> B[u lA~ O+0D50wdzq&Jx?;/60[ѦGŒr]|S.c`a5CrGUז)gh]>* Xxt}q(7Vsk򢋲_ˮ֚S}Mt71$$HS|,Ft_-+uXi ,E3WصͯJ]u뒺.3pQ%ƙ47HqmįuM$߰T3;本ւz=Z+ϴQ).?ceYڔ^AObyփT|:]H)ț^k˖vY%Ss0zjwzrT?cɺ6O|h1hΓsD>Z# hRM*ʰ2ɼ Oԝ49=qlc ULOHHͅ-EY܏Ts T@ai&,Y2avFNQ-`:Ң1ʹԒ@mlNݘ R6`g&jƊ ^CagcPb ܆wyxiQrF>[$7u\S]Jѭp=p;r7aAMm+IyX[}LKmJyH~j9U3^'S|ZJl)üzFXSj=O3CG9.ǫ_UCY{RY[\1Uh\"?=_q_57y^d: Xf"G{;fq|WC5ò~%]{+RRĿ{QI[/'mEp;k|(秀V5]X{^Tt zjZ跰xFo-綦Ք5iߚR~y~zi1T%$eLY_oM~Fq0eL!\d`GfxK4E>B8%F|< P9=dgcxSYOWT(ƒp#ԝK16#;=g"4YgSXn6woR)ֿr 3 rHq~1?('8ʵm 0݉gft}cr숕{ 3vC˸SnWئŪm9K4Aadt:1Лk&htwo? ܾ5IENDB`Legacy/admin/images/select.png000064400000000772150212230450012272 0ustar00PNG  IHDR$$gAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxJ@w7zIR"\ ^ H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-?iTXtXML:com.adobe.xmp 2016-02-20T15:50:05-07:00 2017-06-04T13:43:19-06:00 2017-06-04T13:43:19-06:00 Adobe Photoshop CC 2015 (Macintosh) image/png 3 sRGB IEC61966-2.1 xmp.iid:0a0ea03a-292c-48c7-bdfc-603d81fdfd18 adobe:docid:photoshop:d6683a1d-0fea-117a-8834-df3f7cfb76ae xmp.did:22a37fe0-9407-4d59-805e-f8bf053f45d6 saved xmp.iid:22a37fe0-9407-4d59-805e-f8bf053f45d6 2016-05-30T16:42:30-06:00 Adobe Photoshop CC 2015 (Macintosh) / converted from application/vnd.adobe.photoshop to image/png derived converted from application/vnd.adobe.photoshop to image/png saved xmp.iid:118a24b3-6bba-4ad5-83cf-767b8365204b 2016-05-30T16:42:30-06:00 Adobe Photoshop CC 2015 (Macintosh) / saved xmp.iid:0a0ea03a-292c-48c7-bdfc-603d81fdfd18 2017-06-04T13:43:19-06:00 Adobe Photoshop CC 2015 (Macintosh) / xmp.iid:22a37fe0-9407-4d59-805e-f8bf053f45d6 xmp.did:22a37fe0-9407-4d59-805e-f8bf053f45d6 xmp.did:22a37fe0-9407-4d59-805e-f8bf053f45d6 1 3000000/10000 3000000/10000 2 1 120 119 V cHRMz%u0`:o_F^IDATxyUǿVuLB@,!Y,D ~"('(xFy|*$HL&o/U5: 3]Ku&C>|{Ws=\aY%_#(\BJP"%.a8~q/z â<(inayj70LZ Nq  @OC`=JDx<Ʊp$p},6 ^+ cN`K>e_:X .\Nv8p}X<l)YH)8bK̛E;ܑpn/ A2eLd)(p.~O*< DҢ@y.j-TtOI@zH {+l{3خǕRBO_hDOApm?m/cC5B0MHMgGx=sQQs qh|;)6 ɓ3߰-#;< -/\j7uUJ b .,n@Ŋ- ܗNj?t,vw~( 0hjtK O\+ ,uI8jLYHIVw5WJAU*m11ДE}mW,d/jK/WL.4A8l+N}=:>ߓiâ?`)j?vkSU$݆ UI&S!(C٧|iv#g7ڲ RRHka!TRGnFI=| ~dC2 U0drhLx6^B |$e@VGDS갰\;ɵshB'e&Y"TXj^N>9>\2YOAn2|IO"d--BPx:'Z68)uT5e-TF^4g[Rlz+&~=HW ٭i8;6= P,6[Ԗ+9n#m+~( 'xL}dKl2%frvL> b)!TPRh۩{!dt7궧 _/Dz\.}2Y5X*fMdQW)CI-p܊JvB|X^Nj}SϦ"?6@0Bj9`Iŀe+zSCTUק T83DHʀiM{O,SqD[\M.(>hv=ti.gGJj#eķ#!3FJqdrh4፤R6ֳ}7<#G$*CfEy@*imI.4zHRLG"0` νæE@ (j܃ɷ!쥾| }pSk&4VYLkح|:` U2Yo\l |H~̼)iI,9H8c+ 0uhez%>ڲ ңVgt66IJH$$4Z&Ά`Z)5:!QEm{%,r}e0d+܆in´$Td+RLEЯ (B oݍKFE)GI Q[eEH'Ri DeZタ|۔등eʯx Z8*$CyծoQ]^9ʲzBY;;oݙͶźƽ45j^Eh"4"9W%B|%x*#W 6ݶ?&>7˴wufh?ٶΏ soPA̷41 ѩLW1ڤQac}#As]Cu)4j4QbC[9l/9ա#ßDmL!荴s!Wֿͺ3_Befezl)4O"ivy7RVfZ3~7Na F8 gKo!2)3+(w'm 8ML΅L_o9xgʄfɐǛ"/ 2~9J~~āLN"P1"HuW;!&g◭cfFXȚVZILkܛs9fŞhKW6F!n*}%嬦x0Fݖ n`01CO ~-3.B kŐ̌xߣ1B  P3.Q֞bgYHnUS\` "nw+ #GDAˎ1. ` T@!Ńc2J]&؋B&l,".WY^d\O^Iq=_: !_DKG5Q>e/:V ͶE$xK&EbY&7nRG̅`/,:66,-M$EMTqe#Cffv7LJzyw'}F©Մ@;P#xP_VjY߱M=kinvJ4? ^iAB2|ю&S7ۯd詝6܅$ uQs ]!2DF]"EVfr~]G'?؋lT(*ڠr"/{m+iqexndL"0FzOIA΁W٩fW0fhY& xqc ;"K3 |:,[Eu~' WvBW'z4|`^zk\)Mav턎L_V{hz#~I=7i}*hpO#og|@@Ũ|u *{tr ~ق=M84s"x5;J4|UI❻( a.Euamv¡BUB7a7y"pG8+T b)B@(d&SVNJUOr' I6iV&{:=?{}bM$SvR͠z5_ޒBlVEm[#cY ?\wwvb:<\J%eZ#'/L&r5$^ ! G`@@F&6%4FWѺ.ICu=e {6W.⵺Sf:bO$˗>,k7rKR|>a:mёb۶b{Oj?v9 M-Qrf:bO< nT!x4 7BpUEgg-[,n4+PEba͵ uqo Vcy&ۓnHYOԻ!׏.pY q+{|bA-[1M'S4q2eT塿EM]%;HnB4tK.gq[&ioO ;CJ׎OCo%yf zVz Z뚇.(z3?nyH.~bxp˦ }`!bmKhW2J\ _Ū[󄂬RSkf[I[&+!w>6/¸\ ~Pi>M,SX+hHs|4h@ y5Qjkd lDlfK'>^!)jY&'|dҤ3IB!cȽ9&:K T;M"}gabtQ ->xE/`j _Huk]5P|M`J {sO0MMHe!ך?dM7?CPAj@Z%Y=*&>rH !4[50M\)y>$Kn!+2X/W )I0D%&:pSNpO^r;alԁ%۫y==R/&Zh3Jquy-irɽ`&':z14b8!UKw'tCsՠ҅HUWnMࢨC«᧣z87>{2{} H.*E-r'٨䯣+"oNYj{_nMխD.Ln]MKm#0u-!E,T{#-QSI.~Qf"skNuyh(*a0>LKK>MǴ Zg=F>+s6Q|CB[хg8\EJW=t!7jl%i$) -E#Ps||^lzdάl"[ 1 | 5y. QY^4 5N?w}wQWQeU|;h5]S-{*w7-M5y_^xinxy$-}fc%l.ɖealc.&̲WAPgi)(g([ZCo*&~={ˌ2֕]D&(H6rOߗYgfB!CO4o˜!#~ygD-J~cq#Ь E͚`T'ٻ jzfr.QB- xemCToˠBD*>!EUR3lc#~X?\PڞȵA}x{| u6oEn1X! O,EQR$@g0#nѿFXnх!-޲sk:_"kJw>/H'~~q (X 3{ '', 'status' => 'ok', ]; if ( isset( $_POST['tag_action'] ) ) { check_admin_referer( 'nggallery_admin_tags' ); if ( $_POST['tag_action'] == 'renametag' ) { $oldtag = ( isset( $_POST['renametag_old'] ) ) ? $_POST['renametag_old'] : ''; $newtag = ( isset( $_POST['renametag_new'] ) ) ? $_POST['renametag_new'] : ''; $action_status = nggTags::rename_tags( $oldtag, $newtag ); Transient::flush( 'displayed_gallery_rendering' ); } elseif ( $_POST['tag_action'] == 'deletetag' ) { $todelete = ( isset( $_POST['deletetag_name'] ) ) ? $_POST['deletetag_name'] : ''; $action_status = nggTags::delete_tags( $todelete ); Transient::flush( 'displayed_gallery_rendering' ); } elseif ( $_POST['tag_action'] == 'editslug' ) { $matchtag = esc_html( ( isset( $_POST['tagname_match'] ) ) ? $_POST['tagname_match'] : '' ); $newslug = ( isset( $_POST['tagslug_new'] ) ) ? $_POST['tagslug_new'] : ''; $newslug = esc_html( \Imagely\NGG\DataStorage\Sanitizer::strip_html( $newslug ) ); $action_status = nggTags::edit_tag_slug( $matchtag, $newslug ); Transient::flush( 'displayed_gallery_rendering' ); } } // Som useful variables. $admin_base_url = admin_url() . 'admin.php?page=nggallery-tags'; $nb_tags = 50; // Number of tags to show on a single page. // Manage URL. $sort_order = ( isset( $_GET['tag_sortorder'] ) ) ? esc_attr( stripslashes( $_GET['tag_sortorder'] ) ) : 'desc'; $search_url = ( isset( $_GET['search'] ) ) ? '&search=' . esc_attr( stripslashes( $_GET['search'] ) ) : ''; $action_url = $admin_base_url . '&tag_sortorder=' . $sort_order . $search_url; // Tags Filters. $order_array = [ 'desc' => __( 'Most popular', 'nggallery' ), 'asc' => __( 'Least used', 'nggallery' ), 'natural' => __( 'Alphabetical', 'nggallery' ), ]; // Build Tags Param. $param = 'hide_empty=false'; switch ( $sort_order ) { case 'natural': $param .= '&number=' . $nb_tags . '&orderby=name&order=asc'; break; case 'asc': $param .= '&number=' . $nb_tags . '&orderby=count&order=asc'; break; default: $param .= '&number=' . $nb_tags . '&orderby=count&order=desc'; break; } // Search. if ( ! empty( $_GET['search'] ) ) { $search = sanitize_text_field( wp_unslash( $_GET['search'] ) ); $param .= '&name__like=' . $search; } // Offset. if ( ! empty( $_GET['offset'] ) ) { $param .= '&offset=' . intval( $_GET['offset'] ); } // Navigation urls. if ( empty( $_GET['offset'] ) ) { $offset = 0; } else { $offset = intval( $_GET['offset'] ); } $tag_count = (int) wp_count_terms( [ 'ignore_empty' => true, 'taxonomy' => 'ngg_tag', ] ); if ( $offset + $nb_tags < $tag_count ) { $next_offset = '' . min( $offset + $nb_tags, $tag_count - $nb_tags ); } else { $next_offset = ''; } if ( $nb_tags < $tag_count && $offset > 0 ) { $prev_offset = '' . max( $offset - $nb_tags, 0 ); } else { $prev_offset = ''; } ?>

    $title ) { $output[] = ( $sort == $sort_order ) ? '' . $title . '' : '' . $title . ''; } echo implode( ' | ', $output ); $output = []; unset( $output ); ?>
      ' . $tag->name . ' ('.$tag->count.')'."\n";. echo '
    • ' . esc_html( $tag->name ) . ' ' . '(' . esc_html( $tag->count ) . ')
    • ' . "\n"; } unset( $tags ); ?>

    Slug definition. You can specify multiple tags to rename by separating them with commas.', 'nggallery' ); ?>

    Legacy/admin/roles.php000064400000013452150212230450010674 0ustar00


    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    role_objects; $sorted = []; if ( class_exists( 'RoleManager' ) ) { foreach ( $roles as $role_key => $role_name ) { $role = get_role( $role_key ); if ( empty( $role ) ) { continue; } $role_user_level = array_reduce( array_keys( $role->capabilities ), [ 'WP_User', 'level_reduction' ], 0 ); $sorted[ $role_user_level ] = $role; } $sorted = array_values( $sorted ); } else { $role_order = [ 'subscriber', 'contributor', 'author', 'editor', 'administrator' ]; foreach ( $role_order as $role_key ) { $sorted[ $role_key ] = get_role( $role_key ); } } return $sorted; } function ngg_get_role( $capability ) { // This function return the lowest roles which has the capabilities. $check_order = ngg_get_sorted_roles(); $args = array_slice( func_get_args(), 1 ); $args = array_merge( [ $capability ], $args ); foreach ( $check_order as $check_role ) { if ( empty( $check_role ) ) { return false; } if ( call_user_func_array( [ &$check_role, 'has_cap' ], $args ) ) { return $check_role->name; } } return false; } function ngg_set_capability( $lowest_role, $capability ) { // This function set or remove the $capability. $check_order = ngg_get_sorted_roles(); $add_capability = false; foreach ( $check_order as $the_role ) { $role = $the_role->name; if ( $lowest_role == $role ) { $add_capability = true; } // If you rename the roles, then please use a role manager plugin. if ( empty( $the_role ) ) { continue; } $add_capability ? $the_role->add_cap( $capability ) : $the_role->remove_cap( $capability ); } } ?>Legacy/admin/rotate.php000064400000006466150212230450011055 0ustar00get_image_url( $id, 'full' ); ?>



    Legacy/admin/media-upload.php000064400000035561150212230450012116 0ustar00 __( 'NextGEN Gallery', 'nggallery' ) ]; return array_merge( $tabs, $newtab ); } function media_upload_nextgen() { // Not in use. $errors = false; // Generate TinyMCE HTML output. if ( isset( $_POST['send'] ) ) { $keys = array_keys( $_POST['send'] ); $send_id = (int) array_shift( $keys ); $image = $_POST['image'][ $send_id ]; $alttext = stripslashes( htmlspecialchars( $image['alttext'], ENT_QUOTES ) ); $description = stripslashes( htmlspecialchars( $image['description'], ENT_QUOTES ) ); // here is no new line allowed. $clean_description = preg_replace( "/\n|\r\n|\r$/", ' ', $description ); $img = nggdb::find_image( $send_id ); $thumbcode = $img->get_thumbcode(); $class = "ngg-singlepic ngg-{$image['align']}"; // Create a shell displayed-gallery so we can inspect its settings. $args = new stdClass(); $args->display_type = NGG_BASIC_SINGLEPIC; $displayed_gallery = new \Imagely\NGG\DataTypes\DisplayedGallery( $args ); $width = $displayed_gallery->display_settings['width']; $height = $displayed_gallery->display_settings['height']; // Build output. if ( $image['size'] == 'thumbnail' ) { $html = "{$alttext}"; } else { $html = ''; } // Wrap the link to the fullsize image around. $html = "{$html}"; if ( $image['size'] == 'full' ) { $html = "{$alttext}"; } if ( $image['size'] == 'singlepic' ) { $html = "[singlepic id={$send_id} w={$width} h={$height} float={$image['align']}]"; } media_upload_nextgen_save_image(); // Return it to TinyMCE. return media_send_to_editor( $html ); } // Save button. if ( isset( $_POST['save'] ) ) { media_upload_nextgen_save_image(); } wp_iframe( 'media_upload_nextgen_form', $errors ); die(); } function media_upload_nextgen_save_image() { global $wpdb; check_admin_referer( 'ngg-media-form' ); if ( ! empty( $_POST['image'] ) ) { foreach ( $_POST['image'] as $image_id => $image ) { // create a unique slug. $image_slug = nggdb::get_unique_slug( sanitize_title( $image['alttext'] ), 'image' ); $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->nggpictures} SET `image_slug` = %s, `alttext` = %s, `description` = %s WHERE pid = %d", [ $image_slug, $image['alttext'], $image['description'], $image_id, ] ) ); wp_cache_delete( $image_id, 'ngg_image' ); } } } function media_upload_nextgen_form( $errors ) { global $wpdb, $ngg; media_upload_header(); $from = isset( $_GET['from'] ) && 'block-editor' === $_GET['from'] ? 'block-editor' : 'classic-editor'; $post_id = intval( $_REQUEST['post_id'] ); $galleryID = 0; $total = 1; $picarray = []; $chromeless = isset( $_GET['chromeless'] ) ? $_GET['chromeless'] : null; $chromeless_url = $chromeless ? ( '&chromeless=' . $chromeless ) : null; $form_action_url = site_url( "wp-admin/media-upload.php?type={$GLOBALS['type']}&tab=nextgen&post_id=$post_id" . $chromeless_url, 'admin' ); // Get number of images in gallery. if ( isset( $_REQUEST['select_gal'] ) ) { $galleryID = (int) $_REQUEST['select_gal']; $total = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->nggpictures} WHERE `galleryid` = %d", [ $galleryID, ] ) ); } // Build navigation. $_GET['paged'] = isset( $_GET['paged'] ) ? intval( $_GET['paged'] ) : 0; if ( $_GET['paged'] < 1 ) { $_GET['paged'] = 1; } $start = ( $_GET['paged'] - 1 ) * 10; if ( $start < 1 ) { $start = 0; } // Get the images. if ( $galleryID != 0 ) { // Using %i in $wpdb->prepare() to signify column identifiers was only added in WP 6.2 // // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $picarray = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT `pid` FROM {$wpdb->nggpictures} WHERE `galleryid` = %d AND `exclude` != 1 ORDER BY {$ngg->options['galSort']}, `pid` {$ngg->options['galSortDir']} LIMIT {$start}, 10", [ $galleryID, ] ) ); // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared } // WP-Core code for Post-thumbnail. $calling_post_id = 0; if ( isset( $_GET['post_id'] ) ) { $calling_post_id = $_GET['post_id']; } ?>
    add_query_arg( 'paged', '%#%' ), 'format' => '', 'total' => ceil( $total / 10 ), 'current' => $_GET['paged'], ] ); if ( $page_links ) { echo "
    $page_links
    "; } ?>


    get_image_dimensions( $picid, 'thumb' ); extract( $dimensions ); $thumb_url = $storage->get_image_url( $picid, 'thumb' ); ?>
    alttext ) ) ? wp_html_excerpt( esc_html( $picture->filename ), 60 ) : stripslashes( wp_html_excerpt( esc_html( $picture->alttext ), 60 ) ); ?>
    <?php echo esc_attr( $picture->alttext ); ?>
    filename ); ?>
    alttext ) ); ?>
     
    " . esc_html__( 'Use as featured image', 'nggallery' ) . ''; echo ""; ?>

    gid = (int) $_GET['gid']; $this->gallery = GalleryMapper::get_instance()->find( $this->gid, true ); } if ( isset( $_GET['pid'] ) ) { $this->pid = (int) $_GET['pid']; } if ( isset( $_GET['mode'] ) ) { $this->mode = trim( sanitize_text_field( wp_unslash( $_GET['mode'] ) ) ); } // Check for pagination request, avoid post process of other submit button, exclude search results. // Nonce verification not necessary here: we are only determining which page to view, whose ID is always // cast to an integer. NextGEN has historically used POST in places it shouldn't, such as pagination here. // // phpcs:disable WordPress.Security.NonceVerification.Missing if ( isset( $_POST['post_paged'] ) && ! isset( $_GET['s'] ) ) { if ( $_GET['paged'] != $_POST['post_paged'] ) { $_GET['paged'] = absint( $_POST['post_paged'] ); return; } } // phpcs:enable WordPress.Security.NonceVerification.Missing // Should be only called via manage galleries overview. if ( isset( $_POST['nggpage'] ) && 'manage-galleries' === $_POST['nggpage'] && wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'ngg_bulkgallery' ) ) { $this->post_processor_galleries(); } // Should be only called via a edit single gallery page. if ( isset( $_POST['nggpage'] ) && 'manage-images' === $_POST['nggpage'] && wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'ngg_updategallery' ) ) { $this->post_processor_images(); } // Look for other POST process. if ( ! empty( $_POST ) || ! empty( $_GET ) ) { $this->processor(); } M_NextGen_Admin::emit_do_notices_action(); } public function controller() { switch ( $this->mode ) { case 'sort': include_once __DIR__ . '/manage-sort.php'; nggallery_sortorder( $this->gid ); break; case 'edit': $this->setup_gallery_fields(); $this->setup_image_rows(); include_once __DIR__ . '/manage-images.php'; nggallery_picturelist( $this ); break; case 'main': default: include_once __DIR__ . '/manage-galleries.php'; nggallery_manage_gallery_main(); break; } } public function processor() { global $ngg, $nggdb; // Delete a picture. if ( $this->mode == 'delpic' ) { // TODO:Remove also Tag reference. check_admin_referer( 'ngg_delpicture' ); $image = $nggdb->find_image( $this->pid ); if ( $image ) { do_action( 'ngg_delete_picture', $this->pid, $image ); if ( $ngg->options['deleteImg'] ) { $storage = StorageManager::get_instance(); $storage->delete_image( $this->pid ); } $mapper = ImageMapper::get_instance(); $result = $mapper->destroy( $this->pid ); if ( $result ) { nggGallery::show_message( __( 'Picture', 'nggallery' ) . ' \'' . $this->pid . '\' ' . __( 'deleted successfully', 'nggallery' ) ); } } $this->mode = 'edit'; // show pictures. } // Recover picture from backup. if ( $this->mode == 'recoverpic' ) { check_admin_referer( 'ngg_recoverpicture' ); // bring back the old image. nggAdmin::recover_image( $this->pid ); nggGallery::show_message( __( 'Operation successful. Please clear your browser cache.', 'nggallery' ) ); $this->mode = 'edit'; // show pictures. } // will be called after a ajax operation. if ( isset( $_POST['ajax_callback'] ) ) { if ( $_POST['ajax_callback'] == 1 ) { nggGallery::show_message( __( 'Operation successful. Please clear your browser cache.', 'nggallery' ) ); } } // show sort order. if ( isset( $_POST['sortGallery'] ) ) { $this->mode = 'sort'; } if ( isset( $_GET['s'] ) ) { $this->search_images(); } } public function setup_image_rows() { add_filter( 'ngg_manage_images_row', [ &$this, 'render_image_row' ], 10, 2 ); add_filter( 'ngg_manage_images_column_1_header', [ &$this, 'render_image_column_1_header' ] ); add_filter( 'ngg_manage_images_column_1_content', [ &$this, 'render_image_column_1' ], 10, 2 ); add_filter( 'ngg_manage_images_column_2_header', [ &$this, 'render_image_column_2_header' ] ); add_filter( 'ngg_manage_images_column_2_content', [ &$this, 'render_image_column_2' ], 10, 2 ); add_filter( 'ngg_manage_images_column_3_header', [ &$this, 'render_image_column_3_header' ] ); add_filter( 'ngg_manage_images_column_3_content', [ &$this, 'render_image_column_3' ], 10, 2 ); add_filter( 'ngg_manage_images_column_4_header', [ &$this, 'render_image_column_4_header' ] ); add_filter( 'ngg_manage_images_column_4_content', [ &$this, 'render_image_column_4' ], 10, 2 ); add_filter( 'ngg_manage_images_column_5_header', [ &$this, 'render_image_column_5_header' ] ); add_filter( 'ngg_manage_images_column_5_content', [ &$this, 'render_image_column_5' ], 10, 2 ); add_filter( 'ngg_manage_images_column_6_header', [ &$this, 'render_image_column_6_header' ] ); add_filter( 'ngg_manage_images_column_6_content', [ &$this, 'render_image_column_6' ], 10, 2 ); } public function render_image_column_1_header() { return ''; } public function render_image_column_2_header() { return __( 'ID', 'nggallery' ); } public function render_image_column_3_header() { return __( 'Thumbnail', 'nggallery' ); } public function render_image_column_4_header() { return __( 'Filename', 'nggallery' ); } public function render_image_column_5_header() { return __( 'Alt & Title Text / Description', 'nggallery' ); } public function render_image_column_6_header() { return __( 'Tags', 'nggallery' ); } public function render_image_column_1( $output = '', $picture = [] ) { return ""; } public function render_image_column_2( $output = '', $picture = [] ) { return $picture->pid; } public function render_image_column_3( $output = '', $picture = [] ) { $image_url = add_query_arg( 'i', mt_rand(), $picture->imageURL ); $thumb_url = add_query_arg( 'i', mt_rand(), $picture->thumbURL ); $filename = esc_attr( $picture->filename ); $output = []; $output[] = ""; $output[] = ""; $output[] = ''; return ( $output = implode( "\n", $output ) ); } public function render_image_column_4( $output = '', $picture = [] ) { $image_url = Router::esc_url( $picture->imageURL ); $filename = esc_attr( $picture->filename ); $caption = esc_html( ( empty( $picture->alttext ) ? $picture->filename : $picture->alttext ) ); $data_caption = esc_attr( $caption ); $caption = \Imagely\NGG\Display\I18N::ngg_plain_text_alt_title_attributes( $caption ); $caption = esc_attr( $caption ); $date = mysql2date( get_option( 'date_format' ), $picture->imagedate ); $width = $picture->meta_data['width']; $height = $picture->meta_data['height']; $pixels = "{$width} x {$height} pixels"; $excluded = checked( $picture->exclude, 1, false ); $exclude_label = __( 'Exclude ?', 'nggallery' ); $output = []; $output[] = ""; $output[] = '
    ' . esc_html( $date ) . '
    '; $output[] = "
    {$pixels}
    "; $output[] = "'; return ( $output = implode( "\n", $output ) ); } public function render_image_column_5( $output = '', $picture = [] ) { $alttext = \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $picture->alttext ); $desc = \Imagely\NGG\Display\I18N::ngg_sanitize_text_alt_title_desc( $picture->description ); $output = []; $output[] = ""; $output[] = ""; return ( $output = implode( "\n", $output ) ); } public function render_image_column_6( $output = '', $picture = [] ) { global $wp_version; $fields = version_compare( $wp_version, '4.6', '<=' ) ? 'fields=names' : [ 'fields' => 'names' ]; $tags = wp_get_object_terms( $picture->pid, 'ngg_tag', $fields ); if ( is_array( $tags ) ) { $tags = implode( ', ', $tags ); } $tags = esc_html( $tags ); return ""; } public function render_image_row( $picture, $counter ) { // Get number of columns. $class = ! ( $counter % 2 == 0 ) ? '' : 'alternate'; $columns = apply_filters( 'ngg_manage_images_number_of_columns', 6 ); // Get the valid row actions. $actions = []; $row_actions = apply_filters( 'ngg_manage_images_row_actions', [ 'view' => [ &$this, 'render_view_action_link' ], 'meta' => [ &$this, 'render_meta_action_link' ], 'custom_thumb' => [ &$this, 'render_custom_thumb_action_link' ], 'rotate' => [ &$this, 'render_rotate_action_link' ], 'recover' => [ &$this, 'render_recover_action_link' ], 'delete' => [ &$this, 'render_delete_action_link' ], ] ); foreach ( $row_actions as $id => $callback ) { if ( is_callable( $callback ) ) { $result = call_user_func( $callback, $id, $picture ); if ( $result ) { $actions[] = $result; } } } // Output row columns. echo ""; for ( $i = 1; $i <= $columns; $i++ ) { $rowspan = $i > 4 ? "rowspan='2'" : ''; echo ""; echo apply_filters( "ngg_manage_images_column_{$i}_content", '', $picture ); echo ''; } echo ''; // Actions row. echo ""; echo ''; echo ""; echo "
    "; echo implode( ' | ', $actions ); echo '
    '; echo ''; echo ''; } public function render_view_action_link( $id, $picture ) { $image_url = Router::esc_url( $picture->imageURL ); $label = esc_html__( 'View', 'nggallery' ); $alt_text = empty( $picture->alttext ) ? $picture->filename : $picture->alttext; $data_title = esc_attr( __( 'View', 'nggallery' ) ) . ' "' . esc_attr( $alt_text ) . '"'; $alt_text = \Imagely\NGG\Display\I18N::ngg_plain_text_alt_title_attributes( $alt_text ); $title = esc_attr( __( 'View', 'nggallery' ) ) . ' "' . esc_attr( $alt_text ) . '"'; return "{$label}"; } public function render_meta_action_link( $id, $picture ) { $url = Router::esc_url( NGGALLERY_URLPATH . 'admin/showmeta.php?id=' . $picture->pid . '&nonce=' . \wp_create_nonce( 'ngg_meta_popup' ) ); $title = esc_attr__( 'Show meta data', 'nggallery' ); $label = esc_html__( 'Meta', 'nggallery' ); return "{$label}"; } public function render_custom_thumb_action_link( $id, $picture ) { $url = Router::esc_url( NGGALLERY_URLPATH . 'admin/edit-thumbnail.php?id=' . $picture->pid . '&nonce=' . \wp_create_nonce( 'ngg_edit_thumbnail' ) ); $title = esc_attr__( 'Customize thumbnail', 'nggallery' ); $label = esc_html__( 'Edit thumb', 'nggallery' ); return "{$label}"; } public function render_rotate_action_link( $id, $picture ) { $url = Router::esc_url( NGGALLERY_URLPATH . 'admin/rotate.php?id=' . $picture->pid . '&nonce=' . \wp_create_nonce( 'ngg_edit_rotation' ) ); $title = esc_attr__( 'Rotate', 'nggallery' ); $label = esc_html__( 'Rotate', 'nggallery' ); return "{$label}"; } public function render_recover_action_link( $id, $picture ) { if ( ! file_exists( $picture->imagePath . '_backup' ) ) { return false; } $url = wp_nonce_url( "admin.php?page=nggallery-manage-gallery&mode=recoverpic&gid={$picture->galleryid}&pid={$picture->pid}", 'ngg_recoverpicture' ); $title = esc_attr__( 'Recover image from backup', 'nggallery' ); $label = esc_html__( 'Recover', 'nggallery' ); $question = __( 'Recover', 'nggallery' ); $alttext = empty( $picture->alttext ) ? $picture->filename : $picture->alttext; $alttext = Sanitizer::strip_html( html_entity_decode( $alttext ), true ); $alttext = htmlentities( $alttext, ENT_QUOTES | ENT_HTML401 ); $alttext = \Imagely\NGG\Display\I18N::ngg_plain_text_alt_title_attributes( $alttext ); $alttext = esc_attr( $alttext ); // Event handler is found in nextgen_admin_page.js. return "{$label}"; } public function render_delete_action_link( $id, $picture ) { $url = wp_nonce_url( "admin.php?page=nggallery-manage-gallery&mode=delpic&gid={$picture->galleryid}&pid={$picture->pid}", 'ngg_delpicture' ); $title = esc_attr__( 'Delete image', 'nggallery' ); $label = esc_html__( 'Delete', 'nggallery' ); $question = __( 'Delete', 'nggallery' ); $alttext = empty( $picture->alttext ) ? $picture->filename : $picture->alttext; $alttext = Sanitizer::strip_html( html_entity_decode( $alttext ), true ); $alttext = htmlentities( $alttext, ENT_QUOTES | ENT_HTML401 ); $alttext = \Imagely\NGG\Display\I18N::ngg_plain_text_alt_title_attributes( $alttext ); $alttext = esc_attr( $alttext ); // Event handler is found in nextgen_admin_page.js. return "{$label}"; } public function render_image_row_header() { $columns = apply_filters( 'ngg_manage_images_number_of_columns', 6 ); echo ''; for ( $i = 1; $i <= $columns; $i++ ) { echo ""; echo apply_filters( 'ngg_manage_images_column_' . $i . '_header', "Column #{$i}" ); echo ''; } echo ''; } public function setup_gallery_fields() { add_filter( 'ngg_manage_gallery_fields', [ &$this, 'default_gallery_fields' ], 10, 2 ); } public function default_gallery_fields( $fields = [], $gallery = null ) { $fields['left'] = [ 'title' => [ 'callback' => [ &$this, 'render_gallery_title_field' ], 'label' => __( 'Title:', 'nggallery' ), 'tooltip' => null, 'id' => 'gallery_title', ], 'description' => [ 'callback' => [ &$this, 'render_gallery_desc_field' ], 'label' => __( 'Description:', 'nggallery' ), 'tooltip' => null, 'id' => 'gallery_desc', ], 'path' => [ 'callback' => [ &$this, 'render_gallery_path_field' ], 'label' => __( 'Gallery path:', 'nggallery' ), 'tooltip' => null, 'id' => 'gallery_path', ], 'gallery_author' => [ 'callback' => [ &$this, 'render_gallery_author_field' ], 'label' => __( 'Author', 'nggallery' ), 'tooltip' => null, 'id' => 'gallery_author', ], ]; $fields['right'] = [ 'page_link_to' => [ 'callback' => [ &$this, 'render_gallery_link_to_page_field' ], 'label' => __( 'Link to page:', 'nggallery' ), 'tooltip' => __( 'Albums will link this gallery to the selected page', 'nggallery' ), 'id' => 'gallery_page_link_to', ], 'preview_image' => [ 'callback' => [ &$this, 'render_gallery_preview_image_field' ], 'label' => __( 'Preview image:', 'nggallery' ), 'tooltip' => null, 'id' => 'gallery_preview_image', ], 'create_page' => [ 'callback' => [ &$this, 'render_gallery_create_page_field' ], 'label' => __( 'Create new page:', 'nggallery' ), 'tooltip' => null, 'id' => 'gallery_create_new_page', ], ]; return $fields; } public function render_gallery_field_label_column( $text, $for, $tooltip = null ) { $for = esc_attr( $for ); if ( ! empty( $tooltip ) ) { $tooltip = "title='{$tooltip}' class='tooltip'"; } echo ""; } public function render_gallery_fields() { // Get the gallery entity. $gallery = GalleryMapper::get_instance()->find( $this->gid ); // Get fields. $fields = apply_filters( 'ngg_manage_gallery_fields', [], $gallery ); $left = isset( $fields['left'] ) ? $fields['left'] : []; $right = isset( $fields['right'] ) ? $fields['right'] : []; // Output table. echo ''; $number_of_fields = max( count( $left ), count( $right ) ); $left_keys = array_keys( $left ); $right_keys = array_keys( $right ); for ( $i = 0; $i < $number_of_fields; $i++ ) { // Start row. echo ''; // Left column. if ( isset( $left_keys[ $i ] ) ) { extract( $left[ $left_keys[ $i ] ] ); // Label. $this->render_gallery_field_label_column( $label, $id, $tooltip ); // Input field. if ( is_callable( $callback ) ) { echo ''; } elseif ( WP_DEBUG ) { echo "

    Could not render {$left_keys[$i]} field. No callback exists

    "; } } else { $output[] = ''; } // Right column. if ( isset( $right_keys[ $i ] ) ) { extract( $right[ $right_keys[ $i ] ] ); // Label. $this->render_gallery_field_label_column( $label, $id, $tooltip ); // Input field.. if ( is_callable( $callback ) ) { echo ''; } elseif ( WP_DEBUG ) { echo "

    Could not render {$right_keys[$i]} field. No callback exists

    "; } } else { $output[] = ''; } // End. echo ''; } echo ''; } public function render_gallery_title_field( $gallery ) { include 'templates/manage_gallery/gallery_title_field.php'; } public function render_gallery_desc_field( $gallery ) { include 'templates/manage_gallery/gallery_desc_field.php'; } public function render_gallery_path_field( $gallery ) { include 'templates/manage_gallery/gallery_path_field.php'; } public function render_gallery_author_field( $gallery ) { $user = get_userdata( $gallery->author ); $author = isset( $user->display_name ) ? $user->display_name : $user->user_nicename; include 'templates/manage_gallery/gallery_author_field.php'; } public function render_gallery_link_to_page_field( $gallery ) { $pages = get_pages(); include 'templates/manage_gallery/gallery_link_to_page_field.php'; } public function render_gallery_preview_image_field( $gallery ) { $images = []; foreach ( ImageMapper::get_instance()->find_all( [ 'galleryid = %s', $gallery->{$gallery->id_field} ] ) as $image ) { $images[ $image->{$image->id_field} ] = "[{$image->{$image->id_field}}] {$image->filename}"; } include 'templates/manage_gallery/gallery_preview_image_field.php'; } public function render_gallery_create_page_field( $gallery ) { $pages = get_pages(); include 'templates/manage_gallery/gallery_create_page_field.php'; } public function post_processor_galleries() { global $ngg; check_admin_referer( 'ngg_bulkgallery' ); // bulk update in a single gallery. if ( isset( $_POST['bulkaction'] ) && isset( $_POST['doaction'] ) ) { switch ( $_POST['bulkaction'] ) { case 'no_action'; // No action. break; case 'recover_images': // Recover images from backup. // A prefix 'gallery_' will first fetch all ids from the selected galleries. nggAdmin::do_ajax_operation( 'gallery_recover_image', $_POST['doaction'], __( 'Recover from backup', 'nggallery' ) ); break; case 'set_watermark': // Set watermark // A prefix 'gallery_' will first fetch all ids from the selected galleries. nggAdmin::do_ajax_operation( 'gallery_set_watermark', $_POST['doaction'], __( 'Set watermark', 'nggallery' ) ); break; case 'import_meta': // Import Metadata // A prefix 'gallery_' will first fetch all ids from the selected galleries. nggAdmin::do_ajax_operation( 'gallery_import_metadata', $_POST['doaction'], __( 'Import metadata', 'nggallery' ) ); break; case 'delete_gallery': // Delete gallery. if ( is_array( $_POST['doaction'] ) ) { $deleted = false; $mapper = GalleryMapper::get_instance(); foreach ( $_POST['doaction'] as $id ) { $gallery = $mapper->find( $id ); if ( $gallery->path == '../' || false !== strpos( $gallery->path, '/../' ) ) { nggGallery::show_message( sprintf( __( 'One or more "../" in Gallery paths could be unsafe and NextGen Gallery will not delete gallery %s automatically', 'nggallery' ), $gallery->{$gallery->id_field} ) ); } elseif ( $mapper->destroy( $id, true ) ) { $deleted = true; } } if ( $deleted ) { nggGallery::show_message( esc_html__( 'Gallery deleted successfully ', 'nggallery' ) ); } } break; } } if ( isset( $_POST['addgallery'] ) && isset( $_POST['galleryname'] ) ) { check_admin_referer( 'ngg_bulkgallery' ); if ( ! nggGallery::current_user_can( 'NextGEN Add new gallery' ) ) { wp_die( esc_html_e( 'Cheatin’ uh?', 'nggallery' ) ); } // get the default path for a new gallery. $newgallery = $_POST['galleryname']; if ( ! empty( $newgallery ) ) { $gallery_mapper = GalleryMapper::get_instance(); $gallery = $gallery_mapper->create( [ 'title' => $newgallery ] ); if ( $gallery->save() && ! isset( $_REQUEST['attach_to_post'] ) ) { $url = admin_url() . 'admin.php?page=nggallery-manage-gallery&mode=edit&gid=' . $gallery->gid; $message = sprintf( __( 'Gallery successfully created. Manage gallery', 'nggallery' ), $url ); nggGallery::show_message( $message, 'gallery_created_msg' ); } } do_action( 'ngg_update_addgallery_page' ); } if ( isset( $_POST['TB_bulkaction'] ) && isset( $_POST['TB_ResizeImages'] ) ) { // save the new values for the next operation. $ngg->options['imgWidth'] = (int) $_POST['imgWidth']; $ngg->options['imgHeight'] = (int) $_POST['imgHeight']; // What is in the case the user has no if cap 'NextGEN Change options' ? Check feedback. update_option( 'ngg_options', $ngg->options ); $gallery_ids = explode( ',', $_POST['TB_imagelist'] ); // A prefix 'gallery_' will first fetch all ids from the selected galleries. nggAdmin::do_ajax_operation( 'gallery_resize_image', $gallery_ids, __( 'Resize images', 'nggallery' ) ); } if ( isset( $_POST['TB_bulkaction'] ) && isset( $_POST['TB_NewThumbnail'] ) ) { // save the new values for the next operation. $settings = Settings::get_instance(); $settings->set( 'thumbwidth', (int) $_POST['thumbwidth'] ); $settings->set( 'thumbheight', (int) $_POST['thumbheight'] ); $settings->set( 'thumbfix', isset( $_POST['thumbfix'] ) ); $settings->save(); ngg_refreshSavedSettings(); // What is in the case the user has no if cap 'NextGEN Change options' ? Check feedback. $gallery_ids = explode( ',', $_POST['TB_imagelist'] ); // A prefix 'gallery_' will first fetch all ids from the selected galleries. nggAdmin::do_ajax_operation( 'gallery_create_thumbnail', $gallery_ids, __( 'Create new thumbnails', 'nggallery' ) ); } } public function post_processor_images() { global $wpdb, $ngg, $nggdb; check_admin_referer( 'ngg_updategallery' ); // bulk update in a single gallery. if ( isset( $_POST['bulkaction'] ) && isset( $_POST['doaction'] ) ) { check_admin_referer( 'ngg_updategallery' ); switch ( $_POST['bulkaction'] ) { case 'no_action'; break; case 'rotate_cw': nggAdmin::do_ajax_operation( 'rotate_cw', $_POST['doaction'], __( 'Rotate images', 'nggallery' ) ); break; case 'rotate_ccw': nggAdmin::do_ajax_operation( 'rotate_ccw', $_POST['doaction'], __( 'Rotate images', 'nggallery' ) ); break; case 'recover_images': nggAdmin::do_ajax_operation( 'recover_image', $_POST['doaction'], __( 'Recover from backup', 'nggallery' ) ); break; case 'set_watermark': nggAdmin::do_ajax_operation( 'set_watermark', $_POST['doaction'], __( 'Set watermark', 'nggallery' ) ); break; case 'strip_orientation_tag': nggAdmin::do_ajax_operation( 'strip_orientation_tag', $_POST['doaction'], __( 'Remove EXIF Orientation', 'nggallery' ) ); break; case 'delete_images': if ( is_array( $_POST['doaction'] ) ) { foreach ( $_POST['doaction'] as $imageID ) { $image = $nggdb->find_image( $imageID ); if ( $image ) { do_action( 'ngg_delete_picture', $image->pid, $image ); if ( $ngg->options['deleteImg'] ) { $storage = StorageManager::get_instance(); $storage->delete_image( $image->pid ); } $delete_pic = ImageMapper::get_instance()->destroy( $image->pid ); } } if ( $delete_pic ) { nggGallery::show_message( __( 'Pictures deleted successfully ', 'nggallery' ) ); } } break; case 'import_meta': nggAdmin::do_ajax_operation( 'import_metadata', $_POST['doaction'], __( 'Import metadata', 'nggallery' ) ); break; } } if ( isset( $_POST['TB_bulkaction'] ) && isset( $_POST['TB_ResizeImages'] ) ) { // save the new values for the next operation. $ngg->options['imgWidth'] = (int) $_POST['imgWidth']; $ngg->options['imgHeight'] = (int) $_POST['imgHeight']; update_option( 'ngg_options', $ngg->options ); $pic_ids = explode( ',', $_POST['TB_imagelist'] ); nggAdmin::do_ajax_operation( 'resize_image', $pic_ids, __( 'Resize images', 'nggallery' ) ); } if ( isset( $_POST['TB_bulkaction'] ) && isset( $_POST['TB_NewThumbnail'] ) ) { // save the new values for the next operation. $settings = Settings::get_instance(); $settings->set( 'thumbwidth', (int) $_POST['thumbwidth'] ); $settings->set( 'thumbheight', (int) $_POST['thumbheight'] ); $settings->set( 'thumbfix', isset( $_POST['thumbfix'] ) ); $settings->save(); ngg_refreshSavedSettings(); $pic_ids = explode( ',', $_POST['TB_imagelist'] ); nggAdmin::do_ajax_operation( 'create_thumbnail', $pic_ids, __( 'Create new thumbnails', 'nggallery' ) ); } if ( isset( $_POST['TB_bulkaction'] ) && isset( $_POST['TB_SelectGallery'] ) ) { $pic_ids = explode( ',', $_POST['TB_imagelist'] ); $dest_gid = (int) $_POST['dest_gid']; switch ( $_POST['TB_bulkaction'] ) { case 'copy_to': $destination = GalleryMapper::get_instance()->find( $dest_gid ); $new_ids = StorageManager::get_instance()->copy_images( $pic_ids, $dest_gid ); if ( ! empty( $new_ids ) ) { $admin_url = admin_url(); $title = esc_html( $destination->title ); $link = "{$title}"; nggGallery::show_message( sprintf( __( 'Copied %1$s picture(s) to gallery: %2$s .', 'nggallery' ), count( $new_ids ), $link ) ); } else { nggGallery::show_error( __( 'Failed to copy images', 'nggallery' ) ); } break; case 'move_to': $destination = GalleryMapper::get_instance()->find( $dest_gid ); $new_ids = StorageManager::get_instance()->move_images( $pic_ids, $dest_gid ); if ( ! empty( $new_ids ) ) { $admin_url = admin_url(); $title = esc_html( $destination->title ); $link = "{$title}"; nggGallery::show_message( sprintf( __( 'Moved %1$s picture(s) to gallery: %2$s .', 'nggallery' ), count( $new_ids ), $link ) ); } else { nggGallery::show_error( __( 'Failed to move images', 'nggallery' ) ); } break; } } if ( isset( $_POST['TB_bulkaction'] ) && isset( $_POST['TB_EditTags'] ) ) { // do tags update. // get the images list. $pic_ids = explode( ',', $_POST['TB_imagelist'] ); $taglist = explode( ',', $_POST['taglist'] ); $taglist = array_map( 'trim', $taglist ); if ( is_array( $pic_ids ) ) { foreach ( $pic_ids as $pic_id ) { // which action should be performed ? switch ( $_POST['TB_bulkaction'] ) { case 'no_action'; // No action. break; case 'overwrite_tags': // Overwrite tags. wp_set_object_terms( $pic_id, $taglist, 'ngg_tag' ); break; case 'add_tags': // Add / append tags. wp_set_object_terms( $pic_id, $taglist, 'ngg_tag', true ); break; case 'delete_tags': // Delete tags. $oldtags = wp_get_object_terms( $pic_id, 'ngg_tag', 'fields=names' ); // get the slugs, to vaoid case sensitive problems. $slugarray = array_map( 'sanitize_title', $taglist ); $oldtags = array_map( 'sanitize_title', $oldtags ); // compare them and return the diff. $newtags = array_diff( $oldtags, $slugarray ); wp_set_object_terms( $pic_id, $newtags, 'ngg_tag' ); break; } } nggGallery::show_message( __( 'Tags changed', 'nggallery' ) ); } } if ( isset( $_POST['updatepictures'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), 'ngg_updategallery' ) ) { // Update pictures. $success = false; if ( nggGallery::current_user_can( 'NextGEN Edit gallery options' ) && ! isset( $_GET['s'] ) ) { $tags = [ '', '', '', '
    ', '', '', '', '', '
    ', '
    ', '
    ', '', '
    ', '', '', '', '', '
    ', '', '', '', '
    ', '
    ', '
    ', '', '
    ', '', '

    ', '

    ', '

    ', '

    ', '

    ', '
    ', '
    ', '', '', '', '