1 | remctl PECL Extension for PHP |
---|
2 | |
---|
3 | OVERVIEW |
---|
4 | |
---|
5 | The remctl PECL extension for PHP provides PHP bindings to the libremctl |
---|
6 | client library. The provided interface is roughly the same as the C and |
---|
7 | Perl interfaces, with some minor variations to be more consistent with |
---|
8 | the normal PHP function interface. |
---|
9 | |
---|
10 | This PECL extension provides two interfaces, one which performs a single |
---|
11 | call to a remctl server and returns the result, and another which |
---|
12 | provides more control over the connection, returns individual output |
---|
13 | tokens, and allows multiple commands to be sent via the same connection. |
---|
14 | |
---|
15 | REQUIREMENTS |
---|
16 | |
---|
17 | The module has only been tested with PHP 5.2 and may or may not work |
---|
18 | with earlier versions. As with all libremctl bindings, it does not |
---|
19 | itself obtain Kerberos tickets and requires that a Kerberos ticket cache |
---|
20 | already be set up before making remctl calls. |
---|
21 | |
---|
22 | The PECL module build infrastructure is created on the fly by the |
---|
23 | configure script for the main remctl package using phpize. This means |
---|
24 | that you must have phpize and all of its dependencies installed to build |
---|
25 | the PECL module. |
---|
26 | |
---|
27 | SIMPLIFIED INTERFACE |
---|
28 | |
---|
29 | remctl(HOSTNAME, PORT, PRINCIPAL, COMMAND) |
---|
30 | Runs COMMAND on the remote system and returns an object containing |
---|
31 | the results. COMMAND should be an array of the command, the |
---|
32 | subcommand, and any parameters. HOSTNAME is the remote host to |
---|
33 | connect to. PORT is the port; pass 0 to use the default library |
---|
34 | behavior (first try 4373 and then fall back to 4444). PRINCIPAL is |
---|
35 | the principal of the server to use for authentication; pass in the |
---|
36 | empty string to use the default of host/HOSTNAME with the realm |
---|
37 | determined by domain-realm mapping. |
---|
38 | |
---|
39 | The return value of remctl() is an object which will have the following |
---|
40 | properties: |
---|
41 | |
---|
42 | error |
---|
43 | The error message from the remote host or the local client library |
---|
44 | if the remctl command fails. Set to the empty string if there was |
---|
45 | no error. Checking whether error is the empty string is the |
---|
46 | suppported way of determining whether the call succeeded. |
---|
47 | |
---|
48 | stdout |
---|
49 | The command's standard output or null if there was none. |
---|
50 | |
---|
51 | stdout_len |
---|
52 | The length of the command's standard output or 0 if there was none. |
---|
53 | |
---|
54 | stderr |
---|
55 | The command's standard error or null if there was none. |
---|
56 | |
---|
57 | stderr_len |
---|
58 | The length of the command's standard error or 0 if there was none. |
---|
59 | |
---|
60 | status |
---|
61 | The exit status of the command. |
---|
62 | |
---|
63 | Here is an example using the simplified interface: |
---|
64 | |
---|
65 | dl('remctl.so'); |
---|
66 | if (!extension_loaded('remctl')) { |
---|
67 | echo "Failed to load remctl extension\n"; |
---|
68 | exit(2); |
---|
69 | } |
---|
70 | $command = array('test', 'echo', 'hello world'); |
---|
71 | $result = remctl('server.example.com', 0, '', $command); |
---|
72 | if ($result->error) { |
---|
73 | echo "remctl failed: $result->error\n"; |
---|
74 | exit(2); |
---|
75 | } |
---|
76 | if ($result->stdout_len) { |
---|
77 | echo "stdout: $result->stdout"; |
---|
78 | } |
---|
79 | if ($result->stderr_len) { |
---|
80 | echo "stderr: $result->stderr"; |
---|
81 | } |
---|
82 | echo "status: $result->status"; |
---|
83 | |
---|
84 | Each call to remctl() will open a new connection to the remote host and |
---|
85 | close it after retrieving the results of the command. |
---|
86 | |
---|
87 | FULL INTERFACE |
---|
88 | |
---|
89 | The full remctl interface requires the user to do more bookkeeping, but |
---|
90 | provides more flexibility and visibility into what is happening at a |
---|
91 | protocol level. It allows issuing multiple commands on the same |
---|
92 | persistant connection (provided that the remote server supports protocol |
---|
93 | version two; if it doesn't, the library will transparently fall back to |
---|
94 | opening a connection for each command). |
---|
95 | |
---|
96 | To use the full interface, first create a connection object with |
---|
97 | remctl_new(), connect to a server with remctl_open(), and then |
---|
98 | issue a command with remctl_command() and read output tokens with |
---|
99 | remctl_output(). Once a status token has been received, the command is |
---|
100 | complete and another command can be issued. |
---|
101 | |
---|
102 | The provided functions are: |
---|
103 | |
---|
104 | remctl_new() |
---|
105 | Create a new connection object. This doesn't attempt to connect to |
---|
106 | a host and will only fail if the extension cannot allocate memory. |
---|
107 | |
---|
108 | remctl_error(CONNECTION) |
---|
109 | Returns, as a string, the error message from the last failed |
---|
110 | operation on the connection object CONNECTION. |
---|
111 | |
---|
112 | remctl_open(CONNECTION, HOSTNAME[, PORT[, PRINCIPAL]]) |
---|
113 | Connect to HOSTNAME on port PORT using PRINCIPAL as the remote |
---|
114 | server's principal for authentication. If PORT is omitted or 0, use |
---|
115 | the default (first try 4373, the registered remctl port, and fall |
---|
116 | back to the legacy 4444 port if that fails). If PRINCIPAL is |
---|
117 | omitted or the empty string, use the default of host/HOSTNAME, with |
---|
118 | the realm determined by domain-realm mapping. Returns true on |
---|
119 | success, false on failure. |
---|
120 | |
---|
121 | remctl_command(CONNECTION, COMMAND) |
---|
122 | Send COMMAND (which should be an array) to the remote host. The |
---|
123 | command may, under the remctl protocol, contain any character, but |
---|
124 | be aware that most remctl servers will reject commands or arguments |
---|
125 | containing ASCII 0 (NUL). This currently therefore cannot be used |
---|
126 | for upload of arbitrary unencoded binary data. Returns true on |
---|
127 | success (meaning success in sending the command and implying nothing |
---|
128 | about the result of the command), and false on failure. |
---|
129 | |
---|
130 | remctl_output(CONNECTION) |
---|
131 | Returns the next output token from the remote host. This will be an |
---|
132 | object with one or more of the following properties: |
---|
133 | |
---|
134 | type |
---|
135 | The type of the output token, which will be one of "output", |
---|
136 | "error", "status", or "done". A command will result in either |
---|
137 | one "error" token or zero or more "output" tokens followed by a |
---|
138 | "status" token. The output is complete as soon as any token |
---|
139 | other than an "output" token has been received, but the library |
---|
140 | will keep returning "done" tokens to the caller for as long as |
---|
141 | remctl_output() is called without another remctl_command(). |
---|
142 | |
---|
143 | data |
---|
144 | Returns the contents of the token for either an "error" or |
---|
145 | "output" token. The returned data may contain any character, |
---|
146 | including ASCII 0 (NUL). |
---|
147 | |
---|
148 | stream |
---|
149 | For an "output" token, returns the stream with which the data is |
---|
150 | associated. Currently, this will either be 1 for standard |
---|
151 | output or 2 for standard error. This value is undefined for all |
---|
152 | other token types. |
---|
153 | |
---|
154 | status |
---|
155 | For a "status" token, returns the exit status of the remote |
---|
156 | command. This value is undefined for all other token types. |
---|
157 | |
---|
158 | error |
---|
159 | For an "error" token, returns the remctl error code for the |
---|
160 | protocol error. The text message will be returned in data. |
---|
161 | |
---|
162 | remctl_close(CONNECTION) |
---|
163 | Explicitly close the connection and destroy the connection object. |
---|
164 | This will also be done automatically when the object is destroyed, |
---|
165 | so calling remctl_close explicitly is often not necessary. |
---|
166 | |
---|
167 | Here is an example using the full interface: |
---|
168 | |
---|
169 | dl('remctl.so'); |
---|
170 | if (!extension_loaded('remctl')) { |
---|
171 | echo "Failed to load remctl extension\n"; |
---|
172 | exit(2); |
---|
173 | } |
---|
174 | $r = remctl_new(); |
---|
175 | if ($r == null) { |
---|
176 | echo "remctl_new failed\n"; |
---|
177 | exit(2); |
---|
178 | } |
---|
179 | if (!remctl_open($r, 'server.example.com')) { |
---|
180 | echo "remctl_open failed: " . remctl_error($r) . "\n"; |
---|
181 | exit(2); |
---|
182 | } |
---|
183 | $command = array('test', 'echo', 'hello world'); |
---|
184 | if (!remctl_command($r, $command)) { |
---|
185 | echo "remctl_command failed: " . remctl_error($r) . "\n"; |
---|
186 | } |
---|
187 | $output = remctl_output($r); |
---|
188 | while ($output != null && $output->type != "done") { |
---|
189 | switch($output->type) { |
---|
190 | case "output": |
---|
191 | if ($output->stream == 1) { |
---|
192 | echo "stdout: $output->data"; |
---|
193 | } elseif ($output->stream == 2) { |
---|
194 | echo "stderr: $output->data"; |
---|
195 | } |
---|
196 | break; |
---|
197 | case "error": |
---|
198 | echo "error: $output->error ($output->data)\n"; |
---|
199 | break; |
---|
200 | case "status": |
---|
201 | echo "status: $output->status\n"; |
---|
202 | break; |
---|
203 | default: |
---|
204 | echo "unknown output token type $output->type\n"; |
---|
205 | } |
---|
206 | $output = remctl_output($r); |
---|
207 | } |
---|
208 | if ($output == null) { |
---|
209 | echo "remctl_output failed: " . remctl_error($r) . "\n"; |
---|
210 | exit(2); |
---|
211 | } |
---|
212 | remctl_close($r) |
---|
213 | |
---|
214 | As mentioned above, the final remctl_close() is normally not needed. |
---|
215 | |
---|
216 | HISTORY |
---|
217 | |
---|
218 | This binding was originally written by Andrew Mortensen. part of the |
---|
219 | stock remctl distribution and ongoing maintenance is done by Russ |
---|
220 | Allbery. |
---|