Skip to content

Commit efdf827

Browse files
committed
Add a command line export tool.
1 parent 2052dd2 commit efdf827

File tree

1 file changed

+359
-0
lines changed

1 file changed

+359
-0
lines changed

OracleCLI.php

+359
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
<?php
2+
/*
3+
OracleEditor.php Command Line Interface
4+
Version 1.20
5+
by Tim Strehle <[email protected]>
6+
7+
https://github.com/tistre/oracleeditor
8+
9+
Usage:
10+
11+
php OracleCLI.php \
12+
--user=me \
13+
--password=secret \
14+
--service='oracle.example.com:1721/DB' \
15+
--limit=10 \
16+
--format=xml \
17+
--query="select * from DUAL"
18+
*/
19+
20+
// Don't write PHP warnings into HTML. Watch your PHP error_log file!
21+
22+
ini_set('display_errors', 0);
23+
24+
// Format version string
25+
26+
$version = trim(substr('$Revision: 1.20 $', 10, -1));
27+
28+
// Read command line options
29+
30+
$defaults = [
31+
'format' => 'xml',
32+
'limit' => 100
33+
];
34+
35+
$options = getopt('', ['user:', 'password:', 'service:', 'format:', 'query:', 'limit:']);
36+
37+
$requiredOptions = ['user', 'password', 'service', 'query'];
38+
39+
foreach ($requiredOptions as $option) {
40+
if (!isset($options[$option])) {
41+
die(sprintf("ERROR: --%s is required.\n", $option));
42+
}
43+
}
44+
45+
$options = array_merge($defaults, $options);
46+
47+
if (!is_numeric($options['limit'])) {
48+
die("ERROR: --limit must be a number.\n");
49+
}
50+
51+
$exportformats = [
52+
'xml' => ['XML', 'text/xml'],
53+
'csv' => ['CSV', 'text/comma-separated-values'],
54+
'html' => ['HTML table', 'text/html']
55+
];
56+
57+
if (!isset($exportformats[$options['format']])) {
58+
die(sprintf("ERROR: --format must be one of %s.\n", implode(', ', array_keys($exportformats))));
59+
}
60+
61+
// Initialize database connection parameters
62+
63+
if ($options['user'] !== substr(preg_replace('/[^a-zA-Z0-9$_-]/', '',
64+
$options['user']), 0, 30)) {
65+
die("ERROR: --user contains invalid characters.\n");
66+
}
67+
68+
if ($options['service'] !== substr(preg_replace('|[^a-zA-Z0-9:.() =/_-]|', '',
69+
$options['service']), 0, 2000)) {
70+
die("ERROR: --service contains invalid characters.\n");
71+
}
72+
73+
$charset = 'UTF-8';
74+
75+
// Initialize connection
76+
77+
$conn = false;
78+
79+
pof_connect();
80+
81+
// Exporting may take a while
82+
83+
set_time_limit(0);
84+
85+
// Initialize export settings
86+
87+
$exportlimit = abs(intval($options['limit']));
88+
89+
// Loop through results
90+
91+
$cursor = pof_opencursor($options['query']);
92+
93+
if ($cursor) {
94+
if (ocistatementtype($cursor) !== 'SELECT') {
95+
pof_closecursor($cursor);
96+
die("ERROR: --query must be a SELECT statement.\n");
97+
}
98+
}
99+
100+
$columns = [];
101+
$numcols = ocinumcols($cursor);
102+
103+
for ($j = 1; $j <= $numcols; $j++) {
104+
if (ocicolumnname($cursor, $j) != 'ROWID_') {
105+
$columns[(ocicolumnname($cursor, $j))] = array(
106+
'type' => ocicolumntype($cursor, $j),
107+
'size' => ocicolumnsize($cursor, $j)
108+
);
109+
}
110+
}
111+
112+
// Header
113+
114+
if ($options['format'] == 'xml') {
115+
echo sprintf('<' . '?xml version="1.0" encoding="%s"?' . '>', $charset) . "\n";
116+
echo "<!-- Generated by OracleEditor.php (https://github.com/tistre/oracleeditor) -->\n";
117+
118+
$userstr = $options['user'];
119+
$userstr .= '@' . $options['service'];
120+
121+
echo sprintf('<rowset exported="%s" user="%s" server="%s">', date('Y-m-d\TH:i:s'), $userstr,
122+
$_SERVER['SERVER_NAME']) . "\n";
123+
echo sprintf("\t<sql>%s</sql>\n", htmlspecialchars($options['query']));
124+
125+
// Column aliases: We can use column names as tag names only if
126+
// they're valid XML names - <count(MYFIELD)> won't work.
127+
128+
$i = 0;
129+
foreach ($columns as $name => $column) {
130+
$i++;
131+
132+
if (preg_match('/^[a-zA-Z][a-zA-Z0-9_-]*$/', $name) == 0) {
133+
$columns[$name]['alias'] = 'ALIAS' . $i;
134+
}
135+
}
136+
137+
echo "\t<columns>\n";
138+
foreach ($columns as $name => $column) {
139+
echo sprintf("\t\t" . '<column name="%s" type="%s" size="%s"%s/>' . "\n",
140+
htmlspecialchars($name),
141+
$column['type'],
142+
$column['size'],
143+
(isset($column['alias']) ? ' alias="' . $column['alias'] . '"' : '')
144+
);
145+
}
146+
echo "\t</columns>\n";
147+
} elseif ($options['format'] == 'csv') {
148+
$first = true;
149+
150+
foreach ($columns as $name => $column) {
151+
if ($name != 'ROWID_') {
152+
if (!$first) {
153+
echo ', ';
154+
}
155+
echo sprintf('"%s"', str_replace('"', '""', $name));
156+
$first = false;
157+
}
158+
}
159+
160+
echo "\n";
161+
} elseif ($options['format'] == 'html') { ?>
162+
163+
<html>
164+
<head>
165+
<meta http-equiv="content-type" content="text/html; charset=<?php echo $charset; ?>">
166+
<meta name="date" content="<?php echo date('Y-m-d\TH:i:s'); ?>">
167+
<meta name="generator" content="OracleEditor.php (https://github.com/tistre/oracleeditor)">
168+
<title>Exported Oracle data (by OracleEditor.php)</title>
169+
</head>
170+
<body>
171+
172+
<h1>Exported Oracle data</h1>
173+
174+
<?php
175+
$userstr = $options['user'];
176+
$userstr .= '@' . $options['service'];
177+
?>
178+
179+
<p>The Oracle user <em><?php echo htmlspecialchars($userstr); ?></em> exported this data on
180+
<em><?php echo date('r'); ?></em>
181+
by running the following SQL statement in OracleCLI.php:<br/>
182+
<pre><?php echo htmlspecialchars($options['query']); ?></pre></p>
183+
184+
<table border="1">
185+
<tr>
186+
187+
<?php
188+
189+
foreach ($columns as $name => $column) {
190+
echo sprintf('<th>%s<br />(%s, %s)</th>' . "\n",
191+
htmlspecialchars($name),
192+
$column['type'],
193+
$column['size']
194+
);
195+
}
196+
197+
?>
198+
199+
</tr>
200+
201+
<?php
202+
}
203+
204+
// Rows
205+
206+
$i = 1;
207+
208+
while (true) {
209+
if (!ocifetchinto($cursor, $row, OCI_ASSOC | OCI_RETURN_LOBS)) {
210+
break;
211+
}
212+
213+
if ($options['format'] == 'xml') {
214+
echo sprintf("\t<row%s>\n",
215+
(isset($row['ROWID_']) ? (' id="' . htmlspecialchars($row['ROWID_']) . '"') : ''));
216+
217+
foreach ($row as $fieldname => $value) {
218+
if ($fieldname != 'ROWID_') {
219+
echo sprintf("\t\t<%1\$s>%2\$s</%1\$s>\n",
220+
(isset($columns[$fieldname]['alias']) ? $columns[$fieldname]['alias'] : $fieldname),
221+
htmlspecialchars($value));
222+
}
223+
}
224+
225+
echo "\t</row>\n";
226+
} elseif ($options['format'] == 'csv') {
227+
$first = true;
228+
229+
foreach ($columns as $fieldname => $column) {
230+
if ($fieldname != 'ROWID_') {
231+
if (!$first) {
232+
echo ', ';
233+
}
234+
if (isset($row[$fieldname])) {
235+
echo sprintf('"%s"', str_replace('"', '""', $row[$fieldname]));
236+
} else {
237+
echo '""';
238+
}
239+
$first = false;
240+
}
241+
}
242+
243+
echo "\n";
244+
} elseif ($options['format'] == 'html') {
245+
echo "<tr>\n";
246+
247+
foreach ($columns as $fieldname => $column) {
248+
if ($fieldname != 'ROWID_') {
249+
echo "\t<td>";
250+
if (isset($row[$fieldname])) {
251+
echo htmlspecialchars($row[$fieldname]);
252+
}
253+
echo "</td>\n";
254+
}
255+
}
256+
257+
echo "</tr>\n";
258+
}
259+
260+
if (($exportlimit > 0) && ($exportlimit <= ++$i)) {
261+
break;
262+
}
263+
}
264+
265+
// Footer
266+
267+
if ($options['format'] == 'xml') {
268+
echo "</rowset>\n";
269+
} elseif ($options['format'] == 'html') { ?>
270+
271+
</table>
272+
<p>HTML generated by <a
273+
href="https://github.com/tistre/oracleeditor">OracleEditor.php</a> <?php echo $version; ?>
274+
&copy; 2017 by <a href="https://www.strehle.de/tim/">Tim Strehle</a> &lt;<a
275+
href="mailto:[email protected]">[email protected]</a>&gt;</p>
276+
</body>
277+
</html>
278+
279+
<?php
280+
}
281+
282+
pof_closecursor($cursor);
283+
284+
285+
function pof_connect()
286+
{
287+
global $conn, $options;
288+
289+
$conn = oci_connect
290+
(
291+
$options['user'],
292+
$options['password'],
293+
$options['service'],
294+
'AL32UTF8'
295+
);
296+
297+
$err = ocierror();
298+
299+
if (is_array($err)) {
300+
die(sprintf("ERROR: Logon failed: %s\n", $err['message']));
301+
}
302+
}
303+
304+
305+
function pof_disconnect()
306+
{
307+
global $conn;
308+
309+
if ($conn) {
310+
ocilogoff($conn);
311+
}
312+
}
313+
314+
315+
function pof_opencursor($sql, $bind = false)
316+
{
317+
global $conn, $options;
318+
319+
$cursor = ociparse($conn, $sql);
320+
321+
if (!$cursor) {
322+
$err = ocierror($conn);
323+
if (is_array($err)) {
324+
die(sprintf("ERROR: Parse failed: %s\n", $err['message']));
325+
}
326+
} else { // This might improve performance?
327+
ocisetprefetch($cursor, $options['limit']);
328+
329+
if (is_array($bind)) {
330+
foreach ($bind as $fieldname => $value) {
331+
ocibindbyname($cursor, ':' . $fieldname, $bind[$fieldname], -1);
332+
}
333+
}
334+
335+
$ok = ociexecute($cursor);
336+
337+
if (!$ok) {
338+
$err = ocierror($cursor);
339+
340+
if (is_array($err)) {
341+
die(sprintf("ERROR: Execute failed: %s\n", $err['message']));
342+
}
343+
344+
pof_closecursor($cursor);
345+
346+
$cursor = false;
347+
}
348+
}
349+
350+
return $cursor;
351+
}
352+
353+
354+
function pof_closecursor($cursor)
355+
{
356+
if ($cursor) {
357+
ocifreestatement($cursor);
358+
}
359+
}

0 commit comments

Comments
 (0)