Issues (64)

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/TelegramLog.php (2 issues)

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
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\TelegramBot;
12
13
use Longman\TelegramBot\Exception\TelegramLogException;
14
use Monolog\Formatter\LineFormatter;
15
use Monolog\Handler\StreamHandler;
16
use Monolog\Logger;
17
18
class TelegramLog
19
{
20
    /**
21
     * Monolog instance
22
     *
23
     * @var \Monolog\Logger
24
     */
25
    static protected $monolog;
26
27
    /**
28
     * Monolog instance for update
29
     *
30
     * @var \Monolog\Logger
31
     */
32
    static protected $monolog_update;
33
34
    /**
35
     * Path for error log
36
     *
37
     * @var string
38
     */
39
    static protected $error_log_path;
40
41
    /**
42
     * Path for debug log
43
     *
44
     * @var string
45
     */
46
    static protected $debug_log_path;
47
48
    /**
49
     * Path for update log
50
     *
51
     * @var string
52
     */
53
    static protected $update_log_path;
54
55
    /**
56
     * Temporary stream handle for debug log
57
     *
58
     * @var resource|null
59
     */
60
    static protected $debug_log_temp_stream_handle;
61
62
    /**
63
     * Initialize
64
     *
65
     * Initilize monolog instance. Singleton
66
     * Is possbile provide an external monolog instance
67
     *
68
     * @param \Monolog\Logger
69
     *
70
     * @return \Monolog\Logger
71
     */
72 3
    public static function initialize(Logger $external_monolog = null)
73
    {
74 3
        if (self::$monolog === null) {
75 3
            if ($external_monolog !== null) {
76 1
                self::$monolog = $external_monolog;
77
78 1
                foreach (self::$monolog->getHandlers() as $handler) {
79 1
                    if ($handler->getLevel() === 400) {
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Monolog\Handler\HandlerInterface as the method getLevel() does only exist in the following implementations of said interface: Monolog\Handler\AbstractHandler, Monolog\Handler\AbstractProcessingHandler, Monolog\Handler\AbstractSyslogHandler, Monolog\Handler\AmqpHandler, Monolog\Handler\BrowserConsoleHandler, Monolog\Handler\BufferHandler, Monolog\Handler\ChromePHPHandler, Monolog\Handler\CouchDBHandler, Monolog\Handler\CubeHandler, Monolog\Handler\DeduplicationHandler, Monolog\Handler\DoctrineCouchDBHandler, Monolog\Handler\DynamoDbHandler, Monolog\Handler\ElasticSearchHandler, Monolog\Handler\ErrorLogHandler, Monolog\Handler\ExceptionTestHandler, Monolog\Handler\FilterHandler, Monolog\Handler\FingersCrossedHandler, Monolog\Handler\FirePHPHandler, Monolog\Handler\FleepHookHandler, Monolog\Handler\FlowdockHandler, Monolog\Handler\GelfHandler, Monolog\Handler\GroupHandler, Monolog\Handler\HipChatHandler, Monolog\Handler\IFTTTHandler, Monolog\Handler\LogEntriesHandler, Monolog\Handler\LogglyHandler, Monolog\Handler\MailHandler, Monolog\Handler\MandrillHandler, Monolog\Handler\MongoDBHandler, Monolog\Handler\NativeMailerHandler, Monolog\Handler\NewRelicHandler, Monolog\Handler\NullHandler, Monolog\Handler\PHPConsoleHandler, Monolog\Handler\PsrHandler, Monolog\Handler\PushoverHandler, Monolog\Handler\RavenHandler, Monolog\Handler\RedisHandler, Monolog\Handler\RollbarHandler, Monolog\Handler\RotatingFileHandler, Monolog\Handler\SamplingHandler, Monolog\Handler\SlackHandler, Monolog\Handler\SocketHandler, Monolog\Handler\StreamHandler, Monolog\Handler\StubNewRelicHandler, Monolog\Handler\StubNewR...HandlerWithoutExtension, Monolog\Handler\SwiftMailerHandler, Monolog\Handler\SyslogHandler, Monolog\Handler\SyslogUdpHandler, Monolog\Handler\TestChromePHPHandler, Monolog\Handler\TestFirePHPHandler, Monolog\Handler\TestHandler, Monolog\Handler\WhatFailureGroupHandler, Monolog\Handler\ZendMonitorHandler.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
80 1
                        self::$error_log_path = 'true';
81
                    }
82 1
                    if ($handler->getLevel() === 100) {
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Monolog\Handler\HandlerInterface as the method getLevel() does only exist in the following implementations of said interface: Monolog\Handler\AbstractHandler, Monolog\Handler\AbstractProcessingHandler, Monolog\Handler\AbstractSyslogHandler, Monolog\Handler\AmqpHandler, Monolog\Handler\BrowserConsoleHandler, Monolog\Handler\BufferHandler, Monolog\Handler\ChromePHPHandler, Monolog\Handler\CouchDBHandler, Monolog\Handler\CubeHandler, Monolog\Handler\DeduplicationHandler, Monolog\Handler\DoctrineCouchDBHandler, Monolog\Handler\DynamoDbHandler, Monolog\Handler\ElasticSearchHandler, Monolog\Handler\ErrorLogHandler, Monolog\Handler\ExceptionTestHandler, Monolog\Handler\FilterHandler, Monolog\Handler\FingersCrossedHandler, Monolog\Handler\FirePHPHandler, Monolog\Handler\FleepHookHandler, Monolog\Handler\FlowdockHandler, Monolog\Handler\GelfHandler, Monolog\Handler\GroupHandler, Monolog\Handler\HipChatHandler, Monolog\Handler\IFTTTHandler, Monolog\Handler\LogEntriesHandler, Monolog\Handler\LogglyHandler, Monolog\Handler\MailHandler, Monolog\Handler\MandrillHandler, Monolog\Handler\MongoDBHandler, Monolog\Handler\NativeMailerHandler, Monolog\Handler\NewRelicHandler, Monolog\Handler\NullHandler, Monolog\Handler\PHPConsoleHandler, Monolog\Handler\PsrHandler, Monolog\Handler\PushoverHandler, Monolog\Handler\RavenHandler, Monolog\Handler\RedisHandler, Monolog\Handler\RollbarHandler, Monolog\Handler\RotatingFileHandler, Monolog\Handler\SamplingHandler, Monolog\Handler\SlackHandler, Monolog\Handler\SocketHandler, Monolog\Handler\StreamHandler, Monolog\Handler\StubNewRelicHandler, Monolog\Handler\StubNewR...HandlerWithoutExtension, Monolog\Handler\SwiftMailerHandler, Monolog\Handler\SyslogHandler, Monolog\Handler\SyslogUdpHandler, Monolog\Handler\TestChromePHPHandler, Monolog\Handler\TestFirePHPHandler, Monolog\Handler\TestHandler, Monolog\Handler\WhatFailureGroupHandler, Monolog\Handler\ZendMonitorHandler.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
83 1
                        self::$debug_log_path = 'true';
84
                    }
85
                }
86
            } else {
87 2
                self::$monolog = new Logger('bot_log');
88
            }
89
        }
90
91 3
        return self::$monolog;
92
    }
93
94
    /**
95
     * Initialize error log
96
     *
97
     * @param string $path
98
     *
99
     * @return \Monolog\Logger
100
     * @throws \Longman\TelegramBot\Exception\TelegramLogException
101
     * @throws \InvalidArgumentException
102
     * @throws \Exception
103
     */
104 2 View Code Duplication
    public static function initErrorLog($path)
105
    {
106 2
        if ($path === null || $path === '') {
107 1
            throw new TelegramLogException('Empty path for error log');
108
        }
109 1
        self::initialize();
110 1
        self::$error_log_path = $path;
111
112 1
        return self::$monolog->pushHandler(
113 1
            (new StreamHandler(self::$error_log_path, Logger::ERROR))
114 1
                ->setFormatter(new LineFormatter(null, null, true))
115
        );
116
    }
117
118
    /**
119
     * Initialize debug log
120
     *
121
     * @param string $path
122
     *
123
     * @return \Monolog\Logger
124
     * @throws \Longman\TelegramBot\Exception\TelegramLogException
125
     * @throws \InvalidArgumentException
126
     * @throws \Exception
127
     */
128 2 View Code Duplication
    public static function initDebugLog($path)
129
    {
130 2
        if ($path === null || $path === '') {
131 1
            throw new TelegramLogException('Empty path for debug log');
132
        }
133 1
        self::initialize();
134 1
        self::$debug_log_path = $path;
135
136 1
        return self::$monolog->pushHandler(
137 1
            (new StreamHandler(self::$debug_log_path, Logger::DEBUG))
138 1
                ->setFormatter(new LineFormatter(null, null, true))
139
        );
140
    }
141
142
    /**
143
     * Get the stream handle of the temporary debug output
144
     *
145
     * @return mixed The stream if debug is active, else false
146
     */
147
    public static function getDebugLogTempStream()
148
    {
149
        if (self::$debug_log_temp_stream_handle === null) {
150
            if (!self::isDebugLogActive()) {
151
                return false;
152
            }
153
            self::$debug_log_temp_stream_handle = fopen('php://temp', 'w+b');
154
        }
155
156
        return self::$debug_log_temp_stream_handle;
157
    }
158
159
    /**
160
     * Write the temporary debug stream to log and close the stream handle
161
     *
162
     * @param string $message Message (with placeholder) to write to the debug log
163
     */
164
    public static function endDebugLogTempStream($message = '%s')
165
    {
166
        if (is_resource(self::$debug_log_temp_stream_handle)) {
167
            rewind(self::$debug_log_temp_stream_handle);
168
            self::debug($message, stream_get_contents(self::$debug_log_temp_stream_handle));
169
            fclose(self::$debug_log_temp_stream_handle);
170
            self::$debug_log_temp_stream_handle = null;
171
        }
172
    }
173
174
    /**
175
     * Initialize update log
176
     *
177
     * Initilize monolog instance. Singleton
178
     * Is possbile provide an external monolog instance
179
     *
180
     * @param string $path
181
     *
182
     * @return \Monolog\Logger
183
     * @throws \Longman\TelegramBot\Exception\TelegramLogException
184
     * @throws \InvalidArgumentException
185
     * @throws \Exception
186
     */
187 2
    public static function initUpdateLog($path)
188
    {
189 2
        if ($path === null || $path === '') {
190 1
            throw new TelegramLogException('Empty path for update log');
191
        }
192 1
        self::$update_log_path = $path;
193 1
        if (self::$monolog_update === null) {
194 1
            self::$monolog_update = new Logger('bot_update_log');
195
            // Create a formatter
196 1
            $output = '%message%' . PHP_EOL;
197 1
            $formatter = new LineFormatter($output);
198
199
            // Update handler
200 1
            $update_handler = new StreamHandler(self::$update_log_path, Logger::INFO);
201 1
            $update_handler->setFormatter($formatter);
202
203 1
            self::$monolog_update->pushHandler($update_handler);
204
        }
205
206 1
        return self::$monolog;
207
    }
208
209
    /**
210
     * Is error log active
211
     *
212
     * @return bool
213
     */
214 4
    public static function isErrorLogActive()
215
    {
216 4
        return self::$error_log_path !== null;
217
    }
218
219
    /**
220
     * Is debug log active
221
     *
222
     * @return bool
223
     */
224 2
    public static function isDebugLogActive()
225
    {
226 2
        return self::$debug_log_path !== null;
227
    }
228
229
    /**
230
     * Is update log active
231
     *
232
     * @return bool
233
     */
234 1
    public static function isUpdateLogActive()
235
    {
236 1
        return self::$update_log_path !== null;
237
    }
238
239
    /**
240
     * Report error log
241
     *
242
     * @param string $text
243
     */
244 4
    public static function error($text)
245
    {
246 4
        if (self::isErrorLogActive()) {
247 4
            $text = self::getLogText($text, func_get_args());
248 4
            self::$monolog->error($text);
249
        }
250 4
    }
251
252
    /**
253
     * Report debug log
254
     *
255
     * @param string $text
256
     */
257 2
    public static function debug($text)
258
    {
259 2
        if (self::isDebugLogActive()) {
260 2
            $text = self::getLogText($text, func_get_args());
261 2
            self::$monolog->debug($text);
262
        }
263 2
    }
264
265
    /**
266
     * Report update log
267
     *
268
     * @param string $text
269
     */
270 1
    public static function update($text)
271
    {
272 1
        if (self::isUpdateLogActive()) {
273 1
            $text = self::getLogText($text, func_get_args());
274 1
            self::$monolog_update->info($text);
275
        }
276 1
    }
277
278
    /**
279
     * Applies vsprintf to the text if placeholder replacements are passed along.
280
     *
281
     * @param string $text
282
     * @param array  $args
283
     *
284
     * @return string
285
     */
286 6
    protected static function getLogText($text, array $args = [])
287
    {
288
        // Pop the $text off the array, as it gets passed via func_get_args().
289 6
        array_shift($args);
290
291
        // If no placeholders have been passed, don't parse the text.
292 6
        if (empty($args)) {
293 4
            return $text;
294
        }
295
296 6
        return vsprintf($text, $args);
297
    }
298
}
299