This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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 Reallyli\AB; |
||
4 | |||
5 | use Illuminate\Http\Request; |
||
6 | use Reallyli\AB\Models\Goal; |
||
7 | use Reallyli\AB\Models\Experiment; |
||
8 | use Illuminate\Support\Facades\Route; |
||
9 | use Illuminate\Support\Facades\Config; |
||
10 | use Reallyli\AB\Session\SessionInterface; |
||
11 | |||
12 | class Tester |
||
13 | { |
||
14 | /** |
||
15 | * The Session instance. |
||
16 | * |
||
17 | * @var SessionInterface |
||
18 | */ |
||
19 | protected $session; |
||
20 | |||
21 | /** |
||
22 | * Constructor. |
||
23 | * |
||
24 | * @param SessionInterface $session |
||
25 | */ |
||
26 | public function __construct(SessionInterface $session) |
||
27 | { |
||
28 | $this->session = $session; |
||
29 | } |
||
30 | |||
31 | /** |
||
32 | * Track clicked links and form submissions. |
||
33 | * |
||
34 | * @param Request $request |
||
35 | * @return void |
||
36 | */ |
||
37 | public function track(Request $request) |
||
38 | { |
||
39 | // Don't track if there is no active experiment. |
||
40 | if (! $this->session->get('experiment')) { |
||
41 | return; |
||
42 | } |
||
43 | |||
44 | // Since there is an ongoing experiment, increase the pageviews. |
||
45 | // This will only be incremented once during the whole experiment. |
||
46 | $this->pageview(); |
||
47 | |||
48 | // Check current and previous urls. |
||
49 | $root = $request->root(); |
||
50 | $from = ltrim(str_replace($root, '', $request->headers->get('referer')), '/'); |
||
51 | $to = ltrim(str_replace($root, '', $request->getPathInfo()), '/'); |
||
52 | // Don't track refreshes. |
||
53 | if ($from == $to) { |
||
54 | return; |
||
55 | } |
||
56 | |||
57 | // Because the visitor is viewing a new page, trigger engagement. |
||
58 | // This will only be incremented once during the whole experiment. |
||
59 | $this->interact(); |
||
60 | |||
61 | $goals = $this->getGoals(); |
||
62 | |||
63 | // Detect goal completion based on the current url. |
||
64 | if (in_array($to, $goals) or in_array('/'.$to, $goals)) { |
||
65 | $this->complete($to); |
||
66 | } |
||
67 | |||
68 | // Detect goal completion based on the current route name. |
||
69 | if ($route = Route::currentRouteName() and in_array($route, $goals)) { |
||
70 | $this->complete($route); |
||
71 | } |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * Get or compare the current experiment for this session. |
||
76 | * |
||
77 | * @param string $target |
||
78 | * @return bool|string |
||
79 | */ |
||
80 | public function experiment($target = null) |
||
81 | { |
||
82 | // Get the existing or new experiment. |
||
83 | try { |
||
84 | $experiment = $this->session->get('experiment') ?: $this->nextExperiment(); |
||
85 | |||
86 | if (is_null($target)) { |
||
87 | return $experiment; |
||
88 | } |
||
89 | |||
90 | return $experiment == $target; |
||
91 | } catch (\Exception $e) { |
||
92 | \Log::error('Experiments on front may be deleted'); |
||
93 | |||
94 | return false; |
||
95 | } |
||
96 | } |
||
97 | |||
98 | /** |
||
99 | * Increment the pageviews for the current experiment. |
||
100 | * |
||
101 | * @return void |
||
102 | */ |
||
103 | View Code Duplication | public function pageview() |
|
0 ignored issues
–
show
|
|||
104 | { |
||
105 | // Only interact once per experiment. #reallyli update |
||
106 | if (config('ab.unique_pageview')) { |
||
107 | if ($this->session->get('pageview')) { |
||
108 | return; |
||
109 | } |
||
110 | } |
||
111 | |||
112 | $experiment = Experiment::firstOrNew(['name' => $this->experiment()]); |
||
113 | $experiment->visitors++; |
||
0 ignored issues
–
show
The property
visitors does not exist on object<Reallyli\AB\Models\Experiment> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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. ![]() |
|||
114 | $experiment->save(); |
||
115 | |||
116 | // Mark current experiment as interacted. |
||
117 | $this->session->set('pageview', 1); |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Increment the engagement for the current experiment. |
||
122 | * |
||
123 | * @return void |
||
124 | */ |
||
125 | View Code Duplication | public function interact() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
126 | { |
||
127 | // Only interact once per experiment. |
||
128 | if ($this->session->get('interacted')) { |
||
129 | return; |
||
130 | } |
||
131 | |||
132 | $experiment = Experiment::firstOrNew(['name' => $this->experiment()]); |
||
133 | $experiment->engagement++; |
||
0 ignored issues
–
show
The property
engagement does not exist on object<Reallyli\AB\Models\Experiment> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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. ![]() |
|||
134 | $experiment->save(); |
||
135 | |||
136 | // Mark current experiment as interacted. |
||
137 | $this->session->set('interacted', 1); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Mark a goal as completed for the current experiment. |
||
142 | * |
||
143 | * @return void |
||
144 | */ |
||
145 | public function complete($name) |
||
146 | { |
||
147 | // Only complete once per experiment. |
||
148 | if ($this->session->get("completed_$name")) { |
||
149 | return; |
||
150 | } |
||
151 | |||
152 | $goal = Goal::firstOrCreate(['name' => $name, 'experiment' => $this->experiment()]); |
||
153 | Goal::where('name', $name)->where('experiment', $this->experiment())->update(['count' => ($goal->count + 1)]); |
||
0 ignored issues
–
show
The property
count does not exist on object<Reallyli\AB\Models\Goal> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?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. ![]() |
|||
154 | |||
155 | // Mark current experiment as completed. |
||
156 | $this->session->set("completed_$name", 1); |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Set the current experiment for this session manually. |
||
161 | * |
||
162 | * @param string $experiment |
||
163 | */ |
||
164 | public function setExperiment($experiment) |
||
165 | { |
||
166 | if ($this->session->get('experiment') != $experiment) { |
||
167 | $this->session->set('experiment', $experiment); |
||
168 | |||
169 | // Increase pageviews for new experiment. |
||
170 | $this->nextExperiment($experiment); |
||
171 | } |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Get all experiments. |
||
176 | * |
||
177 | * @return array |
||
178 | */ |
||
179 | public function getExperiments() |
||
180 | { |
||
181 | return Config::get('ab', [])['experiments']; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Get all goals. |
||
186 | * |
||
187 | * @return array |
||
188 | */ |
||
189 | public function getGoals() |
||
190 | { |
||
191 | return Config::get('ab', [])['goals']; |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Get the session instance. |
||
196 | * |
||
197 | * @return SessionInterface |
||
198 | */ |
||
199 | public function getSession() |
||
200 | { |
||
201 | return $this->session; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Set the session instance. |
||
206 | * |
||
207 | * @param $session SessionInterface |
||
208 | */ |
||
209 | public function setSession(SessionInterface $session) |
||
210 | { |
||
211 | $this->session = $session; |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * If an experiment has initialized get his string. |
||
216 | * |
||
217 | * @return string |
||
218 | */ |
||
219 | public function currentExperiment() |
||
220 | { |
||
221 | // Verify that the experiments are in the database. |
||
222 | $this->checkExperiments(); |
||
223 | if ($this->session->get('experiment') != '') { |
||
224 | $experiment = $this->session->get('experiment'); |
||
225 | } else { |
||
226 | $experiment = Experiment::active()->orderBy('updated_at', 'asc')->firstOrFail(); |
||
0 ignored issues
–
show
The method
active() does not exist on Reallyli\AB\Models\Experiment . Did you maybe mean scopeActive() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
227 | $experiment = $experiment->name; |
||
228 | } |
||
229 | |||
230 | return $experiment; |
||
231 | } |
||
232 | |||
233 | /** |
||
234 | * Prepare an experiment for this session. |
||
235 | * |
||
236 | * @return string |
||
237 | */ |
||
238 | protected function nextExperiment($experiment = null) |
||
239 | { |
||
240 | // Verify that the experiments are in the database. |
||
241 | $this->checkExperiments(); |
||
242 | |||
243 | if ($experiment) { |
||
244 | $experiment = Experiment::active()->findOrfail($experiment); |
||
0 ignored issues
–
show
The method
active() does not exist on Reallyli\AB\Models\Experiment . Did you maybe mean scopeActive() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
245 | } else { |
||
246 | $experiment = Experiment::active()->orderBy('visitors', 'asc')->firstOrFail(); |
||
0 ignored issues
–
show
The method
active() does not exist on Reallyli\AB\Models\Experiment . Did you maybe mean scopeActive() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
247 | } |
||
248 | |||
249 | $this->session->set('experiment', $experiment->name); |
||
250 | |||
251 | // Since there is an ongoing experiment, increase the pageviews. |
||
252 | // This will only be incremented once during the whole experiment. |
||
253 | $this->pageview(); |
||
254 | |||
255 | return $experiment->name; |
||
256 | } |
||
257 | |||
258 | /** |
||
259 | * Add experiments to the database. |
||
260 | * |
||
261 | * @return void |
||
262 | */ |
||
263 | protected function checkExperiments() |
||
264 | { |
||
265 | // Check if the database contains all experiments. |
||
266 | if (Experiment::active()->count() != count($this->getExperiments())) { |
||
0 ignored issues
–
show
The method
active() does not exist on Reallyli\AB\Models\Experiment . Did you maybe mean scopeActive() ?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. ![]() |
|||
267 | // Insert all experiments. |
||
268 | foreach ($this->getExperiments() as $experiment) { |
||
269 | Experiment::firstOrCreate(['name' => $experiment]); |
||
270 | } |
||
271 | } |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * Check if there are active experiments. |
||
276 | * |
||
277 | * @return string |
||
278 | */ |
||
279 | public function hasExperiments() |
||
280 | { |
||
281 | $count = Experiment::count(); |
||
282 | |||
283 | return $count > 1; |
||
284 | } |
||
285 | } |
||
286 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.