1
+ <?php
2
+
3
+ namespace SoftBricks \Docker ;
4
+
5
+ class Docker
6
+ {
7
+ /**
8
+ * Checks if given output array contains given string
9
+ *
10
+ * @param $output
11
+ * @param $string
12
+ * @return bool
13
+ */
14
+ private function outputContains ($ output , $ string )
15
+ {
16
+ foreach ($ output as $ line ) {
17
+ if (strpos ($ line , $ string ) !== false ) {
18
+ return true ;
19
+ }
20
+ }
21
+ return false ;
22
+ }
23
+
24
+ /**
25
+ * Executes docker command with given args
26
+ *
27
+ * @param array|string $args
28
+ * @return array
29
+ */
30
+ public function executeCommand ($ args = [])
31
+ {
32
+ // we needs the "args" argument to be an array
33
+ if (!is_array ($ args )) {
34
+ $ args = [ $ args ];
35
+ }
36
+ $ outputBuffer = [];
37
+ exec ('docker ' . implode (' ' , $ args ), $ outputBuffer );
38
+ return $ outputBuffer ;
39
+ }
40
+
41
+ /**
42
+ * Returns list of available docker container
43
+ *
44
+ * @param bool $all
45
+ * @return Container[]
46
+ */
47
+ public function ps ($ all = false )
48
+ {
49
+ $ fieldMap = [
50
+ 'id ' => '{{.ID}} ' ,
51
+ 'image ' => '{{.Image}} ' ,
52
+ 'command ' => '{{.Command}} ' ,
53
+ 'createdAt ' => '{{.CreatedAt}} ' ,
54
+ 'runningFor ' => '{{.RunningFor}} ' ,
55
+ 'ports ' => '{{.Ports}} ' ,
56
+ 'status ' => '{{.Status}} ' ,
57
+ 'size ' => '{{.Size}} ' ,
58
+ 'names ' => '{{.Names}} ' ,
59
+ 'labels ' => '{{.Labels}} ' ,
60
+ 'mounts ' => '{{.Mounts}} ' ,
61
+ 'networks ' => '{{.Networks}} ' ,
62
+ ];
63
+
64
+ // run docker ps to receive list of docker container.
65
+ // we do this
66
+ $ cellGlue = '##---## ' ;
67
+ $ format = "table " . implode ($ cellGlue , $ fieldMap );
68
+ $ containerRaw = $ this ->executeCommand ([
69
+ 'ps ' ,
70
+ ($ all ? ' --all ' : '' ),
71
+ '--format " ' . $ format . '" ' ,
72
+ ]);
73
+
74
+ // first line ouf output is just table header
75
+ $ containerList = [];
76
+ if (count ($ containerRaw ) > 1 ) {
77
+ $ containerFields = array_keys ($ fieldMap );
78
+ for ($ index = 1 ; $ index < count ($ containerRaw ); $ index ++) {
79
+ $ line = $ containerRaw [$ index ];
80
+ $ parsedOutputLine = explode ($ cellGlue , $ line );
81
+
82
+ // fill container object using analysed output line
83
+ $ container = new Container ();
84
+ foreach ($ parsedOutputLine as $ key => $ value ) {
85
+ $ container ->{$ containerFields [$ key ]} = $ value ;
86
+ }
87
+
88
+ // we return this generated container object later
89
+ $ containerList [] = $ container ;
90
+ }
91
+ }
92
+
93
+ return $ containerList ;
94
+ }
95
+
96
+ /**
97
+ * Checks if there is a container running under the given name
98
+ *
99
+ * @param $name
100
+ * @return bool
101
+ */
102
+ public function isContainerRunning ($ name )
103
+ {
104
+ foreach ($ this ->ps () as $ container ) {
105
+ if (in_array ($ name , $ container ->getNames ())) {
106
+ return true ;
107
+ }
108
+ }
109
+ return false ;
110
+ }
111
+
112
+ /**
113
+ * Checks if there is a container existing under the given name
114
+ *
115
+ * @param $name
116
+ * @return bool
117
+ */
118
+ public function isContainerExisting ($ name )
119
+ {
120
+ foreach ($ this ->ps (true ) as $ container ) {
121
+ if (in_array ($ name , $ container ->getNames ())) {
122
+ return true ;
123
+ }
124
+ }
125
+ return false ;
126
+ }
127
+
128
+ /**
129
+ * Returns container object for given container name
130
+ *
131
+ * @param $name
132
+ * @return null|Container
133
+ */
134
+ public function getContainerInfo ($ name )
135
+ {
136
+ foreach ($ this ->ps (true ) as $ container ) {
137
+ if (in_array ($ name , $ container ->getNames ())) {
138
+ return $ container ;
139
+ }
140
+ }
141
+
142
+ return null ;
143
+ }
144
+
145
+ /**
146
+ * Starts container with given name. Return if container could be started or not.
147
+ * Will return true if container is already running.
148
+ *
149
+ * @param $name
150
+ * @return bool
151
+ */
152
+ public function start ($ name )
153
+ {
154
+ if (!$ this ->isContainerRunning ($ name )) {
155
+ $ output = $ this ->executeCommand ([
156
+ 'start ' ,
157
+ $ name
158
+ ]);
159
+ return $ output [0 ] === $ name ;
160
+ }
161
+
162
+ return true ;
163
+ }
164
+
165
+ /**
166
+ * Stops container with given name. Returns if container could be stopped or not.
167
+ * Will return true if container is not running.
168
+ *
169
+ * @param $name
170
+ * @return bool
171
+ */
172
+ public function stop ($ name )
173
+ {
174
+ if ($ this ->isContainerRunning ($ name )) {
175
+ $ output = $ this ->executeCommand ([
176
+ 'stop ' ,
177
+ $ name
178
+ ]);
179
+ return $ output [0 ] === $ name ;
180
+ }
181
+
182
+ return true ;
183
+ }
184
+
185
+ /**
186
+ * Kills existing docker container. Returns if container could be killed.
187
+ * Will return true if docker is not running.
188
+ *
189
+ * @param $name
190
+ * @return bool
191
+ */
192
+ public function kill ($ name )
193
+ {
194
+ if ($ this ->isContainerRunning ($ name )) {
195
+ $ this ->executeCommand ([
196
+ 'kill ' ,
197
+ $ name
198
+ ]);
199
+ return $ this ->isContainerRunning ($ name );
200
+ }
201
+
202
+ return true ;
203
+ }
204
+
205
+ /**
206
+ * Removes container with given name. Returns if container could be removed.
207
+ * Will return true if container is not existing.
208
+ *
209
+ * @param $name
210
+ * @param bool $killIfRunning
211
+ * @return bool
212
+ */
213
+ public function remove ($ name , $ killIfRunning = true )
214
+ {
215
+ if ($ this ->isContainerExisting ($ name )) {
216
+
217
+ // running container can not be removed
218
+ if ($ this ->isContainerRunning ($ name ) && !$ killIfRunning ) {
219
+ return false ;
220
+ }
221
+ $ this ->kill ($ name );
222
+ $ this ->executeCommand ([
223
+ 'rm ' ,
224
+ $ name ,
225
+ ]);
226
+ return !$ this ->isContainerExisting ($ name );
227
+ }
228
+
229
+ return true ;
230
+ }
231
+
232
+ /**
233
+ * Runs container under given name with given arguments. Returns if container could be run.
234
+ * Returns false if container is already running.
235
+ *
236
+ * @param $name
237
+ * @param array $args
238
+ * @return bool
239
+ */
240
+ public function run ($ name , $ args = [])
241
+ {
242
+ if (!$ this ->isContainerExisting ($ name )) {
243
+ $ this ->executeCommand (array_merge (
244
+ [
245
+ 'run ' ,
246
+ '--name ' .$ name ,
247
+ ],
248
+ $ args
249
+ ));
250
+ return $ this ->isContainerRunning ($ name );
251
+ }
252
+
253
+ return false ;
254
+ }
255
+
256
+ /**
257
+ * Checks if docker is installed correctly or not
258
+ * (needs to be available over PATH)
259
+ *
260
+ * @return bool
261
+ */
262
+ public function isInstalled ()
263
+ {
264
+ return $ this ->outputContains (
265
+ $ this ->executeCommand ('--version ' ),
266
+ 'Docker version '
267
+ );
268
+ }
269
+ }
0 commit comments