%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /opt/alt/php-xray/php/profiler/classes/
Upload File :
Create Path :
Current File : //opt/alt/php-xray/php/profiler/classes/xray-profiler-collector-shortcodes.php

<?php

/**
 * Copyright (с) Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2022 All Rights Reserved
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * https://www.cloudlinux.com/legal/
 */

namespace XrayProfiler;

use Closure;
use Exception;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use ReflectionObject;

if (!class_exists('\XrayProfiler\CollectorShortcode')) {
    class CollectorShortcode extends Collector
    {
        /**
         * @var int
         */
        private $next_id = 0;

        /**
         * @var array<string,array<int>>
         */
        public $tag_id = array();

        /**
         * @var array<string,array<string>>
         */
        private $parsed_handlers = array();

        /**
         * @var self|null
         */
        private static $instance = null;

        private function __construct()
        {
        }

        private function __clone()
        {
        }

        /**
         * @return self
         */
        public static function instance()
        {
            if (is_null(self::$instance)) {
                self::$instance = new self();
                self::$instance->clean();
            }

            return self::$instance;
        }

        /**
         * @return int
         */
        public function getNextId()
        {
            return $this->next_id;
        }

        /**
         * @return int
         */
        public function incrNextId()
        {
            return $this->next_id++;
        }

        /**
         * @param string $tag
         * @param int $id
         * @return void
         */
        public function setTagId($tag, $id)
        {
            $this->tag_id[$tag][] = $id;
        }

        /**
         * @param string $tag
         * @param bool $replace
         * @return int
         */
        public function popTagId($tag, $replace = true)
        {
            $id = 0;

            if (array_key_exists($tag, $this->tag_id)) {
                $ids = $this->tag_id[$tag];

                if (!is_null($last = array_pop($ids))) {
                    $id = $last;
                }

                if ($replace === true) {
                    $this->tag_id[$tag] = $ids;
                }
            }

            return $id;
        }

        /**
         * @param string $tag
         *
         * @return array<string,string>|null
         */
        public function getParsedHandlers($tag)
        {
            if (array_key_exists($tag, $this->parsed_handlers)) {
                return $this->parsed_handlers[$tag];
            }

            return null;
        }

        /**
         * @param string $tag
         * @param array<string,string> $data
         *
         * @return void
         */
        public function setParsedHandlers($tag, $data)
        {
            $this->parsed_handlers[$tag] = $data;
        }

        /**
         * @param string $tag
         * @param int $id
         *
         * @return array<string,float|int|string|null>|null
         * [
         *     'shortcode_id' => (int)
         *     'handler' => (string)
         *     'name' => (string)
         *     'plugin' => (string)
         *     'duration' => (int)
         *     'attrs_json' => (string)
         *     'timer_start' => (float)
         *]
         */
        public function getShortcode($tag, $id)
        {
            $data = $this->getData();
            if (array_key_exists($tag, $data) && array_key_exists($id, $data[$tag])) {
                return $data[$tag][$id];
            }

            return null;
        }

        /**
         * @param string $tag
         * @param int $id
         * @param array<string,float|int|string|null> $data
         *
         * @return void
         */
        public function setShortcode($tag, $id, $data)
        {
            $shortcodes = $this->getData();
            if (!array_key_exists($tag, $shortcodes)) {
                $shortcodes[$tag] = array();
            }

            $shortcodes[$tag][$id] = $data;

            $this->setData($shortcodes);
        }

        /**
         * @param array|string $attr
         *
         * @return array<int, array<string|mixed>>
         */
        public function prepareAttributes($attr)
        {
            $attrs = array();
            if (is_array($attr) && !empty($attr)) {
                foreach ($attr as $key => $val) {
                    $attrs[] = array(
                        'type' => 'key',
                        'key' => $key,
                        'val' => $val,
                    );
                }
            } elseif (is_string($attr) && !empty($attr)) {
                $attrs[] = array(
                    'type' => 'string',
                    'key' => '',
                    'val' => $attr,
                );
            }

            return $attrs;
        }

        /**
         * @param string $tag
         * @param object|callable $fn
         *
         * @return array<string,string>
         */
        public function parseHandler($tag, $fn)
        {
            if ($cache = $this->getParsedHandlers($tag)) {
                return $cache;
            }

            $handler = '';
            $plugin = '';

            if (
                class_exists('ReflectionClass') &&
                class_exists('ReflectionObject') &&
                class_exists('ReflectionFunction')
            ) {
                try {
                    $parse = array(
                        'path' => '',
                        'handler' => '',
                    );

                    if (is_array($fn)) {
                        // Class::method
                        $parse = $this->parseHandlerArray($fn);
                    } elseif (is_object($fn)) {
                        // Object/Closure/Invoke
                        $parse = $this->parseHandlerObject($fn);
                    } elseif (is_string($fn)) {
                        // Function string
                        $parse = $this->parseHandlerString($fn);
                    }

                    $path = $parse['path'];
                    $handler = $parse['handler'];

                    if (!empty($path)) {
                        $plugin = $this->pluginOrThemeName($path);
                    }

                    if (empty($handler)) {
                        xray_profiler_log(
                            E_USER_NOTICE,
                            "Can't parse handler: " . print_r($fn, true),
                            __FILE__,
                            __LINE__
                        );
                    }
                } catch (Exception $e) {
                    $message = "Catch Reflection error Exception: "
                               . $e->getMessage()
                               . ', with handler: '
                               . print_r($fn, true);
                    xray_profiler_log(E_USER_WARNING, $message, $e->getFile(), $e->getLine());
                }
            } else {
                xray_profiler_log(E_USER_NOTICE, "Can't parse handler, Reflection doesn't exists", __FILE__, __LINE__);
            }

            $result = array(
                'handler' => $handler,
                'plugin' => $plugin,
            );

            $this->setParsedHandlers($tag, $result);

            return $result;
        }

        /**
         * @param  array<mixed>  $fn
         *
         * @return array<string,string>
         * @throws ReflectionException
         */
        public function parseHandlerArray($fn)
        {
            $path = '';
            $handler = '';
            $fn = array_values($fn);

            if (!empty($fn)) {
                if (is_object($fn[0])) {
                    $parse = $this->parseHandlerObject($fn[0]);
                } elseif (is_string($fn[0])) {
                    $parse = $this->parseHandlerString($fn[0]);
                }

                if (!empty($parse['handler'])) {
                    $path = $parse['path'];
                    $handler = $parse['handler'];

                    if (array_key_exists(1, $fn) && is_string($fn[1])) {
                        $handler .= '::' . $fn[1];
                    }
                }
            }

            return array(
                'path' => $path,
                'handler' => $handler,
            );
        }

        /**
         * @param object $fn
         *
         * @return array<string,string>
         * @throws ReflectionException
         */
        public function parseHandlerObject($fn)
        {
            $ref = new ReflectionObject($fn);
            $name = $ref->getName();
            $path = '';
            $handler = '';

            if (!empty($name)) {
                $handler = $name;
                $file = $ref->getFileName();
                if (!empty($file)) {
                    $path = $file;
                }

                if ($name == 'Closure' && $fn instanceof Closure) {
                    $ref = new ReflectionFunction($fn);
                    $name = $ref->getName();
                    if (!empty($name)) {
                        $file = $ref->getFileName();
                        if (!empty($file)) {
                            $path = $file;
                        }
                    }
                }
            }

            return array(
                'path' => $path,
                'handler' => $handler,
            );
        }

        /**
         * @param string $fn
         *
         * @return array<string,string>
         */
        public function parseHandlerString($fn)
        {
            $path = '';
            $handler = '';
            $class = $fn;
            $ref = null;

            if (strpos($fn, '::') !== false) {
                $parts = explode('::', $fn);
                $class = array_shift($parts);
            }

            if (class_exists($class)) {
                $ref = new ReflectionClass($class);
            } elseif (function_exists($class)) {
                $ref = new ReflectionFunction($class);
            }

            if ($ref) {
                $handler = $fn;
                $name = $ref->getName();
                if (! empty($name)) {
                    $file = $ref->getFileName();
                    if (! empty($file)) {
                        $path = $file;
                    }
                }
            }

            return array(
                'path' => $path,
                'handler' => $handler,
            );
        }

        /**
         * @param string $path
         *
         * @return string
         */
        public function pluginOrThemeName($path)
        {
            $name = '';
            $pattern = '/wp-content\/(mu-plugins\/|plugins\/|themes\/)(.*?)(\/|.php)/is';
            preg_match($pattern, $path, $matches);
            if (!empty($matches) && array_key_exists(2, $matches)) {
                if (strpos($matches[1], 'themes') === 0) {
                    $name = 'Theme: ';
                }

                $name .= $matches[2];
            }

            return $name;
        }

        /**
         * @param false|string $return
         * @param string $tag
         * @param array|string $attr
         * @param array $m
         *
         * @return false|string
         */
        public function preDoShortcodeTagEarly($return, $tag, $attr, $m)
        {
            $this->incrNextId();

            $id = $this->getNextId();
            $this->setTagId($tag, $id);

            $attrs = $this->prepareAttributes($attr);
            $parseHandler = $this->parseHandler($tag, $GLOBALS['shortcode_tags'][$tag]);
            $handler = $parseHandler['handler'];
            $plugin = $parseHandler['plugin'];

            if (empty($attrs) || !($attrs_json = json_encode($attrs))) {
                $attrs_json = 'null';
            }

            $data = [
                'shortcode_id' => $id,
                'handler' => empty($handler) ? 'Unknown' : $handler,
                'name' => $tag,
                'plugin' => empty($plugin) ? 'Unknown' : $plugin,
                'duration' => 0,
                'attrs_json' => $attrs_json,
                'timer_start' => microtime(true),
            ];

            $this->setShortcode($tag, $id, $data);

            return $return;
        }

        /**
         * @param false|string $return
         * @param string $tag
         * @param array|string $attr
         * @param array $m
         *
         * @return false|string
         */
        public function preDoShortcodeTagLate($return, $tag, $attr, $m)
        {
            if ($return !== false) {
                $this->popTagId($tag);
            }

            return $return;
        }

        /**
         * @param false|string $output
         * @param string $tag
         * @param array|string $attr
         * @param array $m
         *
         * @return false|string
         */
        public function doShortcodeTagLate($output, $tag, $attr, $m)
        {
            $timer_end = microtime(true);

            $id = $this->popTagId($tag);
            $shortcode = $this->getShortcode($tag, $id);

            if (empty($shortcode)) {
                xray_profiler_log(
                    E_USER_NOTICE,
                    'Can\'t find shortcode ' . $tag . ' id: ' . $id . ' in ' . __METHOD__,
                    __FILE__,
                    __LINE__
                );
            } else {
                $timer_start = floatval($shortcode['timer_start']);
                $diff = $timer_end - $timer_start;
                $duration = number_format($diff * 1000000, 0, '', '');
                $shortcode['duration'] = $duration;

                unset($shortcode['timer_start']);

                $tag = $shortcode['name'] . '';

                $this->setShortcode($tag, $id, $shortcode);
            }

            return $output;
        }

        /**
         * @return array
         */
        public function getXrayData()
        {
            $shortcodes = $this->data;
            $items = array();
            foreach ($shortcodes as $iterations) {
                $items = array_merge($items, $iterations);
            }

            usort($items, function ($a, $b) {
                if ($a['duration'] == $b['duration']) {
                    return 0;
                }

                return ($a['duration'] < $b['duration']) ? 1 : -1;
            });

            foreach ($items as &$item) {
                if (array_key_exists('timer_start', $item)) {
                    unset($item['timer_start']);
                }
            }

            return array_slice($items, 0, 20);
        }

        /**
         * @return $this
         */
        public function clean()
        {
            $this->data = array();
            $this->next_id = 0;
            $this->tag_id = array();
            $this->parsed_handlers = array();

            return $this;
        }
    }
}

Zerion Mini Shell 1.0