Completed
Push — master ( d66714...8b3fa3 )
by Никита
03:37
created

FileMutex::is_acquired()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
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)) {
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 1
                $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 1
            }
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 (isset($settings->prefix)) {
1 ignored issue
show
Bug introduced by
Accessing prefix 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...
62 1
                $prefix = $settings->prefix;
1 ignored issue
show
Bug introduced by
Accessing prefix 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...
63 4
            } elseif ($this->_mutex_type == self::SERVER) {
64 4
                $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 6
        static function getDomainString() {
79 6
            if (isset($_SERVER['HTTP_HOST']) and ($_SERVER['HTTP_HOST'] != '')) {
80 1
                return $_SERVER['HTTP_HOST'];
81 6
            } elseif (gethostname() != '') {
82 6
                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
?>