Issues (211)

Security Analysis    not enabled

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/Services/AbstractQueuedJob.php (5 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
namespace Symbiote\QueuedJobs\Services;
4
5
use stdClass;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\ORM\DataObject;
8
9
/**
10
 * A base implementation of a queued job that provides some convenience for implementations
11
 *
12
 * This implementation assumes that when you created your job class, you initialised the
13
 * jobData with relevant variables needed to process() your job later on in execution. If you do not,
14
 * please ensure you do before you queueJob() the job, to ensure the signature that is generated is 'correct'.
15
 *
16
 * @author Marcus Nyeholt <[email protected]>
17
 * @license BSD http://silverstripe.org/bsd-license/
18
 */
19
abstract class AbstractQueuedJob implements QueuedJob
20
{
21
    /**
22
     * @var stdClass
23
     */
24
    protected $jobData;
25
26
    /**
27
     * @var array
28
     */
29
    protected $messages = array();
30
31
    /**
32
     * @var int
33
     */
34
    protected $totalSteps = 0;
35
36
    /**
37
     * @var int
38
     */
39
    protected $currentStep = 0;
40
41
    /**
42
     * @var boolean
43
     */
44
    protected $isComplete = false;
45
46
    /**
47
     * Extensions can have a construct but don't have too.
48
     * Without a construct, it's impossible to create a job in the CMS
49
     * @var array params
50
     */
51
    public function __construct($params = array())
52
    {
53
    }
54
55
    /**
56
     * @return string
57
     */
58
    abstract public function getTitle();
59
60
    /**
61
     * Sets a data object for persisting by adding its id and type to the serialised vars
62
     *
63
     * @param DataObject $object
64
     * @param string $name A name to give it, if you want to store more than one
65
     */
66
    protected function setObject(DataObject $object, $name = 'SilverStripe\\Core\\Object')
67
    {
68
        $this->{$name . 'ID'} = $object->ID;
69
        $this->{$name . 'Type'} = $object->ClassName;
70
    }
71
72
    /**
73
     * @param string $name
74
     * @return DataObject|void
75
     */
76
    protected function getObject($name = 'SilverStripe\\Core\\Object')
77
    {
78
        $id = $this->{$name . 'ID'};
79
        $type = $this->{$name . 'Type'};
80
        if ($id) {
81
            return DataObject::get_by_id($type, $id);
82
        }
83
    }
84
85
    /**
86
     * Return a signature for this queued job
87
     *
88
     * @return string
89
     */
90
    public function getSignature()
91
    {
92
        return md5(get_class($this) . serialize($this->jobData));
93
    }
94
95
    /**
96
     * Generate a somewhat random signature
97
     *
98
     * useful if you're want to make sure something is always added
99
     *
100
     * @return string
101
     */
102
    protected function randomSignature()
103
    {
104
        return md5(get_class($this) . time() . mt_rand(0, 100000));
105
    }
106
107
    /**
108
     * By default jobs should just go into the default processing queue
109
     *
110
     * @return string
111
     */
112
    public function getJobType()
113
    {
114
        return QueuedJob::QUEUED;
115
    }
116
117
    /**
118
     * Performs setup tasks the first time this job is run.
119
     *
120
     * This is only executed once for every job. If you want to run something on every job restart, use the
121
     * {@link prepareForRestart} method.
122
     */
123
    public function setup()
124
    {
125
        $this->loadCustomConfig();
126
    }
127
128
    /**
129
     * Run when an already setup job is being restarted.
130
     */
131
    public function prepareForRestart()
132
    {
133
        $this->loadCustomConfig();
134
    }
135
136
    /**
137
     * Do some processing yourself!
138
     */
139
    abstract public function process();
140
141
    /**
142
     * Method for determining whether the job is finished - you may override it if there's
143
     * more to it than just this
144
     */
145
    public function jobFinished()
146
    {
147
        return $this->isComplete;
148
    }
149
150
    /**
151
     * Called when the job is determined to be 'complete'
152
     */
153
    public function afterComplete()
154
    {
155
    }
156
157
    /**
158
     * @return stdClass
159
     */
160
    public function getJobData()
161
    {
162
        // okay, we NEED to store the subsite ID if there's one available
163
        if (!$this->SubsiteID && class_exists('Subsite')) {
0 ignored issues
show
The property SubsiteID does not exist on object<Symbiote\QueuedJo...ices\AbstractQueuedJob>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
164
            /**
165
             * Note: This may need to be checked for 4.x compatibility
166
             */
167
            $this->SubsiteID = \Subsite::currentSubsiteID();
0 ignored issues
show
The property SubsiteID does not exist on object<Symbiote\QueuedJo...ices\AbstractQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
168
        }
169
170
        $data = new stdClass();
171
        $data->totalSteps = $this->totalSteps;
172
        $data->currentStep = $this->currentStep;
173
        $data->isComplete = $this->isComplete;
174
        $data->jobData = $this->jobData;
175
        $data->messages = $this->messages;
176
177
        return $data;
178
    }
179
180
    /**
181
     * @param int $totalSteps
182
     * @param int $currentStep
183
     * @param boolean $isComplete
184
     * @param stdClass $jobData
185
     * @param array $messages
186
     */
187
    public function setJobData($totalSteps, $currentStep, $isComplete, $jobData, $messages)
188
    {
189
        $this->totalSteps = $totalSteps;
190
        $this->currentStep = $currentStep;
191
        $this->isComplete = $isComplete;
192
        $this->jobData = $jobData;
193
        $this->messages = $messages;
194
    }
195
196
    /**
197
     * Gets custom config settings to use when running the job.
198
     *
199
     * @return array|null
200
     */
201
    public function getCustomConfig()
202
    {
203
        return $this->CustomConfig;
0 ignored issues
show
The property CustomConfig does not exist on object<Symbiote\QueuedJo...ices\AbstractQueuedJob>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
204
    }
205
206
    /**
207
     * Sets custom config settings to use when the job is run.
208
     *
209
     * @param array $config
210
     */
211
    public function setCustomConfig(array $config)
212
    {
213
        $this->CustomConfig = $config;
0 ignored issues
show
The property CustomConfig does not exist on object<Symbiote\QueuedJo...ices\AbstractQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
214
    }
215
216
    /**
217
     * Sets custom configuration settings from the job data.
218
     */
219
    private function loadCustomConfig()
220
    {
221
        $custom = $this->getCustomConfig();
222
223
        if (!is_array($custom)) {
224
            return;
225
        }
226
227
        foreach ($custom as $class => $settings) {
228
            foreach ($settings as $setting => $value) {
229
                Config::inst()->update($class, $setting, $value);
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface SilverStripe\Config\Coll...nfigCollectionInterface as the method update() does only exist in the following implementations of said interface: SilverStripe\Config\Coll...\MemoryConfigCollection.

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...
230
            }
231
        }
232
    }
233
234
    /**
235
     * @param string $message
236
     * @param string $severity
237
     */
238
    public function addMessage($message, $severity = 'INFO')
239
    {
240
        $severity = strtoupper($severity);
241
        $this->messages[] = '[' . date('Y-m-d H:i:s') . "][$severity] $message";
242
    }
243
244
    /**
245
     * Convenience methods for setting and getting job data
246
     *
247
     * @param mixed $name
248
     * @param mixed $value
249
     */
250
    public function __set($name, $value)
251
    {
252
        if (!$this->jobData) {
253
            $this->jobData = new stdClass();
254
        }
255
        $this->jobData->$name = $value;
256
    }
257
258
    /**
259
     * Retrieve some job data
260
     *
261
     * @param mixed $name
262
     * @return mixed
263
     */
264
    public function __get($name)
265
    {
266
        return isset($this->jobData->$name) ? $this->jobData->$name : null;
267
    }
268
}
269