Completed
Push — master ( 6470f1...618439 )
by Iurii
01:11
created

Editor::validatePhpCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
3
/**
4
 * @package Theme editor
5
 * @author Iurii Makukh <[email protected]>
6
 * @copyright Copyright (c) 2015, Iurii Makukh
7
 * @license https://www.gnu.org/licenses/gpl.html GNU/GPLv3
8
 */
9
10
namespace gplcart\modules\editor\models;
11
12
use gplcart\core\Model;
13
use gplcart\core\models\Language as LanguageModel;
14
use gplcart\modules\backup\models\Backup as ModuleBackupModel;
15
16
/**
17
 * Manages basic behaviors and data related to Theme Editor module
18
 */
19
class Editor extends Model
20
{
21
22
    /**
23
     * Language model instance
24
     * @var \gplcart\core\models\Language $language
25
     */
26
    protected $language;
27
28
    /**
29
     * Backup model instance
30
     * @var \gplcart\modules\backup\models\Backup $backup
31
     */
32
    protected $backup;
33
34
    /**
35
     * @param LanguageModel $language
36
     * @param ModuleBackupModel $backup
37
     */
38
    public function __construct(LanguageModel $language,
39
            ModuleBackupModel $backup)
40
    {
41
        parent::__construct();
42
43
        $this->backup = $backup;
44
        $this->language = $language;
45
    }
46
47
    /**
48
     * Returns an array of editable files
49
     * @param array $module
50
     * @return array
51
     */
52
    public function getList(array $module)
53
    {
54
        $list = array();
55
        foreach (array('templates', 'css', 'js') as $folder) {
56
            $files = gplcart_file_scan_recursive("{$module['directory']}/$folder");
57
            sort($files);
58
            $list[$folder] = $files;
59
        }
60
61
        $this->hook->attach('module.editor.list', $list);
62
        return $list;
63
    }
64
65
    /**
66
     * Saves an edited file
67
     * @param array $data
68
     * @return boolean
69
     */
70
    public function save($data)
71
    {
72
        $result = null;
73
        $this->hook->attach('module.editor.save.before', $data, $result);
74
75
        if (isset($result)) {
76
            return $result;
77
        }
78
79
        $has_backup = true;
80
        if (!$this->hasBackup($data['module'])) {
81
            $has_backup = $this->backup->backup('module', $data['module']);
82
        }
83
84
        if ($has_backup !== true) {
85
            return false;
86
        }
87
88
        $result = $this->write($data['content'], $data['path']);
89
90
        $this->hook->attach('module.editor.save.after', $data, $result);
91
        return $result;
92
    }
93
94
    /**
95
     * Writes a content to a file
96
     * @param string $content
97
     * @param string $file
98
     * @return boolean
99
     */
100
    protected function write($content, $file)
101
    {
102
        if (file_exists($file)) { // Do not create a new file
103
            return file_put_contents($file, $content) !== false;
104
        }
105
106
        return false;
107
    }
108
109
    /**
110
     * Whether a module ID has a backup
111
     * @param array $module
112
     * @return boolean
113
     */
114
    public function hasBackup(array $module)
115
    {
116
        $existing = $this->backup->getList(array('module_id' => $module['id']));
117
        return !empty($existing);
118
    }
119
120
    /**
121
     * Tries to validate syntax of a PHP file
122
     * @param string $file
123
     * @return mixed
124
     */
125
    public function validatePhpFile($file)
126
    {
127
        if (!$this->canValidatePhpCode()) {
128
            return null;
129
        }
130
131
        $output = shell_exec('php -l ' . escapeshellarg($file));
132
133
        $count = 0;
134
        $error = preg_replace('/Errors parsing.*$/', '', $output, -1, $count);
135
        return $count > 0 ? trim("$error") : true;
136
    }
137
138
    /**
139
     * Whether it's possible to validate a PHP code
140
     * @return bool
141
     */
142
    public function canValidatePhpCode()
143
    {
144
        return function_exists('shell_exec') && !in_array('shell_exec', explode(',', ini_get('disable_functions')));
145
    }
146
147
    /**
148
     * Tries to validate a PHP code
149
     * @param string $code
150
     * @return mixed
151
     */
152
    public function validatePhpCode($code)
153
    {
154
        $temp = tmpfile();
155
        fwrite($temp, $code);
156
        $meta_data = stream_get_meta_data($temp);
157
158
        $result = $this->validatePhpFile($meta_data['uri']);
159
        fclose($temp);
160
        return $result;
161
    }
162
163
}
164