1+ <?php
2+ namespace PhpSandbox \Evaluator ;
3+
4+ /**
5+ * Class Snippet
6+ * @package Evaluator
7+ */
8+ class Snippet
9+ {
10+ /**
11+ * @var Config
12+ */
13+ private $ config ;
14+
15+ /**
16+ * Snippet constructor.
17+ * @param Config $config
18+ */
19+ public function __construct (Config $ config )
20+ {
21+ $ this ->config = $ config ;
22+ }
23+
24+ /**
25+ * @param string|null $subFolder
26+ * @return string
27+ */
28+ private function getSnippetsDir ($ subFolder = null )
29+ {
30+ $ dir = $ this ->config ->read ('snippets_dir ' );
31+
32+ if (!is_null ($ subFolder )) {
33+ $ dir .= DIRECTORY_SEPARATOR . $ subFolder ;
34+ }
35+
36+ if (!file_exists ($ dir )) {
37+ mkdir ($ dir , 0755 , true );
38+ }
39+ return $ dir ;
40+ }
41+
42+ /**
43+ * Validate name of created snippet
44+ *
45+ * @param string $name
46+ * @throws SnippetException
47+ */
48+ private function validateName ($ name )
49+ {
50+ if (substr_count ($ name , '/ ' ) > 1 ) {
51+ throw new SnippetException ("Only one level of folders are allowed. " , SnippetException::MAX_NESTING );
52+ }
53+ if (!preg_match ('/^(\w+\/)?[\w\.]+$/ ' , $ name )) {
54+ throw new SnippetException ("Name contains not allowed characters! " , SnippetException::WRONG_NAME );
55+ }
56+ if (false === strpos ($ name , '.php ' )) {
57+ throw new SnippetException ("Extension is required and should be *.php " , SnippetException::MISSING_EXTENSION );
58+ }
59+ }
60+
61+ /**
62+ * Save posted code into snippet
63+ *
64+ * @param string $name
65+ * @param string $code
66+ * @return bool
67+ */
68+ public function save ($ name , $ code )
69+ {
70+ $ this ->validateName ($ name );
71+
72+ $ dir = null ;
73+ if (false !== strpos ($ name , '/ ' )) {
74+ list ($ dir , $ name ) = explode ('/ ' , $ name );
75+ }
76+
77+ $ fh = fopen ($ this ->getSnippetsDir ($ dir ) . DIRECTORY_SEPARATOR . $ name , 'w+ ' );
78+ fwrite ($ fh , $ code );
79+ fclose ($ fh );
80+
81+ return true ;
82+ }
83+
84+ /**
85+ * Return snippet content
86+ *
87+ * @param array $params
88+ */
89+ public function load ($ params )
90+ {
91+ $ fullName = $ this ->getSnippetsDir () . $ params ['filename ' ];
92+
93+ if (file_exists ($ fullName )) {
94+ $ code = file_get_contents ($ fullName );
95+ }
96+
97+ echo json_encode (compact ('code ' ));
98+ }
99+
100+ /**
101+ * Delete snippet
102+ *
103+ * @param array $params
104+ * @throws SnippetException
105+ * @return bool
106+ */
107+ public function delete ($ params )
108+ {
109+ $ fullName = $ this ->getSnippetsDir () . $ params ['filename ' ];
110+
111+ if (!file_exists ($ fullName )) {
112+ throw new SnippetException ("File does not exists! " , SnippetException::FILE_NOT_EXISTS );
113+ }
114+ if (!is_writable ($ fullName )) {
115+ throw new SnippetException ("No permission to modify file! " , SnippetException::NO_PERMISSION );
116+ }
117+
118+ unlink ($ fullName );
119+
120+ $ parts = explode ('/ ' , $ fullName );
121+ array_pop ($ parts );
122+ $ dir = implode ('/ ' , $ parts );
123+
124+ // if dir is empty, remove it
125+ if (count (scandir ($ dir )) == 2 ) {
126+ rmdir ($ dir );
127+ }
128+
129+ return true ;
130+ }
131+
132+ /**
133+ * Return list of all snippets
134+ *
135+ * @return array
136+ */
137+ public function getList ()
138+ {
139+ $ files = $ this ->recursiveScan ($ this ->getSnippetsDir ());
140+ return $ this ->prepareArrayToJson ($ files );
141+ }
142+
143+ /**
144+ * Build JSON with structure of folders and files
145+ *
146+ * @param $files
147+ * @return array
148+ */
149+ private function prepareArrayToJson ($ files )
150+ {
151+ $ tmp = [];
152+ foreach ($ files as $ k => $ value ) {
153+
154+ $ name = $ value ;
155+ $ type = 'file ' ;
156+ $ data = [];
157+
158+ if (preg_match ('/^>\s/ ' , $ k )) {
159+ $ type = 'folder ' ;
160+ $ name = str_replace ('> ' , '' , $ k );
161+ $ data = $ this ->prepareArrayToJson ($ value );
162+ }
163+
164+ $ tmp [] = ['name ' => $ name , 'type ' => $ type , 'data ' => $ data ];
165+ }
166+ return $ tmp ;
167+ }
168+
169+ /**
170+ * Recursive scan selected folder and list all files and folders
171+ *
172+ * @param string $dir
173+ * @return array
174+ */
175+ private function recursiveScan ($ dir )
176+ {
177+ $ files = scandir ($ dir );
178+ $ tmp = [];
179+
180+ foreach ($ files as $ file ) {
181+ if (in_array ($ file , ['. ' , '.. ' ])) {
182+ continue ;
183+ }
184+
185+ if (is_dir ($ dir . DIRECTORY_SEPARATOR . $ file )) {
186+ $ tmp ['> ' . $ file ] = $ this ->recursiveScan ($ dir . DIRECTORY_SEPARATOR . $ file );
187+ } else {
188+ $ tmp [] = $ file ;
189+ }
190+ }
191+ ksort ($ tmp );
192+ return $ tmp ;
193+ }
194+ }
0 commit comments