Issues (1)

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/Chirp.php (1 issue)

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
 * This file is part of Chirp package
4
 *
5
 * Copyright (c) 2015 Alberto Pagliarini
6
 *
7
 * Licensed under the MIT license
8
 * https://github.com/batopa/chirp/blob/master/LICENSE
9
 */
10
namespace Bato\Chirp;
11
12
use Bato\Chirp\Utility\Parser;
13
use MongoDB\Client;
14
use Abraham\TwitterOAuth\TwitterOAuth;
15
16
/**
17
 * Chirp Class
18
 *
19
 * Help to create a cache for Twitter using MongoDB
20
 *
21
 */
22
class Chirp
23
{
24
25
    /**
26
     * The Database object
27
     *
28
     * @var \MongoDB\Database
29
     */
30
    private $db = null;
31
32
    /**
33
     * The instance of TwitterOAuth
34
     *
35
     * @var \Abraham\TwitterOAuth\TwitterOAuth
36
     */
37
    private $twitter;
38
39
    /**
40
     * Constructor
41
     *
42
     * Passing $twitterAuthConf and/or $mongoConf  it tries to setup them
43
     *
44
     * $twitterAuthConf must contain
45
     * - consumer_key
46
     * - consumer_secret
47
     * - oauth_access_token
48
     * - oauth_access_token_secret
49
     *
50
     * $mongoConf must contain
51
     *  - db: the name of mongo database to use
52
     *
53
     *  and can contain
54
     * - uri
55
     * - uriOptions
56
     * - driverOptions
57
     *
58
     * used for MongoDB connection
59
     *
60
     * @see \MongoDB\Client for $mongoConf
61
     * @param array $twitterAuthConf
62
     * @param array $mongoDbConf
63
     */
64
    public function __construct(array $twitterAuthConf = array(), array $mongoDbConf = array())
65
    {
66
        if (!empty($twitterAuthConf)) {
67
            $this->setupTwitter($twitterAuthConf);
68
        }
69
        if (!empty($mongoDbConf)) {
70
            $this->setupMongoDb($mongoDbConf);
71
        }
72
    }
73
74
    /**
75
     * Setup TwitterOAuth
76
     *
77
     * $twitterAuthConf must contain
78
     * - consumer_key
79
     * - consumer_secret
80
     * - oauth_access_token
81
     * - oauth_access_token_secret
82
     *
83
     * @param array $twitterAuthConf
84
     * @return $this
85
     */
86
    public function setupTwitter(array $twitterAuthConf)
87
    {
88
        $twitterAuthConf += [
89
            'consumer_key' => null,
90
            'consumer_secret' => null,
91
            'oauth_access_token' => null,
92
            'oauth_access_token_secret' => null
93
        ];
94
        $this->twitter = new TwitterOAuth(
95
            $twitterAuthConf['consumer_key'],
96
            $twitterAuthConf['consumer_secret'],
97
            $twitterAuthConf['oauth_access_token'],
98
            $twitterAuthConf['oauth_access_token_secret']
99
        );
100
        $this->twitter->setDecodeJsonAsArray(true);
101
        return $this;
102
    }
103
104
    /**
105
     * Setup MongoDB connection
106
     *
107
     * $mongoDbConf must contain
108
     *  - db: the name of mongo database to use
109
     *
110
     *  and can contain
111
     * - uri
112
     * - uriOptions
113
     * - driverOptions
114
     *
115
     * @see \MongoDB\Client for $mongoConf
116
     * @param array $mongoDbConf
117
     * @return $this
118
     */
119
    public function setupMongoDb(array $mongoDbConf)
120
    {
121
        $mongoDbConf += [
122
            'uri' => 'mongodb://localhost:27017',
123
            'uriOptions' => [],
124
            'driverOptions' => [],
125
            'db' => ''
126
        ];
127
        $client = new Client($mongoDbConf['uri'], $mongoDbConf['uriOptions'], $mongoDbConf['driverOptions']);
128
        $this->db = $client->selectDatabase($mongoDbConf['db']);
129
        return $this;
130
    }
131
132
    /**
133
     * Return TwitterOAuth instance
134
     *
135
     * @return \Abraham\TwitterOAuth\TwitterOAuth
136
     */
137
    public function getTwitter()
138
    {
139
        if (empty($this->twitter)) {
140
            throw new \RuntimeException(
141
                'You have to setup twitter before use it. See \Bato\Chirp\Chirp::setupTwitter()'
142
            );
143
        }
144
        return $this->twitter;
145
    }
146
147
    /**
148
     * Return the instance of MongoDB database
149
     *
150
     * @return \MongoDB\Database
151
     */
152
    public function getDb()
153
    {
154
        if (empty($this->db)) {
155
            throw new \RuntimeException(
156
                'You have to setup MongoDB connection before use it. See \Bato\Chirp\Chirp::setupMongoDb()'
157
            );
158
        }
159
        return $this->db;
160
    }
161
162
    /**
163
     * Starting from twitter endpoint return the related collection
164
     * It replaces "/" with "-" after removing trailing "/", for example:
165
     *
166
     * endpoint "statuses/user_timeline" corresponds to "statuses-user_timeline" collection
167
     *
168
     * @param string $endpoint [description]
169
     * @return \MongoDB\Collection
170
     */
171
    public function getCollection($endpoint)
172
    {
173
        $name = Parser::normalize($endpoint);
174
        return $this->getDb()
175
            ->selectCollection($name);
176
    }
177
178
    /**
179
     * Perform a Twitter request
180
     *
181
     * @param string $endpoint the endpoint for example 'statuses/user_timeline'
182
     * @param array $query an array that specify query string to use with the endpoint
183
     * @param string $requestMethod the http request method
184
     * @return array
185
     */
186
    public function request($endpoint, $query = [], $requestMethod = 'get')
187
    {
188
        $validMethods = ['get', 'post', 'put', 'delete'];
189
        $requestMethod = strtolower($requestMethod);
190
        if (!in_array($requestMethod, $validMethods)) {
191
            throw new \UnexpectedValueException('Unsupported http request method ' . $requestMethod);
192
        }
193
        $response = $this->getTwitter()
194
            ->{$requestMethod}($endpoint, $query);
195
196
        return $response;
197
    }
198
199
    /**
200
     * Read results from a collection (default self::collection)
201
     * using $filter to filter results
202
     *
203
     * If $options['limit'] = 1 return a \MongoDB\BSONDocument object
204
     * else return an array or a cursor depending from $options['returnType']
205
     *
206
     * @param string $endpoint
207
     * @param array $filter
208
     * @param array $options
209
     * @return object|array
210
     */
211
    public function read($endpoint, array $filter = [], array $options = [])
212
    {
213
        $options += ['returnType' => 'array'];
214
        $collection = $this->getCollection($endpoint);
215
        // delegate to MongoDB\Collection::findOne()
216
        if (isset($options['limit']) && $options['limit'] === 1) {
217
            return $collection->findOne($filter, $options);
218
        }
219
        $cursor = $collection->find($filter, $options);
220
        return ($options['returnType'] == 'array') ? iterator_to_array($cursor) : $cursor;
221
    }
222
223
    /**
224
     * Perform twitter request and save results in db.
225
     *
226
     * Possible $options are:
227
     * - query: an array used for compose query string
228
     * - grep: an array used for look up. Results matching the grep criteria will be saved.
229
     *         Example
230
     *         ```
231
     *         [
232
     *             'key_to_look_up' => ['match1', 'match2'],
233
     *             'other_key_to_look_up' => ['match3']
234
     *         ]
235
     *         ```
236
     * - require: an array of string of keys required.
237
     *            Only results with those fields will be saved.
238
     *            Use point separtated string to go deep in results, for example
239
     *            `'key1.key2.key3'` checks against`[ 'key1' => ['key2' => ['key3' => 'some_value']]] `
240
     *
241
     * @param string $endpoint the twitter endpoint for example 'statuses/user_timeline'
242
     * @param array $options
243
     * @return array
244
     */
245
    public function write($endpoint, array $options = [])
246
    {
247
        $options = $this->prepareWriteOptions($options);
248
        $response = $this->request($endpoint, $options['query']);
249
        if (empty($response)) {
250
            return ['saved' => [], 'read'=> []];
251
        }
252
253
        if (array_key_exists('errors', $response)) {
254
            return $response;
255
        }
256
257
        $collection = $this->getCollection($endpoint);
258
        $tweets = $this->filterToSave($response, $collection, $options);
259
        if (!empty($tweets)) {
260
            $collection->insertMany($tweets);
261
        }
262
263
        return [
264
            'saved' => $tweets,
265
            'read'=> $response
266
        ];
267
    }
268
269
    /**
270
     * Check and return $options to be used in self::write()
271
     *
272
     * @param array $options
273
     * @return array
274
     */
275
    private function prepareWriteOptions($options)
276
    {
277
        $options += [
278
            'query' => [],
279
            'grep' => [],
280
            'require' => []
281
        ];
282
        foreach (['query', 'grep', 'require'] as $test) {
283
            if (!is_array($options[$test])) {
284
                throw new \UnexpectedValueException('"' . $test . '" option must be an array');
285
            }
286
        }
287
        $options['query'] = array_filter($options['query']);
288
        return $options;
289
    }
290
291
    /**
292
     * Given an array of tweets and a collection
293
     * return the tweets that missing from the collection
294
     *
295
     * @see self::write() for $options
296
     * @param array $tweets
297
     * @param \MongoDB\Collection $collection
298
     * @param array $options
299
     * @return array
300
     */
301
    private function filterToSave(array $tweets, \MongoDB\Collection $collection, array $options)
302
    {
303
        $toSave = [];
304
        foreach ($tweets as $key => $tweet) {
305
            if (!Parser::match($tweet, $options)) {
306
                continue;
307
            }
308
309
            $countTweets = $collection->count(['id_str' => $tweet['id_str']]);
0 ignored issues
show
Deprecated Code introduced by
The method MongoDB\Collection::count() has been deprecated with message: 1.4

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
310
            if ($countTweets === 0) {
311
                $toSave[] = $tweet;
312
            }
313
        }
314
        return $toSave;
315
    }
316
}
317