Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
queue
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
5 / 5
22
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 init
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 put
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 process
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
10
 save
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
9
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\messenger;
15
16use phpbb\config\config;
17use phpbb\event\dispatcher;
18use phpbb\di\service_collection;
19use phpbb\filesystem\filesystem;
20
21/**
22 * Handling messenger file queue
23 */
24class queue
25{
26    /** @var string */
27    protected $cache_file;
28
29    /** @var config */
30    protected $config;
31
32    /** @var array */
33    protected $data = [];
34
35    /** @var dispatcher */
36    protected $dispatcher;
37
38    /** @var \phpbb\filesystem\filesystem_interface */
39    protected $filesystem;
40
41    /** @var service_collection */
42    protected $messenger_method_collection;
43
44    /** @var array */
45    protected $queue_data = [];
46
47    /**
48     * Messenger queue constructor.
49     *
50     * @param config $config
51     * @param dispatcher $dispatcher
52     * @param service_collection $messenger_method_collection
53     * @param string $cache_file
54     */
55    public function __construct(config $config, dispatcher $dispatcher, service_collection $messenger_method_collection, $cache_file)
56    {
57        $this->config = $config;
58        $this->dispatcher = $dispatcher;
59        $this->messenger_method_collection = $messenger_method_collection;
60        $this->filesystem = new filesystem();
61        $this->cache_file = $cache_file;
62    }
63
64    /**
65     * Init a queue object
66     *
67     * @param string $object     Queue object type: email/etc
68     * @param int $package_size Size of the messenger package to send
69     * @return void
70     */
71    public function init(string $object, int $package_size): void
72    {
73        $this->data[$object] = [];
74        $this->data[$object]['package_size'] = $package_size;
75        $this->data[$object]['data'] = [];
76    }
77
78    /**
79     * Put message into the messenger file queue
80     *
81     * @param string $object         Queue object type: email/etc
82     * @param array $message_data    Message data to send
83     * @return void
84     */
85    public function put(string $object, array $message_data): void
86    {
87        $this->data[$object]['data'][] = $message_data;
88    }
89
90    /**
91     * Process the messenger file queue (using lock file)
92     *
93     * @return void
94     */
95    public function process(): void
96    {
97        $lock = new \phpbb\lock\flock($this->cache_file);
98        $lock->acquire();
99
100        // avoid races, check file existence once
101        $have_cache_file = file_exists($this->cache_file);
102        if (!$have_cache_file || $this->config['last_queue_run'] > time() - $this->config['queue_interval'])
103        {
104            if (!$have_cache_file)
105            {
106                $this->config->set('last_queue_run', time(), false);
107            }
108
109            $lock->release();
110            return;
111        }
112
113        $this->config->set('last_queue_run', time(), false);
114
115        include($this->cache_file);
116
117        /** @psalm-suppress InvalidTemplateParam */
118        $messenger_collection_iterator = $this->messenger_method_collection->getIterator();
119
120        /**
121         * @var \phpbb\messenger\method\messenger_interface $messenger_method
122         * @psalm-suppress UndefinedMethod
123         */
124        foreach ($messenger_collection_iterator as $messenger_method)
125        {
126            if (isset($this->queue_data[$messenger_method->get_queue_object_name()]))
127            {
128                $messenger_method->process_queue($this->queue_data);
129            }
130        }
131
132        if (!count($this->queue_data))
133        {
134            @unlink($this->cache_file);
135        }
136        else
137        {
138            if ($fp = @fopen($this->cache_file, 'wb'))
139            {
140                fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>");
141                fclose($fp);
142
143                if (function_exists('opcache_invalidate'))
144                {
145                    @opcache_invalidate($this->cache_file);
146                }
147
148                try
149                {
150                    $this->filesystem->phpbb_chmod($this->cache_file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
151                }
152                catch (\phpbb\filesystem\exception\filesystem_exception $e)
153                {
154                    // Do nothing
155                }
156            }
157        }
158
159        $lock->release();
160    }
161
162    /**
163     * Save message data to the messenger file queue
164     *
165     * @return void
166     */
167    public function save(): void
168    {
169        if (!count($this->data))
170        {
171            return;
172        }
173
174        $lock = new \phpbb\lock\flock($this->cache_file);
175        $lock->acquire();
176
177        if (file_exists($this->cache_file))
178        {
179            include($this->cache_file);
180
181            foreach ($this->queue_data as $object => $data_ary)
182            {
183                if (isset($this->data[$object]) && count($this->data[$object]))
184                {
185                    $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']);
186                }
187                else
188                {
189                    $this->data[$object]['data'] = $data_ary['data'];
190                }
191            }
192        }
193
194        if ($fp = @fopen($this->cache_file, 'w'))
195        {
196            fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>");
197            fclose($fp);
198
199            if (function_exists('opcache_invalidate'))
200            {
201                @opcache_invalidate($this->cache_file);
202            }
203
204            try
205            {
206                $this->filesystem->phpbb_chmod($this->cache_file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE);
207            }
208            catch (\phpbb\filesystem\exception\filesystem_exception $e)
209            {
210                // Do nothing
211            }
212
213            $this->data = [];
214        }
215
216        $lock->release();
217    }
218}