Файловый менеджер - Редактировать - /home/harasnat/www/horse/wp-content/plugins/admin-menu-editor/includes/ame-utils.php
Назад
<?php /** * Miscellaneous utility functions. */ class ameUtils { /** * HTML tags allowed in WP_Error messages and titles. * * This is based on the default list of allowed tags in /wp-includes/kses.php. */ const ALLOWED_WP_ERROR_TAGS = array( 'abbr' => array( 'title' => true, ), 'acronym' => array( 'title' => true, ), 'b' => array(), 'blockquote' => array( 'cite' => true, ), 'cite' => array(), 'code' => array(), 'del' => array( 'datetime' => true, ), 'em' => array(), 'i' => array(), 'q' => array( 'cite' => true, ), 's' => array(), 'strong' => array(), ); /** * Get a value from a nested array or object based on a path. * * @param array|object $array Get an entry from this array. * @param array|string $path A list of array keys in hierarchy order, or a string path like "foo.bar.baz". * @param mixed $default The value to return if the specified path is not found. Defaults to NULL. * @param string $separator Path element separator. Only applies to string paths. * @return mixed */ public static function get($array, $path, $default = null, $separator = '.') { if ( is_string($path) ) { $path = explode($separator, $path); } if ( empty($path) ) { return $default; } //Follow the $path into $input as far as possible. $currentValue = $array; $pathExists = true; foreach ($path as $node) { if ( ($currentValue instanceof ArrayAccess) && $currentValue->offsetExists($node) ) { $currentValue = $currentValue[$node]; } else if ( is_array($currentValue) && array_key_exists($node, $currentValue) ) { $currentValue = $currentValue[$node]; } else if ( is_object($currentValue) && property_exists($currentValue, $node) ) { $currentValue = $currentValue->$node; } else { $pathExists = false; break; } } if ( $pathExists ) { return $currentValue; } return $default; } /** * Get the first non-root directory from a path. * * Examples: * "foo/bar" => "foo" * "/foo/bar/baz.txt" => "foo" * "bar" => null * "baz/" => "baz" * "/" => null * * @param string $fileName * @return string|null */ public static function getFirstDirectory($fileName) { $fileName = ltrim($fileName, '/'); $segments = explode('/', $fileName, 2); if ( (count($segments) > 1) && ($segments[0] !== '') ) { return $segments[0]; } return null; } /** * Capitalize the first character of every word. Supports UTF-8. * * @param string $input * @return string */ public static function ucWords($input) { static $hasUnicodeSupport = null, $charset = 'UTF-8'; if ( $hasUnicodeSupport === null ) { //We need the mbstring extension and PCRE UTF-8 support. $hasUnicodeSupport = function_exists('mb_list_encodings') && (@preg_match('/\pL/u', 'a') === 1) && function_exists('get_bloginfo'); if ( $hasUnicodeSupport ) { //Technically, the encoding can change if something switches WP to a different site //in the middle of a request, but we'll ignore that possibility. $charset = get_bloginfo('charset'); $hasUnicodeSupport = in_array($charset, mb_list_encodings()) && ($charset === 'UTF-8'); } } if ( $hasUnicodeSupport ) { $totalLength = mb_strlen($input); $words = preg_split('/([\s\-_]++)/u', $input, -1, PREG_SPLIT_DELIM_CAPTURE); $output = array(); foreach ($words as $word) { $firstCharacter = mb_substr($word, 0, 1, $charset); //In old PHP versions, you must specify a non-null length to get the rest of the string. $remainder = mb_substr($word, 1, $totalLength, $charset); $output[] = mb_strtoupper($firstCharacter, $charset) . $remainder; } return implode('', $output); } return ucwords($input); } /** * Check if two arrays have the same keys and values. Arrays with string keys * or mixed keys can be in different order and still be considered "equal". * * @param array $a * @param array $b * @return bool */ public static function areAssocArraysEqual($a, $b) { $secondArraySize = count($b); if ( count($a) !== $secondArraySize ) { return false; } $sameItems = array_intersect_assoc($a, $b); return count($sameItems) === $secondArraySize; } /** * Escape a WP_Error object for passing it to wp_die(). * * Converts special characters in error messages to HTML entities. * Returns a new WP_Error instance. Does not modify the input object. * * @param WP_Error $error * @return WP_Error New WP_Error instance. */ public static function escapeWpError($error) { return self::copyErrorWithFilter($error, 'esc_html'); } /** * Strip disallowed HTML from a WP_Error object. * * @param WP_Error $error * @return WP_Error New WP_Error instance. */ public static function ksesWpError($error) { return self::copyErrorWithFilter($error, array(__CLASS__, 'ksesCallbackForErrors')); } protected static function ksesCallbackForErrors($message) { return wp_kses($message, self::ALLOWED_WP_ERROR_TAGS); } /** * Copy a WP_Error object and apply a filter callback to each message. * * Also, if an error has a data item that's an array with a 'title' key, * this escapes HTML in the title. * * @param WP_Error $error * @param callable $callback * @return WP_Error */ protected static function copyErrorWithFilter($error, $callback) { $result = new WP_Error(); $canGetAllData = method_exists($error, 'get_all_error_data'); //WP 5.6+ foreach ($error->get_error_codes() as $code) { foreach ($error->get_error_messages($code) as $message) { $result->add($code, call_user_func($callback, $message)); } if ( $canGetAllData ) { $dataItems = $error->get_all_error_data($code); } else { $data = $error->get_error_data($code); if ( $data !== null ) { $dataItems = array($data); } else { $dataItems = array(); } } foreach ($dataItems as $data) { //Page titles should never contain unescaped HTML tags. //As of this writing, this plugin doesn't put titles in error data, //but other code might, and wp_die() supports it. if ( isset($data['title']) ) { $data['title'] = esc_html($data['title']); } $result->add_data($data, $code); } } return $result; } /** * Get the first element of an iterable collection. * * @param iterable $collection Array, Traversable, Generator, etc. * @param mixed $defaultValue Value to return if the collection is empty. * @return mixed */ public static function getFirstItem($collection, $defaultValue = null) { foreach ($collection as $value) { return $value; } return $defaultValue; } /** * Get the first key of an iterable collection. * * @param iterable $collection * @param iterable $defaultValue * @return int|string|null */ public static function getFirstKey($collection, $defaultValue = null) { foreach ($collection as $key => $value) { return $key; } return $defaultValue; } /** * Get specific keys from each item of a collection. * * Notes: * - Collection indexes are preserved. * - Items that don't have any of the specified keys are ignored. * * @param iterable $collection An iterable collection of arrays or objects. * @param array $keys * @return array[] Array of arrays. */ public static function collectionPick($collection, array $keys) { $result = array(); foreach ($collection as $index => $item) { $values = array(); foreach ($keys as $key) { if ( is_array($item) && array_key_exists($key, $item) ) { $values[$key] = $item[$key]; } else if ( is_object($item) && property_exists($item, $key) ) { $values[$key] = $item->$key; } } if ( !empty($values) ) { $result[$index] = $values; } } return $result; } /** * Send HTTP caching headers. * * @param int|null $lastModified Unix timestamp for the last modification time. * @param int $cacheLifetime Cache lifetime in seconds. * @return bool True if the response body should be omitted because an If-Modified-Since header * was sent and the resource hasn't changed. */ public static function sendCachingHeaders($lastModified, $cacheLifetime = 30 * 24 * 3600) { //Support the If-Modified-Since header. $omitResponseBody = false; if ( !empty($lastModified) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && is_string($_SERVER['HTTP_IF_MODIFIED_SINCE']) ) { //strtotime() should be able to handle invalid strings safely. //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $threshold = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); if ( $threshold >= $lastModified ) { header('HTTP/1.1 304 Not Modified'); $omitResponseBody = true; } } //Enable browser caching. //Note that admin-ajax.php always adds HTTP headers that prevent caching, so we will //override all of them even though we don't actually need some of them, like "Expires". $expirationBaseTime = time(); if ( !empty($lastModified) ) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s ', $lastModified) . 'GMT'); if ( $lastModified > $expirationBaseTime ) { $expirationBaseTime = $lastModified; } } header('Expires: ' . gmdate('D, d M Y H:i:s ', $expirationBaseTime + $cacheLifetime) . 'GMT'); header('Cache-Control: public, max-age=' . $cacheLifetime); return $omitResponseBody; } /** * Pass through the selected actor from the request to the new query parameters. * * @param array $outputQueryParams Array of query params, usually for a redirect URL. * @param array|null $inputRequestParams Array of form fields from the current request. Defaults to $_POST. * @param array|null $queryParameterName Name of the input field/parameter to use. * @return array Modified $outputQueryParams. */ public static function withSelectedActor( $outputQueryParams, $inputRequestParams = null, $queryParameterName = 'selected_actor' ) { if ( $inputRequestParams === null ) { //This is a utility method; the caller is responsible for nonce verification. //phpcs:ignore WordPress.Security.NonceVerification.Missing $inputRequestParams = $_POST; } if ( !isset($inputRequestParams[$queryParameterName]) ) { return $outputQueryParams; } $selectedActor = $inputRequestParams[$queryParameterName]; //Basic actor ID validation. $isValid = is_string($selectedActor) && (strlen($selectedActor) <= 200) && ( ($selectedActor === 'special:super_admin') || preg_match('/^(role|user):[a-z0-9_]+$/i', $selectedActor) ); if ( $isValid ) { $outputQueryParams[$queryParameterName] = $selectedActor; } return $outputQueryParams; } /** * Check if a string starts with a specific substring. * * @param string $haystack * @param string $needle * @return bool */ public static function stringStartsWith($haystack, $needle) { return (substr($haystack, 0, strlen($needle)) === $needle); } /** * Get the component - e.g. a specific plugin or theme - from a file path. * * @param string $absolutePath Full path to a file or directory. * @return array{type: string, path: string}|null */ public static function getComponentFromPath($absolutePath) { static $pluginDirectory = null, $muPluginDirectory = null, $themeDirectory = null; if ( $pluginDirectory === null ) { $pluginDirectory = wp_normalize_path(WP_PLUGIN_DIR); $muPluginDirectory = wp_normalize_path(WPMU_PLUGIN_DIR); $themeDirectory = wp_normalize_path(WP_CONTENT_DIR . '/themes'); } $absolutePath = wp_normalize_path($absolutePath); if ( empty($absolutePath) ) { return null; } $pos = null; $type = ''; if ( strpos($absolutePath, $pluginDirectory) === 0 ) { $type = 'plugin'; $pos = strlen($pluginDirectory); } else if ( !empty($muPluginDirectory) && (strpos($absolutePath, $muPluginDirectory) === 0) ) { $type = 'mu-plugin'; $pos = strlen($muPluginDirectory); } else if ( strpos($absolutePath, $themeDirectory) === 0 ) { $type = 'theme'; $pos = strlen($themeDirectory); } if ( $pos !== null ) { $nextSlash = strpos($absolutePath, '/', $pos + 1); if ( $nextSlash !== false ) { $componentDirectory = substr($absolutePath, $pos + 1, $nextSlash - $pos - 1); } else { $componentDirectory = substr($absolutePath, $pos + 1); } return ['type' => $type, 'path' => $componentDirectory]; } return null; } /** * Convert a color in the #RRGGBB or #RGB format to the rgba() format. * * @param string $color * @param float $opacity * @return string */ public static function convertHexColorToRgba($color, $opacity = 1.0) { $color = trim($color); if ( $color === '' ) { return 'rgba(0, 0, 0, ' . $opacity . ')'; } //Strip the leading hash, if any. if ( $color[0] === '#' ) { $color = substr($color, 1); } //Convert 3-digit hex to 6-digit hex. if ( strlen($color) === 3 ) { $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; } //Convert hex to RGB. $red = hexdec(substr($color, 0, 2)); $green = hexdec(substr($color, 2, 2)); $blue = hexdec(substr($color, 4, 2)); return 'rgba(' . $red . ', ' . $green . ', ' . $blue . ', ' . $opacity . ')'; } } /** * This function exists because the "EscapeOutput" sniff in the WordPress coding standards * doesn't understand class methods. * * @param WP_Error $error * @return WP_Error * @see ameUtils::escapeWpError */ function wsAmeEscapeWpError($error) { return ameUtils::escapeWpError($error); } class ameFileLock { protected $fileName; protected $handle = null; public function __construct($fileName) { $this->fileName = $fileName; } //fopen() and flock() should be fine here because we only need read permissions. //phpcs:disable WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_flock,WordPress.WP.AlternativeFunctions.file_system_operations_fopen public function acquire($timeout = null) { if ( $this->handle !== null ) { throw new RuntimeException('Cannot acquire a lock that is already held.'); } if ( !function_exists('flock') ) { return false; } $this->handle = @fopen(__FILE__, 'r'); if ( !$this->handle ) { $this->handle = null; return false; } $success = @flock($this->handle, LOCK_EX | LOCK_NB, $wouldBlock); if ( !$success && $wouldBlock && ($timeout !== null) ) { $timeout = max(min($timeout, 0.1), 600); $endTime = microtime(true) + $timeout; //Wait for a short, random time and try again. do { $canWaitMore = $this->waitRandom($endTime); $success = @flock($this->handle, LOCK_EX | LOCK_NB, $wouldBlock); } while (!$success && $wouldBlock && $canWaitMore); } if ( !$success ) { fclose($this->handle); $this->handle = null; return false; } return true; } public function release() { if ( $this->handle !== null ) { @flock($this->handle, LOCK_UN); fclose($this->handle); $this->handle = null; } } //phpcs:enable /** * Wait for a random interval without going over $endTime. * * @param float|int $endTime Unix timestamp. * @return bool TRUE if there's still time until $endTime, FALSE otherwise. */ protected function waitRandom($endTime) { $now = microtime(true); if ( $now >= $endTime ) { return false; } $delayMs = wp_rand(80, 300); $remainingTimeMs = ($endTime - $now) * 1000; if ( $delayMs < $remainingTimeMs ) { usleep($delayMs * 1000); return true; } else { usleep($remainingTimeMs * 1000); return false; } } public static function create($fileName) { return new self($fileName); } public function __destruct() { $this->release(); } } class ameOrderedMap implements Iterator, Countable { /** * @var ameLinkedListNode[] */ private $nodesByKey = array(); /** * @var ameLinkedListNode|null */ private $head = null; /** * @var ameLinkedListNode|null */ private $tail = null; /** * @var ameLinkedListNode|null */ private $currentNode = null; /** * @param array $items * @return $this */ public function addAll($items) { foreach ($items as $key => $item) { $this->set($key, $item); } return $this; } /** * @param string $previousKey * @param array $items * @return $this */ public function insertAllAfter($previousKey, $items) { if ( !isset($this->nodesByKey[$previousKey]) ) { return $this->addAll($items); } $previousNode = $this->nodesByKey[$previousKey]; foreach ($items as $key => $value) { if ( isset($this->nodesByKey[$key]) ) { $node = $this->nodesByKey[$key]; } else { $node = new ameLinkedListNode($value, $key); $this->nodesByKey[$key] = $node; } $this->insertNodeAfter($previousNode, $node); $previousNode = $node; } return $this; } /** * @param string $previousKey * @param string $key * @param mixed $item * @return $this */ public function insertAfter($previousKey, $key, $item) { return $this->insertAllAfter($previousKey, array($key => $item)); } private function insertNodeAfter($previousNode, $newNode) { $newNode->previous = $previousNode; $newNode->next = $previousNode->next; if ( $newNode->next !== null ) { $newNode->next->previous = $newNode; } $previousNode->next = $newNode; if ( $this->tail === $previousNode ) { $this->tail = $newNode; } } /** * @param string $nextKey * @param string $key * @param $item * @return $this */ public function insertBefore($nextKey, $key, $item) { if ( !isset($this->nodesByKey[$nextKey]) ) { return $this->set($key, $item); } $nextNode = $this->nodesByKey[$nextKey]; $previousNode = $nextNode->previous; if ( isset($this->nodesByKey[$key]) ) { $node = $this->nodesByKey[$key]; } else { $node = new ameLinkedListNode($item, $key); $this->nodesByKey[$key] = $node; } $node->next = $nextNode; $node->previous = $previousNode; $nextNode->previous = $node; if ( $previousNode !== null ) { $previousNode->next = $node; } if ( $this->head === $nextNode ) { $this->head = $node; } return $this; } public function set($key, $item) { if ( isset($this->nodesByKey[$key]) ) { $this->nodesByKey[$key]->value = $item; } else { $this->append($key, $item); } return $this; } private function append($key, $item) { $node = new ameLinkedListNode($item, $key); $this->nodesByKey[$key] = $node; if ( $this->tail === null ) { $this->head = $node; $this->tail = $node; } else { $this->insertNodeAfter($this->tail, $node); $this->tail = $node; } return $this; } #[\ReturnTypeWillChange] public function current() { return $this->currentNode->value; } #[\ReturnTypeWillChange] public function next() { if ( $this->currentNode !== null ) { $this->currentNode = $this->currentNode->next; } } #[\ReturnTypeWillChange] public function key() { return $this->currentNode->key; } #[\ReturnTypeWillChange] public function valid() { return ($this->currentNode !== null); } #[\ReturnTypeWillChange] public function rewind() { $this->currentNode = $this->head; } #[\ReturnTypeWillChange] public function count() { return count($this->nodesByKey); } /** * Filter the map using a callback function. * Returns a new map that contains only the items for which the callback function returns a truthy value. * * @param callable $predicate * @return ameOrderedMap */ public function filter($predicate) { $result = new self(); foreach ($this as $key => $value) { if ( call_user_func($predicate, $value, $key) ) { $result->append($key, $value); } } return $result; } } class ameLinkedListNode { /** * @var string */ public $key; /** * @var mixed */ public $value; /** * @var self|null */ public $next = null; /** * @var self|null */ public $previous = null; public function __construct($value, $key = '') { $this->value = $value; $this->key = $key; } } class ameMultiDictionary { const PATH_SEPARATOR = '.'; const MAX_PATH_DEPTH = 64; /** * Get a value from an array or object using a path. * * Supports multidimensional/nested arrays and objects. * * @param array|object $collection * @param string|string[] $path * @param mixed $defaultValue * @param string $separator * @return mixed|null The value at the specified path, or the default value * if the path does not exist. */ public static function get($collection, $path, $defaultValue = null, $separator = self::PATH_SEPARATOR) { $path = self::parsePath($path, $separator); if ( empty($path) ) { return $collection; } //Follow the $path into the $collection as far as possible. $currentValue = $collection; $pathExists = true; foreach ($path as $key) { if ( ($currentValue instanceof ArrayAccess) && $currentValue->offsetExists($key) ) { //Caution: offsetExists() may return false if the key exists but is null. $currentValue = $currentValue[$key]; } else if ( is_array($currentValue) && array_key_exists($key, $currentValue) ) { $currentValue = $currentValue[$key]; } else if ( is_object($currentValue) && property_exists($currentValue, $key) ) { $currentValue = $currentValue->{$key}; } else { $pathExists = false; break; } } if ( $pathExists ) { return $currentValue; } return $defaultValue; } public static function set( &$collection, $path, $value, $createArrays = true, $overwriteScalars = false, $separator = self::PATH_SEPARATOR ) { $path = self::parsePath($path, $separator); if ( empty($path) ) { //An empty path doesn't make sense, we can't replace the collection itself. throw new InvalidArgumentException('Cannot set a value because the path is empty.'); } if ( !self::isCollection($collection) ) { //The collection is not an array or an object, so we can't set a value in it. throw new InvalidArgumentException('Collection must be an array or an object.'); } $lastKey = array_pop($path); if ( empty($path) ) { $target = &$collection; } else { $target = &self::acquireNestedCollection( $collection, $path, $createArrays, $overwriteScalars ); if ( $target === null ) { return false; } } if ( is_array($target) || ($target instanceof ArrayAccess) ) { $target[$lastKey] = $value; } else if ( is_object($target) ) { $target->{$lastKey} = $value; } return true; } public static function delete(&$collection, $path, $separator = self::PATH_SEPARATOR) { $path = self::parsePath($path, $separator); if ( empty($path) ) { throw new InvalidArgumentException('Cannot delete an item because the path is empty.'); } if ( !self::isCollection($collection) ) { throw new InvalidArgumentException('Collection must be an array or an object.'); } $lastKey = array_pop($path); $target = &self::acquireNestedCollection($collection, $path, false); if ( $target !== null ) { if ( is_array($target) || ($target instanceof ArrayAccess) ) { unset($target[$lastKey]); } else if ( is_object($target) ) { unset($target->{$lastKey}); } } } public static function parsePath($path, $separator = self::PATH_SEPARATOR) { if ( is_array($path) ) { return $path; } else if ( ($path === '') || ($path === $separator) ) { return array(); } return explode($separator, $path, self::MAX_PATH_DEPTH); } /** * @param array $prefix * @param string|array $path * @return array */ public static function addPrefixToPath($prefix, $path, $separator = self::PATH_SEPARATOR) { return array_merge($prefix, self::parsePath($path, $separator)); } protected static function isCollection($collection) { return is_array($collection) || is_object($collection); } protected static function &acquireNestedCollection( &$collection, $parsedPath, $createArrays = true, $overwriteScalars = false ) { $current = &$collection; $notFound = null; $previousNode = null; $previousKey = null; foreach ($parsedPath as $key) { //The array and object branches are functionally identical, //but they must be separated due to syntax differences. if ( is_array($current) || ($current instanceof ArrayAccess) ) { if ( !isset($current[$key]) ) { if ( $createArrays ) { $current[$key] = array(); } else { return $notFound; } } $current = &$current[$key]; } else if ( is_object($current) ) { if ( !isset($current->{$key}) ) { if ( $createArrays ) { $current->{$key} = array(); } else { return $notFound; } } $current = &$current->{$key}; } //Overwrite scalar values with associative arrays if necessary. if ( !is_array($current) && !is_object($current) ) { if ( $overwriteScalars && ($previousNode !== null) ) { if ( is_array($previousNode) || ($previousNode instanceof ArrayAccess) ) { $previousNode[$previousKey] = array(); } else if ( is_object($previousNode) ) { $previousNode->{$previousKey} = array(); } $current = &$previousNode[$previousKey]; } else { return $notFound; } } $previousNode = &$current; $previousKey = $key; } return $current; } } class ameCustomizationFeatureToggle { /** * @var string */ private $component; /** * @var WPMenuEditor */ private $menuEditor; /** * @var string */ private $tabSlug; /** * @var callable|null */ private $noticeTextCallback; public function __construct( $component, $menuEditor, $tabSlug = '', $noticeTextCallback = null ) { $this->component = $component; $this->menuEditor = $menuEditor; $this->tabSlug = $tabSlug; $this->noticeTextCallback = $noticeTextCallback; } /** * @return bool */ public function isCustomizationDisabled() { return $this->menuEditor->is_customization_disabled($this->component); } public function onSettingsSaved() { if ( !empty($this->tabSlug) && !empty($this->noticeTextCallback) ) { add_action( 'admin_menu_editor-tab_admin_notices-' . $this->tabSlug, [$this, 'maybeShowNotice'] ); } } public function maybeShowNotice() { if ( !empty($this->noticeTextCallback) && $this->isCustomizationDisabled() ) { $texts = call_user_func($this->noticeTextCallback); if ( empty($texts) ) { return; } list($mainText, $additionalText) = $texts; if ( empty($mainText) ) { return; } printf( '<div class="notice notice-info"><p><strong>%s</strong> %s</p></div>', esc_html($mainText), !empty($additionalText) ? esc_html(' ' . $additionalText) : '' ); } } } class ameKnockoutSaveForm { private $action; private $submitUrl; private $saveButtonText; public function __construct($action, $submitUrl, $saveButtonText = '') { $this->action = $action; $this->submitUrl = $submitUrl; $this->saveButtonText = $saveButtonText; } public function getSaveFormConfig() { $config = [ 'action' => $this->action, 'actionNonce' => wp_create_nonce($this->action), 'submitUrl' => $this->submitUrl, 'referer' => remove_query_arg('_wp_http_referer'), ]; if ( !empty($this->saveButtonText) ) { $config['saveButtonText'] = $this->saveButtonText; } return $config; } public function processSubmission(array $post) { check_admin_referer($this->action); if ( empty($post['settings']) ) { wp_die('The "settings" field is missing or empty.'); } if ( !is_string($post['settings']) ) { wp_die('Invalid settings data: expected a JSON string.'); } $newSettings = json_decode($post['settings'], true); if ( !is_array($newSettings) ) { wp_die('Invalid settings data: expected a valid JSON object.'); } return new ameParsedKnockoutFormSubmission($newSettings, $post); } } class ameParsedKnockoutFormSubmission { const SELECTED_ACTOR_FIELD = 'selectedActor'; private $settings; private $fields; public function __construct(array $settings, array $fields) { $this->settings = $settings; $this->fields = $fields; } public function getSettings() { return $this->settings; } public function getField($name, $defaultValue = null) { if ( isset($this->fields[$name]) ) { return $this->fields[$name]; } return $defaultValue; } /** * @return string */ public function getSelectedActorId() { $defaultValue = ''; $result = $this->getField('selectedActor', $defaultValue); if ( is_string($result) ) { return $result; } return $defaultValue; } /** * Add the selected actor submitted via the form to the provided query parameters. * * @param array $queryParams * @return array */ public function withSelectedActor(array $queryParams) { return ameUtils::withSelectedActor( $queryParams, $this->fields, self::SELECTED_ACTOR_FIELD ); } } class ameLockedGlobalOption { private $optionName; private $lockFileName; private $autoload; /** * @var float|null */ private $lockTimeout; /** * @param string $optionName * @param string $lockFileName * @param float|null $lockTimeout * @param bool|null $autoload */ public function __construct($optionName, $lockFileName, $lockTimeout = null, $autoload = null) { $this->optionName = $optionName; $this->lockFileName = $lockFileName; $this->autoload = $autoload; $this->lockTimeout = $lockTimeout; } public function get($defaultValue = null) { if ( is_multisite() ) { return get_site_option($this->optionName, $defaultValue); } else { return get_option($this->optionName, $defaultValue); } } public function set($value) { $lock = ameFileLock::create($this->lockFileName); if ( $lock->acquire($this->lockTimeout) ) { if ( is_multisite() ) { update_site_option($this->optionName, $value); } else { update_option($this->optionName, $value, $this->autoload); } $lock->release(); return true; } return false; } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка