Issues (60)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/SmallFilesQueueTransport.php (17 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
    namespace NokitaKaze\Queue;
4
5
    use NokitaKaze\Mutex\FileMutex;
6
7
    class SmallFilesQueueTransport extends AbstractQueueTransport {
8
        const SINGLE_FILE_DB_VERSION = 1;
9
10
        protected $_message_folder;
11
        protected $_queue_name;
12
        protected $_message_folder_subfolder_count = Queue::DefaultMessageFolderSubfolderCount;
13
        protected $_key_to_file = [];
14
        protected $_is_inotify_enabled;
15
        protected $_chunk_file_postfix = '';
16
17
        /**
18
         * @var iMessage[]
19
         */
20
        protected $_last_consumed_messages = [];
21
        /**
22
         * @var integer[] В keys список файлов, которые были прочитаны
23
         */
24
        protected $_consumed_filenames = [];
25
26
        /**
27
         * @param SmallFilesQueueConstructionSettings|object $settings
28
         *
29
         * @throws QueueException
30
         */
31
        function __construct($settings) {
32
            if (!isset($settings->message_folder)) {
33
                throw new QueueException('message_folder has not been set');
34
            }
35
            if (!isset($settings->name)) {
36
                throw new QueueException('name has not been set');
37
            }
38
            $this->_message_folder = $settings->message_folder;
39
            $this->_queue_name = $settings->name;
40
            if (isset($settings->message_folder_subfolder_count)) {
41
                $this->_message_folder_subfolder_count = $settings->message_folder_subfolder_count;
42
            }
43
            if (isset($settings->is_inotify_enabled)) {
44
                $this->_is_inotify_enabled = $settings->is_inotify_enabled;
45
            } else {
46
                $this->_is_inotify_enabled = function_exists('inotify_init');
47
            }
48
            $this->_chunk_file_postfix = '_'.static::generate_rnd_postfix();
49
        }
50
51
        /**
52
         * @param boolean $mode
53
         *
54
         * @hint Ничего не делаем, у этого транспорта нет эксклюзивного режима
55
         * @codeCoverageIgnore
56
         */
57
        function set_exclusive_mode($mode) { }
58
59
        /**
60
         * @return string
61
         */
62
        function get_queue_name() {
63
            return $this->_queue_name;
64
        }
65
66
        function save() {
67
            $this->set_same_time_flag(1);
68
            if (empty($this->_pushed_for_save)) {
69
                return;
70
            }
71
72
            /**
73
             * @var SmallFilesQueueSingleFile $data
74
             */
75
            $data = (object) [];
76
            $data->queue = $this->_pushed_for_save;
0 ignored issues
show
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
77
            $data->queue_name = $this->_queue_name;
0 ignored issues
show
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
78
            $data->time_create = microtime(true);
0 ignored issues
show
Accessing time_create on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
79
            $data->time_last_update = microtime(true);
0 ignored issues
show
Accessing time_last_update on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
80
            $data->version = self::SINGLE_FILE_DB_VERSION;
0 ignored issues
show
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
81
            $num = mt_rand(0, $this->_message_folder_subfolder_count - 1);
82
            $folder = $this->_message_folder.'/'.$num;
83
            FileMutex::create_folders_in_path($folder);
84
            $filename = sprintf('%s/smartqueue_%s%s.chunk.dat',
85
                $folder, number_format(microtime(true), 4, '.', ''), $this->_chunk_file_postfix);
86
87
            $u = file_put_contents($filename, Queue::serialize($data), LOCK_EX);
88
            if ($u === false) {
89
                // @codeCoverageIgnoreStart
90
                throw new QueueException('Can not save queue to a file: '.FileMutex::get_last_php_error_as_string());
91
                // @codeCoverageIgnoreEnd
92
            }
93
            foreach ($this->_pushed_for_save as $message) {
94
                $this->_key_to_file[static::get_real_key_for_message($message)] = $filename;
95
            }
96
            $this->_pushed_for_save = [];
97
        }
98
99
        /**
100
         * @param double|integer $wait_time
101
         *
102
         * @return iMessage|object|null
103
         * @throws QueueException
104
         */
105
        function consume_next_message($wait_time = -1) {
106
            $this->set_same_time_flag(2);
107
            if (!empty($this->_last_consumed_messages)) {
108
                return array_shift($this->_last_consumed_messages);
109
            }
110
111
            return $this->consume_next_message_without_inotify($wait_time);
112
            /*
113
            if ($this->_is_inotify_enabled and false) {// @todo добавить Inotify
114
                // @codeCoverageIgnoreStart
115
                return $this->consume_next_message_with_inotify($wait_time);
116
                // @codeCoverageIgnoreEnd
117
            } else {
118
                return $this->consume_next_message_without_inotify($wait_time);
119
            }
120
            */
121
        }
122
123
        function clear_consumed_keys() {
124
            parent::clear_consumed_keys();
125
            $this->_last_consumed_messages = [];
126
            $this->_consumed_filenames = [];
127
        }
128
129
        function __clone() {
130
            parent::__clone();
131
            foreach ($this->_last_consumed_messages as &$message) {
132
                $message = clone $message;
133
            }
134
        }
135
136
        /**
137
         * @param double|integer $wait_time
138
         *
139
         * @return iMessage|object|null
140
         */
141
        protected function consume_next_message_without_inotify($wait_time = -1) {
142
            $start = microtime(true);
143
            do {
144
                for ($i = 0; $i < $this->_message_folder_subfolder_count; $i++) {
145
                    $folder = $this->_message_folder.'/'.$i;
146
                    if (!file_exists($folder) or !is_readable($folder) or !is_dir($folder)) {
147
                        continue;
148
                    }
149
                    $event = $this->consume_next_message_without_inotify_folder($folder);
150
                    if (!is_null($event)) {
151
                        return $event;
152
                    }
153
                }
154
            } while (($wait_time == -1) or ($start + $wait_time >= microtime(true)));
155
156
            return null;
157
        }
158
159
        /**
160
         * @param string $folder
161
         *
162
         * @return iMessage|object|null
163
         */
164
        protected function consume_next_message_without_inotify_folder($folder) {
165
            foreach (scandir($folder) as $f) {
166
                if (in_array($f, ['.', '..']) or !preg_match('|smartqueue_[0-9.]+(_[a-z0-9]+)?\\.chunk\\.dat$|', $f)) {
167
                    continue;
168
                }
169
                $filename = $folder.'/'.$f;
170
                if (is_dir($filename) or !is_readable($filename)) {
171
                    continue;
172
                }
173
                $event = $this->consume_next_message_from_file($filename);
174
                if (!is_null($event)) {
175
                    return $event;
176
                }
177
            }
178
179
            return null;
180
        }
181
182
183
        /**
184
         * Забираем новые event'ы из файла. Файл должен быть уже существующим, читабельным
185
         *
186
         * Проверка на присутствие в индексе осуществляется в этом файле
187
         *
188
         * @param string $filename
189
         *
190
         * @return iMessage|object|null
191
         */
192
        protected function consume_next_message_from_file($filename) {
193
            if (isset($this->_consumed_filenames[$filename])) {
194
                return null;
195
            }
196
197
            $fi = fopen($filename, 'r');
198
            $locked = flock($fi, LOCK_EX | LOCK_NB);
199
            if (!$locked) {
200
                fclose($fi);
201
202
                return null;
203
            }
204
205
            $buf = file_get_contents($filename);
206
            /**
207
             * @var SmallFilesQueueSingleFile $file_data
208
             */
209
            $file_data = Queue::unserialize($buf, $is_valid);
210
            if (!is_object($file_data)) {
211
                // File does not contain Single Queue object
212
                flock($fi, LOCK_UN);
213
                fclose($fi);
214
215
                return null;
216
            }
217
            if ($file_data->queue_name != $this->get_queue_name()) {
218
                flock($fi, LOCK_UN);
219
                fclose($fi);
220
221
                return null;
222
            }
223
            if ($file_data->version != self::SINGLE_FILE_DB_VERSION) {
224
                flock($fi, LOCK_UN);
225
                fclose($fi);
226
227
                return null;
228
            }
229
230
            $this->_last_consumed_messages = [];
231
            foreach ($file_data->queue as $message) {
232
                $key = self::get_real_key_for_message($message);
233
                if (isset($this->_consumed_keys[$key])) {
234
                    continue;
235
                }
236
237
                $message->time_consumed = microtime(true);
238
                $message->queue = $this;
239
                $this->_key_to_file[$key] = $filename;
240
                $this->_last_consumed_messages[] = $message;
241
                $this->_consumed_keys[$key] = 1;
242
            }
243
            flock($fi, LOCK_UN);
244
            fclose($fi);
245
            $this->_consumed_filenames[$filename] = 1;
246
247
            return !empty($this->_last_consumed_messages) ? array_shift($this->_last_consumed_messages) : null;
248
        }
249
250
        /**
251
         * @param iMessage[]|object[] $messages
252
         */
253
        protected function copy_key_to_file_from_messages(array $messages) {
254
            foreach ($messages as $message) {
255
                if (isset($message->queue) and (get_class($message->queue) == self::class)) {
256
                    foreach ($message->queue->_key_to_file as $key => $filename) {
257
                        $this->_key_to_file[$key] = $filename;
258
                    }
259
                }
260
            }
261
        }
262
263
        /**
264
         * @param iMessage[]|object[] $messages
265
         *
266
         * @return array[]
267
         */
268
        protected function get_filenames_from_messages(array $messages) {
269
            $this->copy_key_to_file_from_messages($messages);
270
            $filenames = [];
271
            $filenames_contains_keys = [];
272
            foreach ($messages as $message) {
273
                $key = self::get_real_key_for_message($message);
274
                if (!isset($this->_key_to_file[$key])) {
275
                    continue;
276
                }
277
                $filename = $this->_key_to_file[$key];
278
                $filenames[] = $filename;
279
                if (!isset($filenames_contains_keys[$filename])) {
280
                    $filenames_contains_keys[$filename] = [];
281
                }
282
283
                $filenames_contains_keys[$filename][] = $key;
284
            }
285
286
            return [$filenames, $filenames_contains_keys];
287
        }
288
289
        /**
290
         * Удалить сообщения и сразу же записать это в БД
291
         *
292
         * @param iMessage[]|object[] $messages
293
         *
294
         * @return string[]|integer[]
295
         * @throws QueueException
296
         */
297
        function delete_messages(array $messages) {
298
            /**
299
             * @var string[][] $filenames_contains_keys
300
             * @var string[]   $filenames
301
             */
302
            list($filenames, $filenames_contains_keys) = $this->get_filenames_from_messages($messages);
303
            $filenames_contains_keys_all = [];
304
            foreach ($this->_key_to_file as $key => $filename) {
305
                if (isset($filenames_contains_keys_all[$filename])) {
306
                    $filenames_contains_keys_all[$filename][] = $key;
307
                } else {
308
                    $filenames_contains_keys_all[$filename] = [$key];
309
                }
310
            }
311
            unset($key, $filename);
312
313
            $deleted_keys = [];
314
            foreach ($filenames as $filename) {
315
                if (!file_exists($filename)) {
316
                    // @todo Надо подумать правильный ли это подход
317
                    // Тут будут все ключи, а не только те, которые надо было удалить
318
                    $deleted_keys = array_merge($deleted_keys, $filenames_contains_keys[$filename]);
319
                    continue;
320
                }
321
                if (!is_writable($filename)) {
322
                    throw new QueueException('Can not delete messages from read only files');
323
                }
324
                if (count($filenames_contains_keys[$filename]) == count($filenames_contains_keys_all[$filename])) {
325
                    // Нужно удалить все записи в файле, значит можно просто удалить файл целиком
326
                    if (!unlink($filename)) {
327
                        // @codeCoverageIgnoreStart
328
                        throw new QueueException('Can not delete file '.$filename.': '.
329
                                                 FileMutex::get_last_php_error_as_string());
330
                        // @codeCoverageIgnoreEnd
331
                    }
332
                    $deleted_keys = array_merge($deleted_keys, $filenames_contains_keys[$filename]);
333
                    continue;
334
                }
335
336
                $fo = fopen($filename, 'r');
337
                $locked = flock($fo, LOCK_EX);
338
                if (!$locked) {
339
                    fclose($fo);
340
                    throw new QueueException('Can not delete file '.$filename);
341
                }
342
                $buf = file_get_contents($filename);
343
                if (empty($buf)) {
344
                    flock($fo, LOCK_UN);
345
                    fclose($fo);
346
                    throw new QueueException('File "'.$filename.'" is empty');
347
                }
348
                /**
349
                 * @var SmallFilesQueueSingleFile $data
350
                 */
351
                $data = Queue::unserialize($buf, $is_valid);
352
                if (!is_object($data)) {
353
                    flock($fo, LOCK_UN);
354
                    fclose($fo);
355
                    throw new QueueException('File "'.$filename.'" does not contain Single Queue object');
356
                }
357
                if ($data->queue_name != $this->get_queue_name()) {
0 ignored issues
show
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
358
                    flock($fo, LOCK_UN);
359
                    fclose($fo);
360
                    throw new QueueException('Invalid queue name ("'.$data->queue_name.
0 ignored issues
show
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
361
                                             '" instead of "'.$this->get_queue_name().'")');
362
                }
363
                if ($data->version != self::SINGLE_FILE_DB_VERSION) {
0 ignored issues
show
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
364
                    flock($fo, LOCK_UN);
365
                    fclose($fo);
366
                    continue;
367
                }
368
                $data->time_last_update = microtime(true);
0 ignored issues
show
Accessing time_last_update on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
369
370
                $new_queue = [];
371
                foreach ($data->queue as $message) {
0 ignored issues
show
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
372
                    $key = self::get_real_key_for_message($message);
373
                    if (!in_array($key, $filenames_contains_keys[$filename])) {
374
                        $message->is_read = true;
375
                        $new_queue[] = $message;
376
                    } else {
377
                        $deleted_keys[] = $key;
378
                    }
379
                }
380
                if (empty($new_queue)) {
381
                    // @hint На самом деле это невозможно
382
                    flock($fo, LOCK_UN);
383
                    fclose($fo);
384
                    if (!unlink($filename)) {
385
                        // @codeCoverageIgnoreStart
386
                        throw new QueueException('Can not delete file '.$filename.': '.
387
                                                 FileMutex::get_last_php_error_as_string());
388
                        // @codeCoverageIgnoreEnd
389
                    }
390
                    continue;
391
                }
392
                $data->queue = $new_queue;
0 ignored issues
show
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
393
                $u = file_put_contents($filename, Queue::serialize($data));
394
                if ($u === false) {
395
                    // @codeCoverageIgnoreStart
396
                    throw new QueueException('Can not save single query file "'.$filename.'": '.
397
                                             FileMutex::get_last_php_error_as_string());
398
                    // @codeCoverageIgnoreEnd
399
                }
400
                flock($fo, LOCK_UN);
401
                fclose($fo);
402
            }
403
404
            return array_unique($deleted_keys);
405
        }
406
407
        /**
408
         * Обновляем сообщение и сразу же сохраняем всё
409
         *
410
         * Эта функция не рейзит ошибку, если сообщение не найдено
411
         *
412
         * @param iMessage|object $message
413
         * @param string|null     $key форсированно задаём ключ сообщения
414
         *
415
         * @return boolean
416
         * @throws QueueException
417
         */
418
        function update_message($message, $key = null) {
419
            $this_key = !is_null($key) ? $key : self::get_real_key_for_message($message);
420
421
            if (!isset($this->_key_to_file[$this_key])) {
422
                // Нет такого файла в списке
423
                return false;
424
            }
425
            $filename = $this->_key_to_file[$this_key];
426
            if (!file_exists($filename)) {
427
                return false;
428
            }
429
            if (!is_writable($filename)) {
430
                throw new QueueException('Can not update read only file');
431
            }
432
433
            $fo = fopen($filename, 'r');
434
            $locked = flock($fo, LOCK_EX);
435
            if (!$locked) {
436
                fclose($fo);
437
                throw new QueueException('Can not delete file '.$filename.': '.FileMutex::get_last_php_error_as_string());
438
            }
439
            $buf = file_get_contents($filename);
440
            if (empty($buf)) {
441
                flock($fo, LOCK_UN);
442
                fclose($fo);
443
                throw new QueueException('File "'.$filename.'" is empty');
444
            }
445
            // @todo обрабатывать ошибки
446
            /**
447
             * @var SmallFilesQueueSingleFile $data_in
448
             */
449
            $data_in = Queue::unserialize($buf, $is_valid);
450
            if (!is_object($data_in)) {
451
                flock($fo, LOCK_UN);
452
                fclose($fo);
453
                throw new QueueException('File "'.$filename.'" does not contain Single Queue object');
454
            }
455
            if ($data_in->version != self::SINGLE_FILE_DB_VERSION) {
0 ignored issues
show
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
456
                flock($fo, LOCK_UN);
457
                fclose($fo);
458
                throw new QueueException('Single DB File version mismatch ('.$data_in->version.
0 ignored issues
show
Accessing version on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
459
                                         ' instead of '.self::SINGLE_FILE_DB_VERSION.')');
460
            }
461
            if ($data_in->queue_name != $this->get_queue_name()) {
0 ignored issues
show
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
462
                flock($fo, LOCK_UN);
463
                fclose($fo);
464
                throw new QueueException('Invalid queue name ("'.$data_in->queue_name.
0 ignored issues
show
Accessing queue_name on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
465
                                         '" instead of "'.$this->get_queue_name().'")');
466
            }
467
            $data_in->time_last_update = microtime(true);
0 ignored issues
show
Accessing time_last_update on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
468
469
            // Ищем то же сообщение и заменяем его
470
            $exists = $this->change_message_in_array($data_in->queue, $message, $this_key);
0 ignored issues
show
Accessing queue on the interface NokitaKaze\Queue\SmallFilesQueueSingleFile 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...
471
            if ($exists) {
472
                $u = file_put_contents($filename, Queue::serialize($data_in));
473
                if ($u === false) {
474
                    // @codeCoverageIgnoreStart
475
                    throw new QueueException('Can not save single query file "'.$filename.'": '.
476
                                             FileMutex::get_last_php_error_as_string());
477
                    // @codeCoverageIgnoreEnd
478
                }
479
            }
480
            flock($fo, LOCK_UN);
481
            fclose($fo);
482
483
            return $exists;
484
        }
485
486
        /**
487
         * Поддерживает ли очередь сортировку event'ов при вставке
488
         *
489
         * @return boolean
490
         */
491
        static function is_support_sorted_events() {
492
            return false;
493
        }
494
495
        /*
496
         * @param double|integer $wait_time
497
         *
498
         * @return iMessage|object|null
499
         *
500
         * @throws QueueException
501
         * @codeCoverageIgnore
502
         /
503
        protected function consume_next_message_with_inotify($wait_time = -1) {
504
            $start = microtime(true);
505
            // @todo написать
506
            throw new QueueException('Не готово');
507
        }
508
        */
509
510
        /*
511
         * @codeCoverageIgnore
512
         /
513
        function test_inotify() {
514
            // @todo этого тут быть не должно
515
            $a = inotify_init();
516
        }
517
        */
518
519
        /**
520
         * @param SmallFilesQueueTransport $queue
521
         *
522
         * @return boolean
523
         */
524
        function is_equal_to($queue) {
525
            if (spl_object_hash($this) == spl_object_hash($queue)) {
526
                return true;
527
            }
528
            if (!parent::is_equal_to($queue)) {
529
                return false;
530
            }
531
532
            return (($queue->_message_folder == $this->_message_folder) and
533
                    ($queue->get_queue_name() == $this->get_queue_name()));
534
        }
535
    }
536
537
?>