Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of Psy Shell.
5
 *
200 lars 6
 * (c) 2012-2023 Justin Hileman
148 lars 7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Psy\Command;
13
 
14
use PhpParser\NodeTraverser;
15
use PhpParser\PrettyPrinter\Standard as Printer;
16
use Psy\Input\CodeArgument;
17
use Psy\ParserFactory;
18
use Psy\Readline\Readline;
19
use Psy\Sudo\SudoVisitor;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Output\OutputInterface;
22
 
23
/**
24
 * Evaluate PHP code, bypassing visibility restrictions.
25
 */
26
class SudoCommand extends Command
27
{
28
    private $readline;
29
    private $parser;
30
    private $traverser;
31
    private $printer;
32
 
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function __construct($name = null)
37
    {
38
        $parserFactory = new ParserFactory();
39
        $this->parser = $parserFactory->createParser();
40
 
41
        $this->traverser = new NodeTraverser();
42
        $this->traverser->addVisitor(new SudoVisitor());
43
 
44
        $this->printer = new Printer();
45
 
46
        parent::__construct($name);
47
    }
48
 
49
    /**
50
     * Set the Shell's Readline service.
51
     *
52
     * @param Readline $readline
53
     */
54
    public function setReadline(Readline $readline)
55
    {
56
        $this->readline = $readline;
57
    }
58
 
59
    /**
60
     * {@inheritdoc}
61
     */
62
    protected function configure()
63
    {
64
        $this
65
            ->setName('sudo')
66
            ->setDefinition([
67
                new CodeArgument('code', CodeArgument::REQUIRED, 'Code to execute.'),
68
            ])
69
            ->setDescription('Evaluate PHP code, bypassing visibility restrictions.')
70
            ->setHelp(
71
                <<<'HELP'
72
Evaluate PHP code, bypassing visibility restrictions.
73
 
74
e.g.
75
<return>>>> $sekret->whisper("hi")</return>
76
<return>PHP error:  Call to private method Sekret::whisper() from context '' on line 1</return>
77
 
78
<return>>>> sudo $sekret->whisper("hi")</return>
79
<return>=> "hi"</return>
80
 
81
<return>>>> $sekret->word</return>
82
<return>PHP error:  Cannot access private property Sekret::$word on line 1</return>
83
 
84
<return>>>> sudo $sekret->word</return>
85
<return>=> "hi"</return>
86
 
87
<return>>>> $sekret->word = "please"</return>
88
<return>PHP error:  Cannot access private property Sekret::$word on line 1</return>
89
 
90
<return>>>> sudo $sekret->word = "please"</return>
91
<return>=> "please"</return>
92
HELP
93
            );
94
    }
95
 
96
    /**
97
     * {@inheritdoc}
98
     *
99
     * @return int 0 if everything went fine, or an exit code
100
     */
101
    protected function execute(InputInterface $input, OutputInterface $output)
102
    {
103
        $code = $input->getArgument('code');
104
 
105
        // special case for !!
106
        if ($code === '!!') {
107
            $history = $this->readline->listHistory();
108
            if (\count($history) < 2) {
109
                throw new \InvalidArgumentException('No previous command to replay');
110
            }
111
            $code = $history[\count($history) - 2];
112
        }
113
 
114
        if (\strpos($code, '<?') === false) {
115
            $code = '<?php '.$code;
116
        }
117
 
118
        $nodes = $this->traverser->traverse($this->parse($code));
119
 
120
        $sudoCode = $this->printer->prettyPrint($nodes);
121
        $shell = $this->getApplication();
122
        $shell->addCode($sudoCode, !$shell->hasCode());
123
 
124
        return 0;
125
    }
126
 
127
    /**
128
     * Lex and parse a string of code into statements.
129
     *
130
     * @param string $code
131
     *
132
     * @return array Statements
133
     */
134
    private function parse(string $code): array
135
    {
136
        try {
137
            return $this->parser->parse($code);
138
        } catch (\PhpParser\Error $e) {
139
            if (\strpos($e->getMessage(), 'unexpected EOF') === false) {
140
                throw $e;
141
            }
142
 
143
            // If we got an unexpected EOF, let's try it again with a semicolon.
144
            return $this->parser->parse($code.';');
145
        }
146
    }
147
}