Passed
Push — master ( 777bbe...3499c9 )
by Никита
02:30
created

FileMutex::get_lock()   C

Complexity

Conditions 16
Paths 15

Size

Total Lines 53
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 17.0078

Importance

Changes 0
Metric Value
dl 0
loc 53
ccs 32
cts 38
cp 0.8421
rs 6.2752
c 0
b 0
f 0
cc 16
eloc 35
nc 15
nop 1
crap 17.0078

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
    namespace NokitaKaze\Mutex;
4
5
    class FileMutex implements MutexInterface {
6
        /**
7
         * @var string Название файла, на котором будет работать мьютекс
8
         */
9
        var $filename = '';
10
        protected $_mutex_type;
11
        /**
12
         * @var string|null Название мьютекса, должно состоять из валидных для имени файлов символов
13
         */
14
        var $_mutex_name;
15
        /**
16
         * @var string|null Место, где расположен файл.
17
         * Не используется в логике класса
18
         */
19
        protected $_mutex_folder;
20
        /**
21
         * @var double|null Время, когда мьютекс был получен
22
         */
23
        protected $_lock_acquired_time = null;
24
        /**
25
         * @var boolean Текущее состояние мьютекса
26
         */
27
        protected $_lock_acquired = false;
28
        /**
29
         * @var resource|false Файл, открывающийся через fopen
30
         */
31
        protected $_file_handler = false;
32
        /**
33
         * @var boolean Удалять файл при анлоке
34
         * В данный момент это unsafe поведение, из-за немандаторного доступа к файлам из PHP
35
         */
36
        protected $_delete_on_release = false;
37
38
        /**
39
         * @param MutexSettings|array $settings
40
         */
41 4
        function __construct($settings) {
42
            /**
43
             * @var MutexSettings $settings
44
             */
45 4
            $settings = (object) $settings;
46 4
            if (!isset($settings->type)) {
47 1
                $settings->type = null;
48 1
            }
49 4
            if (!isset($settings->folder)) {
50 1
                $settings->folder = null;
51 1
            }
52
53 4
            $this->_mutex_type = is_null($settings->type) ? self::SERVER : $settings->type;
54 4
            $this->_mutex_folder = is_null($settings->folder) ? sys_get_temp_dir() : $settings->folder;
55 4
            $this->_mutex_name = $settings->name;
56 4
            if (isset($settings->delete_on_release)) {
57
                $this->_delete_on_release = $settings->delete_on_release;
58
            }
59
60 4
            $prefix = '';
61 4
            if (isset($settings->prefix)) {
62 1
                $prefix = $settings->prefix;
63 4
            } elseif ($this->_mutex_type == self::DOMAIN) {
64 1
                $prefix = hash('sha512', self::getDomainString()).'_';
65 4
            } elseif ($this->_mutex_type == self::DIRECTORY) {
66 1
                $prefix = hash('sha512', strtolower(self::getDirectoryString())).'_';
67 1
            }
68 4
            $this->filename = $this->_mutex_folder.DIRECTORY_SEPARATOR.'smartmutex_'.$prefix.$this->_mutex_name.'.lock';
69 4
        }
70
71 4
        function __destruct() {
72 4
            $this->release_lock();
73 4
        }
74
75
        /**
76
         * @return string
77
         */
78 3
        static function getDomainString() {
79 3
            if (isset($_SERVER['HTTP_HOST']) and ($_SERVER['HTTP_HOST'] != '')) {
80 1
                return $_SERVER['HTTP_HOST'];
81 3
            } elseif (gethostname() != '') {
82 3
                return gethostname();
83
            } elseif (isset($_SERVER['SCRIPT_NAME'])) {
84
                return $_SERVER['SCRIPT_NAME'];
85
            } else {
86
                return 'none';
87
            }
88
        }
89
90
        /**
91
         * @return string
92
         */
93 2
        static function getDirectoryString() {
94 2
            if (isset($_SERVER['DOCUMENT_ROOT']) and ($_SERVER['DOCUMENT_ROOT'] != '')) {
95 1
                return $_SERVER['DOCUMENT_ROOT'];
96 2
            } elseif (isset($_SERVER['PWD']) and ($_SERVER['PWD'] != '')) {
97 2
                return $_SERVER['PWD'];
98 1
            } elseif (isset($_SERVER['SCRIPT_NAME'])) {
99 1
                return dirname($_SERVER['SCRIPT_NAME']);
100
            } else {
101 1
                return 'none';
102
            }
103
        }
104
105
        /**
106
         * @return boolean
107
         *
108
         * @throws MutexException
109
         */
110 1
        function is_free() {
111 1
            if ($this->_lock_acquired) {
112 1
                return false;
113
            }
114 1
            if (!file_exists(dirname($this->filename))) {
115 1
                throw new MutexException('Folder "'.dirname($this->filename).'" does not exist', 1);
116 1
            } elseif (!is_dir(dirname($this->filename))) {
117 1
                throw new MutexException('Folder "'.dirname($this->filename).'" does not exist', 4);
118 1
            } elseif (!is_writable(dirname($this->filename))) {
119 1
                throw new MutexException('Folder "'.dirname($this->filename).'" is not writable', 2);
120 1
            } elseif (file_exists($this->filename) and !is_writable($this->filename)) {
121 1
                throw new MutexException('File "'.$this->filename.'" is not writable', 3);
122
            }
123
124 1
            $fo = fopen($this->filename, 'ab');
125 1
            $result = flock($fo, LOCK_EX | LOCK_NB);
126 1
            flock($fo, LOCK_UN);
127 1
            fclose($fo);
128
129 1
            return $result;
130
        }
131
132
        /**
133
         * @param double|integer $time
134
         *
135
         * @return bool
136
         * @throws MutexException
137
         */
138 3
        function get_lock($time = -1) {
139 3
            $tmp_time = microtime(true);
140 3
            if ($this->_lock_acquired) {
141 2
                return true;
142
            }
143
144 3
            if (!file_exists(dirname($this->filename))) {
145 1
                throw new MutexException('Folder "'.dirname($this->filename).'" does not exist', 1);
146 3
            } elseif (!is_dir(dirname($this->filename))) {
147 1
                throw new MutexException('Folder "'.dirname($this->filename).'" is not a folder', 4);
148 3
            } elseif (!is_writable(dirname($this->filename))) {
149 1
                throw new MutexException('Folder "'.dirname($this->filename).'" is not writable', 2);
150 3
            } elseif (file_exists($this->filename) and !is_writable($this->filename)) {
151 1
                throw new MutexException('File "'.$this->filename.'" is not writable', 3);
152
            }
153
154
            // Открываем файл
155 3
            $this->_file_handler = fopen($this->filename, file_exists($this->filename) ? 'ab' : 'wb');
156 3
            while (($this->_file_handler === false) and (
157
                    ($tmp_time + $time >= microtime(true)) or ($time == -1)
158 3
                )) {
159
                usleep(10000);
160
                $this->_file_handler = fopen($this->filename, 'ab');
161
            }
162 3
            if ($this->_file_handler === false) {
163
                return false;
164
            }
165
166
            // Блочим файл
167 3
            if ($time >= 0) {
168 3
                $result = flock($this->_file_handler, LOCK_EX | LOCK_NB);
169 3
                while (!$result and ($tmp_time + $time >= microtime(true))) {
170
                    // U MAD?
171 1
                    usleep(10000);
172 1
                    $result = flock($this->_file_handler, LOCK_EX | LOCK_NB);
173 1
                }
174 3
            } else {
175
                $result = flock($this->_file_handler, LOCK_EX);
176
            }
177
178 3
            if ($result) {
179 3
                $this->_lock_acquired_time = microtime(true);
180
                // @todo Не работает под Windows
181 3
                fwrite($this->_file_handler, posix_getpid()."\n".microtime(true)."\n".posix_getuid()."\n\n");
182 3
                fflush($this->_file_handler);
183 3
                $this->_lock_acquired = true;
184 3
            } else {
185 1
                fclose($this->_file_handler);
186 1
                $this->_file_handler = false;
187
            }
188
189 3
            return $result;
190
        }
191
192 4
        function release_lock() {
193 4
            if (!$this->_lock_acquired) {
194 4
                return;
195
            }
196 3
            if (is_resource($this->_file_handler)) {// @hint По неизвестным причинам это не always true condition
197 3
                flock($this->_file_handler, LOCK_UN);
198 3
                fclose($this->_file_handler);
199 3
            }
200 3
            $this->_file_handler = false;
201 3
            $this->_lock_acquired = false;
202 3
            $this->_lock_acquired_time = null;
203
204 3
            if ($this->_delete_on_release and file_exists($this->filename)) {
205 1
                @unlink($this->filename);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
206 1
            }
207 3
        }
208
209
        /**
210
         * @return double|null
211
         */
212 1
        function get_acquired_time() {
213 1
            return $this->_lock_acquired_time;
214
        }
215
216
        /**
217
         * @return string
218
         */
219 1
        function get_mutex_name() {
220 1
            return $this->_mutex_name;
221
        }
222
223
        /**
224
         * @return boolean
225
         */
226 1
        function get_delete_on_release() {
227 1
            return $this->_delete_on_release;
228
        }
229
230
        /**
231
         * @return boolean
232
         */
233 3
        function is_acquired() {
234 3
            return $this->_lock_acquired;
235
        }
236
237
        /**
238
         * @param string $path
239
         *
240
         * @throws \NokitaKaze\Mutex\MutexException
241
         */
242 7
        static function create_folders_in_path($path) {
243 7
            $path = rtrim(str_replace('\\', '/', $path), '/');
244
            do {
245 7
                $old_path = $path;
246 7
                $path = str_replace('//', '/', str_replace('/./', '/', $path));
247 7
            } while ($path != $old_path);
248
            do {
249 7
                $path = preg_replace('_/([^/]+?)/../_', '/', $path, -1, $count);
250 7
            } while ($count > 0);
251 7
            unset($old_path, $count);
252
253 7
            $chunks = explode('/', $path);
254 7
            unset($path);
255 7
            $full_path = '';
256 7
            foreach ($chunks as $chunk) {
257
                // @hint Такая логика из-за структуры файловой системы Windows
258 7
                $full_path = str_replace('//', '/', $full_path.'/'.$chunk);
259 7
                if (!file_exists($full_path) and !@mkdir($full_path)) {
260 1
                    throw new MutexException('Can not create folder');
261 7
                } elseif (!is_dir($full_path)) {
262 1
                    throw new MutexException($full_path.' is not a directory');
263
                }
264 7
            }
265 5
        }
266
    }
267
268
?>