getProperties() as $property){ if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){ continue; } if(!$property->isInitialized()){ continue; } $staticCount++; $staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize); } if(count($staticProperties[$className]) === 0){ unset($staticProperties[$className]); } foreach($reflection->getMethods() as $method){ if($method->getDeclaringClass()->getName() !== $reflection->getName()){ continue; } $methodStatics = []; foreach(Utils::promoteKeys($method->getStaticVariables()) as $name => $variable){ $methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } if(count($methodStatics) > 0){ $functionStaticVars[$className . "::" . $method->getName()] = $methodStatics; $functionStaticVarsCount += count($functionStaticVars); } } } file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Wrote $staticCount static properties"); $globalVariables = []; $globalCount = 0; $ignoredGlobals = [ 'GLOBALS' => true, '_SERVER' => true, '_REQUEST' => true, '_POST' => true, '_GET' => true, '_FILES' => true, '_ENV' => true, '_COOKIE' => true, '_SESSION' => true ]; foreach(Utils::promoteKeys($GLOBALS) as $varName => $value){ if(isset($ignoredGlobals[$varName])){ continue; } $globalCount++; $globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Wrote $globalCount global variables"); foreach(get_defined_functions()["user"] as $function){ $reflect = new \ReflectionFunction($function); $vars = []; foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $varName => $variable){ $vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } if(count($vars) > 0){ $functionStaticVars[$function] = $vars; $functionStaticVarsCount += count($vars); } } file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Wrote $functionStaticVarsCount function static variables"); $data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize); do{ $continue = false; foreach(Utils::stringifyKeys($objects) as $hash => $object){ if(!is_object($object)){ continue; } $continue = true; $className = get_class($object); if(!isset($instanceCounts[$className])){ $instanceCounts[$className] = 1; }else{ $instanceCounts[$className]++; } $objects[$hash] = true; $info = [ "information" => "$hash@$className", ]; if($object instanceof \Closure){ $info["definition"] = Utils::getNiceClosureName($object); $info["referencedVars"] = []; $reflect = new \ReflectionFunction($object); if(($closureThis = $reflect->getClosureThis()) !== null){ $info["this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $name => $variable){ $info["referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } }else{ $reflection = new \ReflectionObject($object); $info["properties"] = []; for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){ foreach($reflection->getProperties() as $property){ if($property->isStatic()){ continue; } $name = $property->getName(); if($reflection !== $original){ if($property->isPrivate()){ $name = $reflection->getName() . ":" . $name; }else{ continue; } } if(!$property->isInitialized($object)){ continue; } $info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize); } } } fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n"); } }while($continue); $logger->info("Wrote " . count($objects) . " objects"); fclose($obData); file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); arsort($instanceCounts, SORT_NUMERIC); file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Finished!"); ini_set('memory_limit', $hardLimit); if($gcEnabled){ gc_enable(); } } /** * @param object[]|true[] $objects reference parameter * @param int[] $refCounts reference parameter * * @phpstan-param array $objects * @phpstan-param array $refCounts * @phpstan-param-out array $objects * @phpstan-param-out array $refCounts */ private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{ if($maxNesting <= 0){ return "(error) NESTING LIMIT REACHED"; } --$maxNesting; if(is_object($from)){ if(!isset($objects[$hash = spl_object_hash($from)])){ $objects[$hash] = $from; $refCounts[$hash] = 0; } ++$refCounts[$hash]; $data = "(object) $hash"; }elseif(is_array($from)){ if($recursion >= 5){ return "(error) ARRAY RECURSION LIMIT REACHED"; } $data = []; $numeric = 0; foreach(Utils::promoteKeys($from) as $key => $value){ $data[$numeric] = [ "k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize), "v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize), ]; $numeric++; } }elseif(is_string($from)){ $data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize); }elseif(is_resource($from)){ $data = "(resource) " . print_r($from, true); }elseif(is_float($from)){ $data = "(float) $from"; }else{ $data = $from; } return $data; } }