Passed
Push — master ( f3f932...d66714 )
by Никита
02:09
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) {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
42
            /**
43
             * @var MutexSettings $settings
44
             */
45 4
            $settings = (object) $settings;
46 4
            if (!isset($settings->type)) {
1 ignored issue
show
Bug introduced by
Accessing type on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
47
                $settings->type = null;
1 ignored issue
show
Bug introduced by
Accessing type on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
48
            }
49 4
            if (!isset($settings->folder)) {
1 ignored issue
show
Bug introduced by
Accessing folder on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
50 1
                $settings->folder = null;
1 ignored issue
show
Bug introduced by
Accessing folder on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
51 1
            }
52
53 4
            $this->_mutex_type = is_null($settings->type) ? self::SERVER : $settings->type;
1 ignored issue
show
Bug introduced by
Accessing type on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
54 4
            $this->_mutex_folder = is_null($settings->folder) ? sys_get_temp_dir() : $settings->folder;
1 ignored issue
show
Bug introduced by
Accessing folder on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
55 4
            $this->_mutex_name = $settings->name;
1 ignored issue
show
Bug introduced by
Accessing name on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
56 4
            if (isset($settings->delete_on_release)) {
1 ignored issue
show
Bug introduced by
Accessing delete_on_release on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
57
                $this->_delete_on_release = $settings->delete_on_release;
1 ignored issue
show
Bug introduced by
Accessing delete_on_release on the interface NokitaKaze\Mutex\MutexSettings suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
58
            }
59
60 4
            $prefix = '';
61 4
            if ($this->_mutex_type == self::SERVER) {
62 4
                $prefix = hash('sha512', self::getDomainString()).'_';
63 4
            } elseif ($this->_mutex_type == self::DIRECTORY) {
64 1
                $prefix = hash('sha512', strtolower(self::getDirectoryString())).'_';
65 1
            }
66 4
            $this->filename = $this->_mutex_folder.DIRECTORY_SEPARATOR.'smartmutex_'.$prefix.$this->_mutex_name.'.lock';
67 4
        }
68
69 4
        function __destruct() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
70 4
            $this->release_lock();
71 4
        }
72
73
        /**
74
         * @return string
75
         */
76 6
        static function getDomainString() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
77 6
            if (isset($_SERVER['HTTP_HOST']) and ($_SERVER['HTTP_HOST'] != '')) {
78 1
                return $_SERVER['HTTP_HOST'];
79 6
            } elseif (isset($_SERVER['HOSTNAME']) and ($_SERVER['HOSTNAME'] != '')) {
80 1
                return $_SERVER['HOSTNAME'];
81 6
            } elseif (isset($_SERVER['SCRIPT_NAME'])) {
82 5
                return $_SERVER['SCRIPT_NAME'];
83
            } else {
84 2
                return 'none';
85
            }
86
        }
87
88
        /**
89
         * @return string
90
         */
91 2
        static function getDirectoryString() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
92 2
            if (isset($_SERVER['DOCUMENT_ROOT']) and ($_SERVER['DOCUMENT_ROOT'] != '')) {
93 1
                return $_SERVER['DOCUMENT_ROOT'];
94 2
            } elseif (isset($_SERVER['PWD']) and ($_SERVER['PWD'] != '')) {
95 2
                return $_SERVER['PWD'];
96 1
            } elseif (isset($_SERVER['SCRIPT_NAME'])) {
97 1
                return $_SERVER['SCRIPT_NAME'];
98
            } else {
99 1
                return 'none';
100
            }
101
        }
102
103
        /**
104
         * @return boolean
105
         *
106
         * @throws MutexException
107
         */
108 1
        function is_free() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
109 1
            if ($this->_lock_acquired) {
110 1
                return false;
111
            }
112 1
            if (!file_exists(dirname($this->filename))) {
113 1
                throw new MutexException('Folder "'.dirname($this->filename).'" does not exist', 1);
114 1
            } elseif (!is_dir(dirname($this->filename))) {
115 1
                throw new MutexException('Folder "'.dirname($this->filename).'" does not exist', 4);
116 1
            } elseif (!is_writable(dirname($this->filename))) {
117 1
                throw new MutexException('Folder "'.dirname($this->filename).'" is not writable', 2);
118 1
            } elseif (file_exists($this->filename) and !is_writable($this->filename)) {
119 1
                throw new MutexException('File "'.$this->filename.'" is not writable', 3);
120
            }
