1
#!/usr/bin/env php
2
<?php
3
/*
4
 * StatusNet - the distributed open-source microblogging tool
5
 * Copyright (C) 2009, StatusNet, Inc.
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
# Abort if called from a web server
22
23
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
24
25
$helptext = <<<ENDOFHELP
26
console.php - provide an interactive PHP interpreter for testing
27
28
ENDOFHELP;
29
30
require_once INSTALLDIR.'/scripts/commandline.inc';
31
32
// Assume we're on a terminal if on Windows, otherwise posix_isatty tells us.
33
define('CONSOLE_INTERACTIVE', !function_exists('posix_isatty') || posix_isatty(0));
34
define('CONSOLE_READLINE', CONSOLE_INTERACTIVE && function_exists('readline'));
35
36
if (CONSOLE_READLINE && CONSOLE_INTERACTIVE) {
37
    define('CONSOLE_HISTORY', getenv("HOME") . "/.statusnet_console_history");
38
    if (file_exists(CONSOLE_HISTORY)) {
39
        readline_read_history(CONSOLE_HISTORY);
40
    }
41
}
42
43
function read_input_line($prompt)
44
{
45
    if (CONSOLE_INTERACTIVE) {
46
        if (CONSOLE_READLINE) {
47
            $line = readline($prompt);
48
            if (trim($line) != '') {
49
                readline_add_history($line);
50
                if (defined('CONSOLE_HISTORY')) {
51
                    // Save often; it's easy to hit fatal errors.
52
                    readline_write_history(CONSOLE_HISTORY);
53
                }
54
            }
55
            return $line;
56
        } else {
57
            return readline_emulation($prompt);
58
        }
59
    } else {
60
        return fgets(STDIN);
61
    }
62
}
63
64
/**
65
 * On Unix-like systems where PHP readline extension isn't present,
66
 * -cough- Mac OS X -cough- we can shell out to bash to do it for us.
67
 * This lets us at least handle things like arrow keys, but we don't
68
 * get any entry history. :(
69
 *
70
 * Shamelessly ripped from when I wrote the same code for MediaWiki. :)
71
 * @author Brion Vibber <brion@status.net>
72
 *
73
 * @param string $prompt
74
 * @return mixed string on success, false on fail or EOF
75
 */
76
function readline_emulation($prompt)
77
{
78
    if(CONSOLE_INTERACTIVE && file_exists(trim(shell_exec('which bash')))) {
79
        $encPrompt = escapeshellarg($prompt);
80
        $command = "read -er -p $encPrompt && echo \"\$REPLY\"";
81
        $encCommand = escapeshellarg($command);
82
        $metaCommand = "bash -c $encCommand";
83
84
        // passthru passes our STDIN and TTY to the child...
85
        // We can pull the returned string via output buffering.
86
        ob_start();
87
        $retval = false;
88
        passthru($metaCommand, $retval);
89
        $line = ob_get_contents();
90
        ob_end_clean();
91
92
        if ($retval == 0) {
93
            return $line;
94
        } elseif ($retval == 127) {
95
            // Couldn't execute bash even though we thought we saw it.
96
            // Shell probably spit out an error message, sorry :(
97
            // Fall through to fgets()...
98
        } else {
99
            // EOF/ctrl+D
100
            return false;
101
        }
102
    }
103
104
    // Fallback... we'll have no editing controls, EWWW
105
    if (feof(STDIN)) {
106
        return false;
107
    }
108
    if (CONSOLE_INTERACTIVE) {
109
        print $prompt;
110
    }
111
    return fgets(STDIN);
112
}
113
114
function console_help()
115
{
116
    print "Welcome to StatusNet's interactive PHP console!\n";
117
    print "Type some PHP code and it'll execute...\n";
118
    print "\n";
119
    print "Hint: return a value of any type to output it via var_export():\n";
120
    print "  \$profile = new Profile();\n";
121
    print "  \$profile->find();\n";
122
    print "  \$profile->fetch();\n";
123
    print "  return \$profile;\n";
124
    print "\n";
125
    print "Note that PHP is cranky and you can easily kill your session by mistyping.\n";
126
    print "\n";
127
    print "Type ctrl+D or enter 'exit' to exit.\n";
128
}
129
130
if (CONSOLE_INTERACTIVE) {
131
    print "StatusNet interactive PHP console... type ctrl+D or enter 'exit' to exit.\n";
132
    $prompt = common_config('site', 'name') . '> ';
133
} else {
134
    $prompt = '';
135
}
136
while (!feof(STDIN)) {
137
    $line = read_input_line($prompt);
138
    if ($line === false) {
139
        if (CONSOLE_INTERACTIVE) {
140
            print "\n";
141
        }
142
        break;
143
    } elseif ($line !== '') {
144
        try {
145
            if (trim($line) == 'exit') {
146
                break;
147
            } elseif (trim($line) == 'help') {
148
                console_help();
149
                continue;
150
            }
151
            
152
            // Let's do this!
153
            $result = eval($line);
154
            if ($result === false) {
155
                // parse error
156
            } elseif ($result === null) {
157
                // no return
158
            } else {
159
                // return value from eval'd code
160
                var_export($result);
161
            }
162
        } catch(Exception $e) {
163
            print get_class($e) . ": " . $e->getMessage() . "\n";
164
        }
165
    }
166
    if (CONSOLE_INTERACTIVE) {
167
        print "\n";
168
    }
169
}