-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdb-credentials
More file actions
executable file
·170 lines (142 loc) · 4.8 KB
/
db-credentials
File metadata and controls
executable file
·170 lines (142 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env php
<?php
// Can't use a namespace here yet because of this bug: https://bugs.php.net/bug.php?id=66566
//namespace Loadsys\CakePHPShellScripts\DbCredentials;
/**
* Prints usage information and exits.
*
* @param string $script Typically set to basename($argv[0]) when the method is called.
* @param int $exitCode The numeric exit code to return. 0 = success. >0 = failure.
* @return void
*/
function usage($script = null, $exitCode = 0) {
$script = $script ?: basename(__FILE__);
$usage = <<<EOD
${script}
Reads a Cake app's default database connection configuration and
formats it for consumption by bash scripts or for inclusion in
other PHP scripts. Useful for auto-logging-into the proper
database for the Cake app from the command line, or for initiating
a mysqldump backup.
Depends on the availability of the ConsoleShell, and by extension
the `psy/psysh` composer package.
Usage:
bin/${script}
This will print bash variable declarations to the console. To import
these into another bash script, use `eval \$( bin/${script} )`,
which will populate variables for DB_HOST, DB_PORT, DB_DATABASE,
DB_LOGIN and DB_PASSWORD. See `db-login` for a usage pattern that
preserves special char escaping for DB_PASS.
This script can also detect when it has been `include()`d from
another PHP script, and will return an object with properties set
for any keys defined in [Datasources][default] in config/app.php.
With this style, if ${script} runs into any trouble, it will return
an \Exception, so check for that in your consuming script. You also
need to wrap the call in output buffering to squash the shebang at
the top of this file.
<?php
\$credentialsScript = "bin/db-credentials";
if (!is_readable(\$credentialsScript)) {
echo "!! DB credentials are not available. Aborting.";
exit(3);
}
ob_start(); // Capture the shebang line from db-credentials.
\$db = include(\$credentialsScript);
ob_get_clean(); // Flush it.
if (\$db instanceof \Exception) {
echo \$db->getMessage();
exit(4);
}
// Now safe to access \$db->host, \$db->username, etc.
EOD;
echo $usage;
exit($exitCode);
}
/**
* Simulates a Cake 2 style DB_CONFIG class object.
*
* Obtains values from either the ConfigReadShell when available, or by
* calling the ConsoleShell and loads them into the ::$default class
* property of the instance.
*/
class DbConfig {
/**
* Populate the object's properties with DB connection values.
*
* @return void
*/
public function __construct() {
$injectedCode = 'echo serialize(\Cake\Datasource\ConnectionManager::config("default")) . PHP_EOL; exit;'; // This must be on a single line to work with the REPL.
$cmd = "echo '{$injectedCode}' | "
. escapeshellcmd("bin/cake Console -q");
$response = [];
$code = 0;
exec($cmd, $response, $code);
if (empty($response) || $code > 0) {
throw new RuntimeException(
'Unable to fetch Database config from ConsoleShell.'
);
}
$unserialized = @unserialize(implode('', $response));
if (empty($unserialized)) {
throw new RuntimeException(
'Unable to retrieve Datasources.default config from Configure.'
);
}
foreach ($unserialized as $key => $val) {
$this->{$key} = $val;
}
}
/**
* Handle requests for properties that we didn't obtain from the Cake app.
*
* This will only ever get called when the "real" property doesn't exist,
* so all we have to do is return the empty string.
*
* @param string $name The name of the property being accessed.
* @return string Always the empty string: ''.
*/
public function __get($name) {
return '';
}
}
/**
* Prints essential DB values to the console in bash variable declaration format.
*
* @param DbConfig $db A DbConfig instance with ::$default properties set.
* @return void
*/
function printDbConfig($db) {
echo <<<EOD
DB_HOST='{$db->host}'
DB_PORT='{$db->port}'
DB_DATABASE='{$db->database}'
DB_USERNAME='{$db->username}'
DB_PASSWORD='{$db->password}'
EOD;
}
/**
* main() ===================================================================
*/
if (isset($argv[1]) && $argv[1] == '-h') {
usage();
}
// Determine if this PHP file has been `include()`d from another PHP script.
$isIncluded = (count(get_included_files()) > 1);
// First try running the command line to fetch the configs.
try {
$db = new DbConfig();
} catch (Exception $e) { // If that fails, either pass the exception to our parent, or print the error and exit.
if($isIncluded) {
return $e;
} else {
echo $e->getMessage();
exit(2);
}
}
if($isIncluded) { // Be friendly and return the $db object to them.
return $db;
} else { // Otherwise print bash-compatible var declarations and exit.
printDbConfig($db);
exit(0);
}