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