drupflare/worker - v1.0.4
    Preparing search index...

    Variable BOUNDARY_STATE_PHPConst

    BOUNDARY_STATE_PHP: "\nuse Drupal\\Component\\Utility\\Html;\nuse Drupal\\Core\\Cache\\CacheCollector;\nuse Drupal\\Core\\Database\\Database;\nuse Drupal\\Core\\Entity\\EntityViewBuilder;\nuse Drupal\\Core\\Form\\FormState;\nuse Drupal\\Core\\Render\\Renderer;\n\n// __CFW_FIBER_SHIM__\n// __CFW_HOST_HELPERS__\nchdir('/drupal');\n\n$obFound = ob_get_level();\nwhile (ob_get_level() > 0) {\n\t@ob_end_clean();\n}\n\n$out = ['obLevel' => $obFound];\n$out['headers'] = function_exists('headers_list') ? count(headers_list()) : -1;\n$out['sessionStatus'] = function_exists('session_status') ? session_status() : -1;\n$out['sessionId'] = function_exists('session_id') ? (string) @session_id() : '';\n$out['sessionKeys'] =\n\tisset($GLOBALS['_SESSION']) && is_array($GLOBALS['_SESSION'])\n\t\t? array_keys($GLOBALS['_SESSION'])\n\t\t: [];\n$out['booted'] = isset($GLOBALS['__pw_kernel']) ? 1 : 0;\n$out['post'] =\n\tisset($GLOBALS['_POST']) && is_array($GLOBALS['_POST']) ? array_keys($GLOBALS['_POST']) : [];\n$out['cookies'] =\n\tisset($GLOBALS['_COOKIE']) && is_array($GLOBALS['_COOKIE'])\n\t\t? array_keys($GLOBALS['_COOKIE'])\n\t\t: [];\n\n$ask = function (callable $fn) {\n\ttry {\n\t\treturn $fn();\n\t} catch (Throwable $e) {\n\t\treturn 'ERR: ' . substr($e->getMessage(), 0, 120);\n\t}\n};\n\n// #region the named carriers\n$out['uid'] = $ask(function () {\n\treturn (int) Drupal::currentUser()->id();\n});\n\n// memoised by ThemeManager::getActiveTheme() and cleared only by resetActiveTheme(), which on a\n// normal request nothing calls -- so the FIRST route to negotiate decides the theme for the object\n$out['theme'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\tif ($container === null || !$container->initialized('theme.manager')) {\n\t\treturn null;\n\t}\n\t$manager = $container->get('theme.manager');\n\treturn $manager->hasActiveTheme() ? $manager->getActiveTheme()->getName() : null;\n});\n\n$out['formErrors'] = $ask(function () {\n\treturn FormState::hasAnyErrors() ? 1 : 0;\n});\n\n$out['seenIds'] = $ask(function () {\n\t$property = new ReflectionProperty(Html::class, 'seenIds');\n\t$value = $property->getValue();\n\treturn is_array($value) ? count($value) : -1;\n});\n\n// the carrier beside it, and the one the blind half could not have caught: it only moves on an\n// AJAX request and nothing in the sweep makes one. Left true it sends getUniqueId() down its\n// random branch, so every id on every later render differs on every request\n$out['isAjax'] = $ask(function () {\n\t$property = new ReflectionProperty(Html::class, 'isAjax');\n\treturn $property->getValue() ? 1 : 0;\n});\n\n// the same shape on a SERVICE, which is why the blind half over class statics cannot see it.\n// Messenger::addMessage() triggers it and core never untriggers it, so one save makes every later\n// render on the incarnation private, no-store and cfw_page stops filling site-wide\n$out['killSwitch'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\tif ($container === null || !$container->initialized('page_cache_kill_switch')) {\n\t\treturn null;\n\t}\n\t$switch = $container->get('page_cache_kill_switch');\n\t$property = new ReflectionProperty($switch, 'kill');\n\treturn $property->getValue($switch) ? 1 : 0;\n});\n\n// the one that costs content: a key left behind by a render that threw makes every later build of\n// that entity and view mode render EMPTY, and nothing anywhere reports it\n$out['recursionKeys'] = $ask(function () {\n\t$property = new ReflectionProperty(EntityViewBuilder::class, 'recursionKeys');\n\t$value = $property->getValue();\n\treturn is_array($value) ? count($value) : -1;\n});\n\n// the flag core resets in a catch and this SAPI can leave set, because an abort is not an\n// exception: true here means every later renderRoot() answers 500\n$out['renderingRoot'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\tif ($container === null || !$container->initialized('renderer')) {\n\t\treturn null;\n\t}\n\t$renderer = $container->get('renderer');\n\t$property = new ReflectionProperty($renderer, 'isRenderingRoot');\n\treturn $property->getValue($renderer) ? 1 : 0;\n});\n\n// keyed by the Request OBJECT in a static SplObjectStorage, so every request ever served stays\n// referenced; correct per request and unbounded across them\n$out['renderContexts'] = $ask(function () {\n\t$property = new ReflectionProperty(Renderer::class, 'contextCollection');\n\t$value = $property->getValue();\n\treturn $value instanceof SplObjectStorage ? $value->count() : -1;\n});\n\n$out['requestStack'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\tif ($container === null || !$container->initialized('request_stack')) {\n\t\treturn null;\n\t}\n\t$stack = $container->get('request_stack');\n\t$property = new ReflectionProperty($stack, 'requests');\n\t$value = $property->getValue($stack);\n\treturn is_array($value) ? count($value) : -1;\n});\n\n// the flash bag lives on a session service that outlives the request, so a message queued for one\n// visitor and never rendered is rendered to the next\n$out['messages'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\tif ($container === null || !$container->initialized('messenger')) {\n\t\treturn null;\n\t}\n\t$counts = [];\n\tforeach ($container->get('messenger')->all() as $type => $list) {\n\t\t$counts[$type] = count($list);\n\t}\n\treturn $counts;\n});\n\n// LocaleLookup::getCid() folds the CURRENT USER'S ROLE IDS into the key and memoises it, so the\n// first request to translate anything decides the key every later one reads; null unless locale is on\n$out['localeCids'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\t$id = 'string_translator.locale.lookup';\n\tif ($container === null || !$container->has($id) || !$container->initialized($id)) {\n\t\treturn null;\n\t}\n\t$service = $container->get($id);\n\t$held = new ReflectionProperty($service, 'translations');\n\t$memo = new ReflectionProperty(CacheCollector::class, 'cid');\n\t$cids = [];\n\tforeach ((array) $held->getValue($service) as $langcode => $contexts) {\n\t\tforeach ((array) $contexts as $context => $lookup) {\n\t\t\t$cids[$langcode . '|' . $context] = is_object($lookup)\n\t\t\t\t? $memo->getValue($lookup)\n\t\t\t\t: null;\n\t\t}\n\t}\n\treturn $cids;\n});\n\n$out['db'] = $ask(function () {\n\t$connection = Database::getConnection();\n\treturn [\n\t\t'buffering' => method_exists($connection, 'isBuffering')\n\t\t\t? (int) $connection->isBuffering()\n\t\t\t: -1,\n\t\t'inTransaction' => (int) $connection->inTransaction(),\n\t\t'hostTransactions' => method_exists($connection, 'transactionCount')\n\t\t\t? $connection->transactionCount()\n\t\t\t: -1,\n\t];\n});\n\n// which of the seeded ids the resetter can actually reset; method_exists() is the gate it applies,\n// so an id with no reset() is skipped in silence\n$out['resetAudit'] = $ask(function () {\n\t$container = Drupal::getContainer();\n\tif ($container === null || !$container->has('drupflare.request_resetter')) {\n\t\treturn null;\n\t}\n\t$resetter = $container->get('drupflare.request_resetter');\n\t$property = new ReflectionProperty($resetter, 'resettable');\n\t$audit = [];\n\tforeach ((array) $property->getValue($resetter) as $id) {\n\t\tif (!$container->has($id)) {\n\t\t\t$audit[$id] = 'absent';\n\t\t\tcontinue;\n\t\t}\n\t\tif (!$container->initialized($id)) {\n\t\t\t$audit[$id] = 'uninitialized';\n\t\t\tcontinue;\n\t\t}\n\t\t$service = $container->get($id);\n\t\t$audit[$id] =\n\t\t\tis_object($service) && method_exists($service, 'reset') ? 'reset' : 'no-reset';\n\t}\n\treturn $audit;\n});\n// #endregion\n\n// #region the blind half\n$fingerprint = function ($value, $depth = 0) use (&$fingerprint) {\n\tif ($depth > 2) {\n\t\treturn 'deep';\n\t}\n\tif ($value === null) {\n\t\treturn 'null';\n\t}\n\tif (is_bool($value)) {\n\t\treturn $value ? 'true' : 'false';\n\t}\n\tif (is_int($value) || is_float($value)) {\n\t\treturn 'n' . $value;\n\t}\n\tif (is_string($value)) {\n\t\treturn 's' . strlen($value) . ':' . substr(md5($value), 0, 6);\n\t}\n\tif (is_array($value)) {\n\t\t$parts = [];\n\t\tforeach ($value as $key => $item) {\n\t\t\t$parts[] = $key . '=' . $fingerprint($item, $depth + 1);\n\t\t}\n\t\treturn 'a' . count($value) . ':' . substr(md5(implode('|', $parts)), 0, 6);\n\t}\n\tif ($value instanceof Closure) {\n\t\treturn 'fn';\n\t}\n\tif ($value instanceof Countable) {\n\t\treturn 'C' . get_class($value) . ':' . count($value);\n\t}\n\tif (is_object($value)) {\n\t\treturn 'o:' . get_class($value);\n\t}\n\treturn 'x';\n};\n\n$statics = [];\n$skipped = 0;\nforeach (get_declared_classes() as $class) {\n\ttry {\n\t\t$reflection = new ReflectionClass($class);\n\t\tforeach ($reflection->getProperties(ReflectionProperty::IS_STATIC) as $property) {\n\t\t\tif ($property->getDeclaringClass()->getName() !== $class) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t$name = $class . '::' . $property->getName();\n\t\t\t\t$statics[$name] = $property->isInitialized()\n\t\t\t\t\t? $fingerprint($property->getValue())\n\t\t\t\t\t: 'uninit';\n\t\t\t} catch (Throwable $e) {\n\t\t\t\t$skipped++;\n\t\t\t}\n\t\t}\n\t} catch (Throwable $e) {\n\t\t$skipped++;\n\t}\n}\nksort($statics);\n$out['statics'] = $statics;\n$out['staticCount'] = count($statics);\n$out['staticSkipped'] = $skipped;\n$out['classCount'] = count(get_declared_classes());\n// #endregion\n\n// #region the blind half over SERVICES\n//\n// THE HALF ABOVE CANNOT SEE A CARRIER THAT IS INSTANCE STATE ON A PERSISTENT SERVICE, and three of\n// the nine named carriers are exactly that: the page-cache kill switch, the renderer's\n// isRenderingRoot and the locale lookup's memoised cid. Each was found by hand and then added to\n// the named list; the blind half walked static properties of declared classes and reported nothing\n// for all three, so the next one would have been found by a browser again.\n//\n// THE initialized() GATE IS THE WHOLE SAFETY PROPERTY. Asking the container for a service it never\n// built would CONSTRUCT the state this is looking for, which is the same mistake as a probe that\n// warms what it reads. Every id is filtered through it, so what is walked is exactly the set the\n// request itself instantiated; a service nobody touched contributes nothing rather than being made.\n$services = [];\n$serviceSkipped = 0;\n$container = Drupal::hasContainer() ? Drupal::getContainer() : null;\nif ($container !== null && method_exists($container, 'getServiceIds')) {\n\tforeach ((array) $container->getServiceIds() as $id) {\n\t\ttry {\n\t\t\tif (!$container->initialized($id)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$service = $container->get($id);\n\t\t\tif (!is_object($service)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t$reflection = new ReflectionObject($service);\n\t\t\tforeach ($reflection->getProperties() as $property) {\n\t\t\t\tif ($property->isStatic()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\t$name = $id . '::' . $property->getName();\n\t\t\t\t\t$services[$name] = $property->isInitialized($service)\n\t\t\t\t\t\t? $fingerprint($property->getValue($service))\n\t\t\t\t\t\t: 'uninit';\n\t\t\t\t} catch (Throwable $e) {\n\t\t\t\t\t$serviceSkipped++;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Throwable $e) {\n\t\t\t$serviceSkipped++;\n\t\t}\n\t}\n}\nksort($services);\n$out['services'] = $services;\n$out['serviceCount'] = count($services);\n$out['serviceSkipped'] = $serviceSkipped;\n$out['servicesInitialized'] =\n\t$container !== null && method_exists($container, 'getServiceIds')\n\t\t? count(\n\t\t\tarray_filter((array) $container->getServiceIds(), function ($id) use ($container) {\n\t\t\t\ttry {\n\t\t\t\t\treturn $container->initialized($id);\n\t\t\t\t} catch (Throwable $e) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}),\n\t\t)\n\t\t: -1;\n// #endregion\n\necho json_encode($out);\n"