Issues (46)

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.

code/EmailDownloadPage.php (25 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
 * Page for Email Download
4
 * Easiest changed by extending this page
5
 * and using the hide_ancestor static to hide this page itself.
6
 */
7
8
class EmailDownloadPage extends Page
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
9
{
10
11
    /**
12
     * standard SS Variable
13
     */
14
    private static $description = "Allow the user to download a file through their e-mail.";
0 ignored issues
show
The property $description is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
15
16
    /**
17
     * standard SS Variable
18
     */
19
    private static $icon = "downloadtoemail/images/treeicons/EmailDownloadPage";
0 ignored issues
show
The property $icon is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
20
21
    /**
22
     * standard SS Variable
23
     */
24
    private static $db = array(
0 ignored issues
show
The property $db is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
25
        "LinkToThirdPartyDownload" => "Varchar(255)",
26
        "TitleOfFile" => "Varchar(50)",
27
        "EmailSubject" => "Varchar(200)",
28
        "NoAccessContent" => "Varchar(255)",
29
        "ValidityInDays" => "Float",
30
        "AllowReRequest" => "Boolean",
31
        "AllowReRequestLabel" => "Varchar(255)",
32
        "DeclineReRequestLabel" => "Varchar(255)",
33
        "ThankYouForRequesting" => "Varchar(255)",
34
        "ThankYouLink" => "Varchar(255)",
35
        "CopyOfAllEmailsToAdmin" => "Boolean"
36
    );
37
38
    /**
39
     * standard SS Variable
40
     */
41
    private static $has_one = array(
0 ignored issues
show
The property $has_one is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
42
        "DownloadFile" => "File"
43
    );
44
45
    /**
46
     * standard SS Variable
47
     */
48
    private static $has_many = array(
0 ignored issues
show
The property $has_many is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
49
        "EmailsSent" => "EmailDownloadPage_Registration"
50
    );
51
52
    /**
53
     * standard SS Variable
54
     */
55
    private static $defaults = array(
0 ignored issues
show
The property $defaults is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
56
        "NoAccessContent" => "Sorry, you do not have access to this file right now.  Please request access again.",
57
        "ThankYouForRequesting" => "Thank you for requesting this download, please check your e-mail for more information ...",
58
        "AllowReRequest" => true,
59
        "AllowReRequestLabel" => "Request another copy.",
60
        "DeclineReRequestLabel" => "You have already requested this file and you can not request it again."
61
    );
62
63
    /**
64
     *
65
     * @param boolean $includerelations a boolean value to indicate if the labels returned include relation fields
66
     *
67
     */
68
    public function fieldLabels($includerelations = true)
69
    {
70
        $labels = parent::fieldLabels($includerelations);
71
        $labels["TitleOfFile"] = _t("EmailDownloadPage.TITLEOFFILE", "Title of file");
72
        $labels["LinkToThirdPartyDownload"] = _t("EmailDownloadPage.LINKTOTHIRDPARTYDOWNLOAD", "Link to third-party download file / page");
73
        $labels["ValidityInDays"] = _t("EmailDownloadPage.VALIDITYINDAYS", "Validity in days (you can use 0.5 for 12 hours, etc...)");
74
        $labels["DownloadFile"] = $labels["DownloadFileID"] = _t("EmailDownloadPage.DOWNLOADFILE", "Select file to download");
75
        $labels["ThankYouForRequesting"] = _t("EmailDownloadPage.THANKYOUFORREQUESTING", "Thank you for requesting message");
76
        $labels["ThankYouLink"] = _t("EmailDownloadPage.THANKYOULINK", "Thank you link");
77
        $labels["EmailSubject"] = _t("EmailDownloadPage.EMAILSUBJECT", "E-mail Subject");
78
        $labels["AllowReRequest"] = _t("EmailDownloadPage.ALLOWREREQUEST", "Allow the user to make more than one request for the file (not strictly enforced) - change and reload to see more options");
79
        $labels["AllowReRequestLabel"] = _t("EmailDownloadPage.ALLOWREREQUESTLABEL", "Label for requesting another copy");
80
        $labels["DeclineReRequestLabel"] = _t("EmailDownloadPage.DECLINEREREQUESTLABEL", "Explanation of why the user can not request another copy");
81
        $labels["NoAccessContent"] = _t("EmailDownloadPage.NOACCESSCONTENT", "Content shown when the user does not have access");
82
        $labels["EmailsSent"] = _t("EmailDownloadPage.EMAILSSENT", "Downloads requested");
83
        $labels["CopyOfAllEmailsToAdmin"] = _t("EmailDownloadPage.COPYOFALLEMAILSTOADMIN", "Send a copy of all e-mails to the website administrator ");
84
        return $labels;
85
    }
86
87
    /**
88
     * standard SS Method
89
     */
90
    public function getCMSFields()
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
91
    {
92
        $fields = parent::getCMSFields();
93
        $labels = $this->fieldLabels(true);
94
        $fieldsToAdd = array(
95
            new TextField("TitleOfFile", $labels["TitleOfFile"]),
96
            $uploadField = new UploadField("DownloadFile", $labels["DownloadFile"])
97
        );
98
99
100
        if ($this->DownloadFileID) {
101
            $fieldsToAdd = array_merge($fieldsToAdd, array(
102
                new NumericField("ValidityInDays", $label["ValidityInDays"])
0 ignored issues
show
The variable $label does not exist. Did you mean $labels?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
103
            ));
104
        } else {
105
            $fieldsToAdd = array_merge($fieldsToAdd, array(
106
                $linkToThirdPartyDownloadField = new TextField("LinkToThirdPartyDownload", $labels["LinkToThirdPartyDownload"])
107
            ));
108
            $linkToThirdPartyDownloadField->setRightTitle(_t("EmailDownloadPage.LINKTOTHIRDPARTYDOWNLOAD_RIGHT_TITLE", "Set this to a third-party website link (e.g. dropbox) - e.g. http://www.mycooldownloadpage.com/mydownloadpage/"));
109
        }
110
        $fieldsToAdd = array_merge($fieldsToAdd, array(
111
            new CheckboxField("AllowReRequest", $labels["AllowReRequest"]),
112
            new TextField("EmailSubject", $labels["EmailSubject"]),
113
            new CheckboxField("CopyOfAllEmailsToAdmin", $labels["CopyOfAllEmailsToAdmin"]." (".Email::getAdminEmail().")"),
0 ignored issues
show
Deprecated Code introduced by
The method Email::getAdminEmail() has been deprecated with message: 4.0 Use the "Email.admin_email" config setting instead

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...
114
            new TextField("ThankYouForRequesting", $labels["ThankYouForRequesting"]),
115
            new TextField("ThankYouLink", $labels["ThankYouLink"])
116
        ));
117
        if ($this->AllowReRequest) {
118
            $fieldsToAdd = array_merge($fieldsToAdd, array(
119
                new TextField("AllowReRequestLabel", $labels["AllowReRequestLabel"]),
120
            ));
121
        } else {
122
            $fieldsToAdd = array_merge($fieldsToAdd, array(
123
                new TextField("DeclineReRequestLabel", $labels["DeclineReRequestLabel"]),
124
            ));
125
        }
126
        $fieldsToAdd = array_merge($fieldsToAdd, array(
127
            new TextField("NoAccessContent", $labels["NoAccessContent"]),
128
            $gridField = new GridField("EmailsSent", $labels["EmailsSent"], $this->EmailsSent(), GridFieldConfig_RelationEditor::create())
129
        ));
130
        $gridField->getConfig()->addComponent(new GridFieldExportButton());
131
        $fields->addFieldsToTab(
132
            "Root.DownloadToEmail",
133
            $fieldsToAdd
134
        );
135
        return $fields;
136
    }
137
}
138
139
class EmailDownloadPage_Controller extends Page_Controller
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
140
{
141
142
    /**
143
     * standard SS Variable
144
     */
145
    private static $allowed_actions = array(
0 ignored issues
show
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
146
        "DownloadForm",
147
        "dodownload",
148
        "thankyou",
149
        "requestrerequest",
150
        "noaccess"
151
    );
152
153
    /**
154
     * Template to be used for sending e-mail.
155
     * @var String
156
     */
157
    private static $email_template = "DownloadToEmailEmail";
0 ignored issues
show
The property $email_template is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
158
159
    /**
160
     * Show the download form?
161
     * @var Boolean
162
     */
163
    protected $showDownloadForm = true;
164
165
    /**
166
     * Message to user (e.g. you do not have access to this file)
167
     * @var String
168
     */
169
    protected $feedbackMessage = "";
170
171
    /**
172
     * Type of feedback (Good | Bad | Warning)
173
     * @var String
174
     */
175
    protected $feedbackMessageStyle = "";
176
177
178
    /**
179
     * Standard SS method
180
     */
181
    public function init()
182
    {
183
        parent::init();
184
        $this->showDownloadForm = $this->AlreadyRequestedSuccessfully() ? false : true;
185
    }
186
187
188
    /**
189
     *
190
     * @return Boolean
191
     */
192
    public function AlreadyRequestedSuccessfully()
193
    {
194
        return Session::get($this->sessionVarNameForSending()) ? true : false;
195
    }
196
197
    public function ReRequestLink()
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
198
    {
199
        return $this->Link("requestrerequest");
200
    }
201
202
    /**
203
     * feedback message for user
204
     * @return Varchar
0 ignored issues
show
Should the return type not be boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
205
     */
206
    public function ShowDownloadForm()
207
    {
208
        return $this->showDownloadForm;
209
    }
210
211
    /**
212
     * feedback message for user
213
     * @return Varchar
214
     */
215
    public function FeedbackMessage()
216
    {
217
        return DBField::create_field('Varchar', $this->feedbackMessage);
218
    }
219
220
    /**
221
     * feedback message for user
222
     * @return Varchar
223
     */
224
    public function FeedbackMessageStyle()
225
    {
226
        return DBField::create_field('Varchar', $this->feedbackMessageStyle);
227
    }
228
229
    /**
230
     * show the download form.
231
     *
232
     * @return Form
233
     */
234
    public function DownloadForm()
235
    {
236
        Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
237
        Requirements::javascript('downloadtoemail/javascript/DownloadToEmail.js');
238
        $form = new Form(
239
            $this,
240
            'DownloadForm',
241
            new FieldList($emailField = new EmailField('EmailDownloadPageEmail', _t("EmailDownloadPage.EMAIL", "enter your e-mail address"))),
242
            new FieldList(new FormAction('sendmail', _t("EmailDownloadPage.REQUEST_ACCESS", "request access"))),
243
            RequiredFields::create(array("EmailDownloadPageEmail"))
244
        );
245
        return $form;
246
    }
247
248
    /**
249
     * Sent the e-mail.
250
     *
251
     * @param Array $data
252
     * @param Form $form
253
     */
254
    public function sendmail($data, $form)
255
    {
256
        $email = Convert::raw2sql($data["EmailDownloadPageEmail"]);
257
        $obj = EmailDownloadPage_Registration::get()
258
            ->filter(array("Email" => $email, "DownloadFileID" => $this->DownloadFileID))
259
            ->first();
260
        if (!$obj) {
261
            $obj = new EmailDownloadPage_Registration();
262
            $obj->Email = $email;
0 ignored issues
show
The property Email does not exist on object<EmailDownloadPage_Registration>. 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...
263
            $obj->DownloadFileID = $this->DownloadFileID;
0 ignored issues
show
The property DownloadFileID does not exist on object<EmailDownloadPage_Registration>. 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...
264
        } else {
265
            $obj->Used = false;
266
        }
267
        $obj->EmailDownloadPageID = $this->ID;
268
        $obj->write();
269
        $adminEmail = Email::getAdminEmail();
0 ignored issues
show
Deprecated Code introduced by
The method Email::getAdminEmail() has been deprecated with message: 4.0 Use the "Email.admin_email" config setting instead

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...
270
        if (!$adminEmail) {
271
            user_error("You need to set an admin email in order to use this page", E_USER_NOTICE);
272
        }
273
        $email = new Email($adminEmail, $data["EmailDownloadPageEmail"], $this->EmailSubject);
274
        if ($this->CopyOfAllEmailsToAdmin) {
275
            $email->setBcc($adminEmail);
276
        }
277
        $email->setTemplate($this->config()->get("email_template"));
278
        // You can call this multiple times or bundle everything into an array, including DataSetObjects
279
        $email->populateTemplate(
280
            new ArrayData(
281
                array(
282
                    "EmailSubject" => DBField::create_field('Varchar', $this->EmailSubject),
283
                    "TitleOfFile" => DBField::create_field('Varchar', $this->TitleOfFile),
284
                    "ValidUntil" => date('Y-M-d', strtotime("+".($this->ValidityInDays * 86400)." seconds")),
285
                    "HasLink" => $this->LinkToThirdPartyDownload ? true : false,
286
                    "HasFile" => $this->DownloadFileID ? true : false,
287
                    "LinkToThirdPartyDownload" => $this->LinkToThirdPartyDownload,
288
                    "File" => $this->DownloadFile(),
289
                    "DownloadLink" => Director::absoluteURL($this->Link("dodownload/".$obj->ID."/".$obj->Code.'/')),
290
                    "FileLocation" => Director::absoluteURL($this->DownloadFile()->Link())
291
                )
292
            )
293
        );
294
        $outcome = $email->send();
295
        Session::set($this->sessionVarNameForSending(), $outcome);
0 ignored issues
show
$outcome is of type array<integer,string,{"0...g","4":"string"}>|false, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
296
        $this->redirect($this->Link("thankyou/".($outcome ? "success" : "fail")."/"));
297
        return array();
298
    }
299
300
    /**
301
     * Do the download itself.
302
     * URL should be formatted as
303
     * /thankyou/outcome/
304
     *
305
     * @param HTTPRequest
306
     */
307
    public function thankyou($request)
308
    {
309
        $outcome = $request->param("ID");
310
        if ($outcome == "success") {
311
            $this->feedbackMessage = $this->ThankYouForRequesting;
312
            $this->feedbackMessageStyle = "good";
313
            $this->showDownloadForm = false;
314
            $this->DeclineReRequestLabel = "";
315
        } else {
316
            $this->feedbackMessage = "E-mail could not be sent.";
317
            $this->feedbackMessageStyle = "bad";
318
            $this->DeclineReRequestLabel = "";
319
        }
320
        return array();
321
    }
322
323
    /**
324
     * Do the download itself.
325
     * URL should be formatted as
326
     * /dodownload/$ID/$CodeForObject/
327
     *
328
     * @param HTTPRequest
329
     */
330
    public function dodownload($request)
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
331
    {
332
        Session::set($this->sessionVarNameForSending(), true);
0 ignored issues
show
true is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
333
        $id = intval($request->param("ID"));
334
        $code = Convert::raw2sql($request->param("OtherID"));
335
        if ($id && $code) {
336
            $obj = EmailDownloadPage_Registration::get()->filter(
337
                array(
338
                    "ID" => $id,
339
                    "Code" => $code,
340
                    "Used" => 0
341
                )
342
            )->First();
343
            if ($obj) {
344
                if ($this->ValidityInDays) {
345
                    $tsNow = strtotime("NOW");
346
                    $validUntilTs = strtotime($obj->Created." +".(86400 * $this->ValidityInDays)." seconds");
347
                    if ($tsNow > $validUntilTs) {
348
                        return $this->redirect($this->Link("noaccess"));
349
                    }
350
                }
351
                $obj->DownloadTimes++;
352
                $obj->Used = true;
353
                $obj->write();
354
                return $this->sendFile($obj->DownloadFile());
355
            }
356
        }
357
        $this->redirect($this->Link("noaccess"));
358
    }
359
360
    /**
361
     *
362
     * What happens when the person does not have access.
363
     */
364
    public function noaccess()
365
    {
366
        $this->feedbackMessage = $this->NoAccessContent;
367
        $this->feedbackMessageStyle = "warning";
368
        return array();
369
    }
370
371
    /**
372
     *
373
     * What happens when the person does not have access.
374
     */
375
    public function requestrerequest()
376
    {
377
        if ($this->AllowReRequest) {
378
            Session::set($this->sessionVarNameForSending(), false);
0 ignored issues
show
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
379
            Session::clear($this->sessionVarNameForSending());
380
            $this->redirect($this->Link());
381
        } else {
382
            $this->redirect($this->Link("noaccess"));
383
        }
384
        return array();
385
    }
386
387
    // We calculate the timelimit based on the filesize. Set to 0 to give unlimited timelimit.
388
    // The calculation is: give enough time for the user with x kB/s connection to donwload the entire file.
389
    // E.g. The default 50kB/s equates to 348 minutes per 1GB file.
390
    private static $min_download_bandwidth = 50; // [in kilobytes per second]
0 ignored issues
show
The property $min_download_bandwidth is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
391
392
    /**
393
     *
394
     * COPIED CODE!!!!!
395
     *
396
     * This is copied from here:
397
     * https://github.com/silverstripe-labs/silverstripe-secureassets/blob/master/code/SecureFileController.php
398
     *
399
     * @param File $file
400
     */
401
    protected function sendFile($file)
402
    {
403
        $path = $file->getFullPath();
404
        if (SapphireTest::is_running_test()) {
405
            return file_get_contents($path);
406
        }
407
        header('Content-Description: File Transfer');
408
        // Quotes needed to retain spaces (http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download)
409
        header('Content-Disposition: inline; filename="' . basename($path) . '"');
410
        header('Content-Length: ' . $file->getAbsoluteSize());
411
        header('Content-Type: ' . HTTP::get_mime_type($file->getRelativePath()));
412
        header('Content-Transfer-Encoding: binary');
413
        // Fixes IE6,7,8 file downloads over HTTPS bug (http://support.microsoft.com/kb/812935)
414
        header('Pragma: ');
415
        if ($this->config()->min_download_bandwidth) {
416
            // Allow the download to last long enough to allow full download with min_download_bandwidth connection.
417
            increase_time_limit_to((int)(filesize($path)/($this->config()->min_download_bandwidth*1024)));
418
        } else {
419
            // Remove the timelimit.
420
            increase_time_limit_to(0);
421
        }
422
        // Clear PHP buffer, otherwise the script will try to allocate memory for entire file.
423
        while (ob_get_level() > 0) {
424
            ob_end_flush();
425
        }
426
        // Prevent blocking of the session file by PHP. Without this the user can't visit another page of the same
427
        // website during download (see http://konrness.com/php5/how-to-prevent-blocking-php-requests/)
428
        session_write_close();
429
        readfile($path);
430
        die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method sendFile() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
431
    }
432
433
    /**
434
     *
435
     * @return String
436
     */
437
    protected function sessionVarNameForSending()
438
    {
439
        return "EmailDownloadPage_Controller_".$this->ID."_Sent";
440
    }
441
}
442