121
122 1
            $fo = fopen($this->filename, 'ab');
123 1
            $result = flock($fo, LOCK_EX | LOCK_NB);
124 1
            flock($fo, LOCK_UN);
125 1
            fclose($fo);
126
127 1
            return $result;
128
        }
129
130
        /**
131
         * @param double|integer $time
132
         *
133
         * @return bool
134
         * @throws MutexException
135
         */
136 3
        function get_lock($time = -1) {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
137 3
            $tmp_time = microtime(true);
138 3
            if ($this->_lock_acquired) {
139 2
                return true;
140
            }
141
142 3
            if (!file_exists(dirname($this->filename))) {
143 1
                throw new MutexException('Folder "'.dirname($this->filename).'" does not exist', 1);
144 3
            } elseif (!is_dir(dirname($this->filename))) {
145 1
                throw new MutexException('Folder "'.dirname($this->filename).'" is not a folder', 4);
146 3
            } elseif (!is_writable(dirname($this->filename))) {
147 1
                throw new MutexException('Folder "'.dirname($this->filename).'" is not writable', 2);
148 3
            } elseif (file_exists($this->filename) and !is_writable($this->filename)) {
149 1
                throw new MutexException('File "'.$this->filename.'" is not writable', 3);
150
            }
151
152
            // Открываем файл
153 3
            $this->_file_handler = fopen($this->filename, file_exists($this->filename) ? 'ab' : 'wb');
154 3
            while (($this->_file_handler === false) and (
155
                    ($tmp_time + $time >= microtime(true)) or ($time == -1)
156 3
                )) {
157
                usleep(10000);
158
                $this->_file_handler = fopen($this->filename, 'ab');
159
            }
160 3
            if ($this->_file_handler === false) {
161
                return false;
162
            }
163
164
            // Блочим файл
165 3
            if ($time >= 0) {
166 3
                $result = flock($this->_file_handler, LOCK_EX | LOCK_NB);
167 3
                while (!$result and ($tmp_time + $time >= microtime(true))) {
168
                    // U MAD?
169 1
                    usleep(10000);
170 1
                    $result = flock($this->_file_handler, LOCK_EX | LOCK_NB);
171 1
                }
172 3
            } else {
173
                $result = flock($this->_file_handler, LOCK_EX);
174
            }
175
176 3
            if ($result) {
177 3
                $this->_lock_acquired_time = microtime(true);
178
                // @todo Не работает под Windows
179 3
                fwrite($this->_file_handler, posix_getpid()."\n".microtime(true)."\n".posix_getuid()."\n\n");
180 3
                fflush($this->_file_handler);
181 3
                $this->_lock_acquired = true;
182 3
            } else {
183 1
                fclose($this->_file_handler);
184 1
                $this->_file_handler = false;
185
            }
186
187 3
            return $result;
188
        }
189
190 4
        function release_lock() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
191 4
            if (!$this->_lock_acquired) {
192 4
                return;
193
            }
194 3
            if (is_resource($this->_file_handler)) {// @hint По неизвестным причинам это не always true condition
195 3
                flock($this->_file_handler, LOCK_UN);
196 3
                fclose($this->_file_handler);
197 3
            }
198 3
            $this->_file_handler = false;
199 3
            $this->_lock_acquired = false;
200 3
            $this->_lock_acquired_time = null;
201
202 3
            if ($this->_delete_on_release and file_exists($this->filename)) {
203 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...
204 1
            }
205 3
        }
206
207
        /**
208
         * @return double|null
209
         */
210 1
        function get_acquired_time() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
211 1
            return $this->_lock_acquired_time;
212
        }
213
214
        /**
215
         * @return string
216
         */
217 1
        function get_mutex_name() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
218 1
            return $this->_mutex_name;
219
        }
220
221
        /**
222
         * @return boolean
223
         */
224 1
        function get_delete_on_release() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
225 1
            return $this->_delete_on_release;
226
        }
227
228
        /**
229
         * @return boolean
230
         */
231 3
        function is_acquired() {
1 ignored issue
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
232 3
            return $this->_lock_acquired;
233
        }
234
    }
235
236
?>
1 ignored issue
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...