samsoncms /
newsletter
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 samsoncms\newsletter; |
||
| 4 | |||
| 5 | use samson\activerecord\email_distribution; |
||
| 6 | use samson\activerecord\email_letter; |
||
| 7 | use samson\activerecord\email_template; |
||
| 8 | use samson\core\SamsonLocale; |
||
| 9 | |||
| 10 | class Application extends \samsoncms\Application |
||
| 11 | { |
||
| 12 | /** @var string Module identifier */ |
||
| 13 | protected $id = 'newsletter'; |
||
| 14 | |||
| 15 | /** @var string Entity class name */ |
||
| 16 | protected $entity = '\samson\activerecord\email_distribution'; |
||
| 17 | |||
| 18 | /** Application name */ |
||
| 19 | public $name = 'Newsletter'; |
||
| 20 | |||
| 21 | /** Application description */ |
||
| 22 | public $description = 'Newsletter distribution management'; |
||
| 23 | |||
| 24 | /** @var string $icon Icon class */ |
||
| 25 | public $icon = 'envelope'; |
||
| 26 | |||
| 27 | public $hide = false; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * Prepare DB for application settings |
||
| 31 | * @return mixed |
||
| 32 | */ |
||
| 33 | public function prepare() |
||
| 34 | { |
||
| 35 | db()->execute( |
||
| 36 | " |
||
| 37 | CREATE TABLE IF NOT EXISTS `email_distribution` ( |
||
| 38 | `distribution_id` int(11) NOT NULL AUTO_INCREMENT, |
||
| 39 | `template_id` int(11) NOT NULL, |
||
| 40 | `status` int(11) DEFAULT '0', |
||
| 41 | `recipient_count` int(11) DEFAULT '0', |
||
| 42 | `bounce_count` int(11) DEFAULT '0', |
||
| 43 | `open_count` int(11) DEFAULT '0', |
||
| 44 | `click_count` int(11) DEFAULT '0', |
||
| 45 | `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
||
| 46 | `finished` datetime NOT NULL, |
||
| 47 | `active` int(11) NOT NULL DEFAULT '0', |
||
| 48 | PRIMARY KEY (`distribution_id`) |
||
| 49 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; |
||
| 50 | " |
||
| 51 | ); |
||
| 52 | |||
| 53 | db()->execute( |
||
| 54 | " |
||
| 55 | CREATE TABLE IF NOT EXISTS `email_letter` ( |
||
| 56 | `letter_id` int(11) NOT NULL AUTO_INCREMENT, |
||
| 57 | `distribution_id` int(11) NOT NULL, |
||
| 58 | `template_id` int(11) NOT NULL, |
||
| 59 | `recipient` varchar(50) NOT NULL, |
||
| 60 | `status` int(11) DEFAULT '0', |
||
| 61 | `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
||
| 62 | PRIMARY KEY (`letter_id`) |
||
| 63 | ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; |
||
| 64 | " |
||
| 65 | ); |
||
| 66 | |||
| 67 | db()->execute( |
||
| 68 | " |
||
| 69 | CREATE TABLE IF NOT EXISTS `email_template` ( |
||
| 70 | `template_id` int(11) NOT NULL AUTO_INCREMENT, |
||
| 71 | `content` text NOT NULL, |
||
| 72 | `locale` varchar(5) NOT NULL DEFAULT 'en', |
||
| 73 | `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
||
| 74 | PRIMARY KEY (`template_id`) |
||
| 75 | ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; |
||
| 76 | " |
||
| 77 | ); |
||
| 78 | |||
| 79 | return parent::prepare(); |
||
| 80 | } |
||
| 81 | |||
| 82 | /** |
||
| 83 | * Universal controller action. |
||
| 84 | * Entity collection rendering |
||
| 85 | */ |
||
| 86 | public function __template() |
||
| 87 | { |
||
| 88 | $description = t($this->description, true); |
||
| 89 | $name = t($this->description, true); |
||
| 90 | $letter = $this->createLetter('HEADER', 'MESSAGE'); |
||
| 91 | |||
| 92 | // Prepare view |
||
| 93 | $this->title($description) |
||
| 94 | ->view('form') |
||
| 95 | ->set('name', $name) |
||
| 96 | ->set('icon', $this->icon) |
||
| 97 | ->set('letter', $letter) |
||
| 98 | ->set('description', $description) |
||
| 99 | ; |
||
| 100 | } |
||
| 101 | |||
| 102 | /** |
||
| 103 | * Save number of email opens |
||
| 104 | * @param int $distribution_id Distribution identifier |
||
| 105 | */ |
||
| 106 | public function __openaction($distribution_id) |
||
| 107 | { |
||
| 108 | /** @var email_distribution $distribution */ |
||
| 109 | $distribution = null; |
||
| 110 | if ($this->query->entity('email_distribution')->where('distribution_id', $distribution_id)->first($distribution)) { |
||
| 111 | $distribution->open_count ++; |
||
|
0 ignored issues
–
show
|
|||
| 112 | $distribution->save(); |
||
| 113 | } |
||
| 114 | } |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Save number of email clicks |
||
| 118 | * @param int $distribution_id Distribution identifier |
||
| 119 | * @param string $params |
||
| 120 | */ |
||
| 121 | public function __clickaction($distribution_id, $params = '') |
||
| 122 | { |
||
| 123 | /** @var email_distribution $distribution */ |
||
| 124 | $distribution = null; |
||
| 125 | if ($this->query->entity('email_distribution')->where('distribution_id', $distribution_id)->first($distribution)) { |
||
| 126 | $distribution->click_count ++; |
||
|
0 ignored issues
–
show
Accessing
click_count on the interface samsonframework\orm\RecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
|
|||
| 127 | $distribution->save(); |
||
| 128 | |||
| 129 | $params = explode('-', $params); |
||
| 130 | $url = 'http://'.$_SERVER['HTTP_HOST'].'/'; |
||
| 131 | if (sizeof($params)) { |
||
| 132 | foreach ($params as $param) { |
||
| 133 | $url .= $param.'/'; |
||
| 134 | } |
||
| 135 | } |
||
| 136 | |||
| 137 | header('Location: '.$url);die; |
||
| 138 | } |
||
| 139 | } |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Show template content |
||
| 143 | * @param int $id Template identifier |
||
| 144 | * @return array |
||
| 145 | */ |
||
| 146 | public function __async_templates($id) |
||
| 147 | { |
||
| 148 | /** @var $this->entity $outfit */ |
||
| 149 | $template = null; |
||
| 150 | $response = array('status' => 0, 'popup' => ''); |
||
| 151 | if ($this->query->entity('email_template')->where('template_id', $id)->first($template)) { |
||
| 152 | $response['popup'] = $this->view('template/popup')->content($template->content)->output(); |
||
|
0 ignored issues
–
show
Accessing
content on the interface samsonframework\orm\RecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
Loading history...
The method
content does not exist on object<samsoncms\newsletter\Application>? Since you implemented __call, maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
Loading history...
|
|||
| 153 | $response['status'] = 1; |
||
| 154 | } |
||
| 155 | |||
| 156 | return $response; |
||
| 157 | } |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Create template content |
||
| 161 | * @param string $header Email Header |
||
| 162 | * @param string $message Email text |
||
| 163 | * @return string |
||
| 164 | */ |
||
| 165 | public function createLetter($header, $message) |
||
| 166 | { |
||
| 167 | return '<h1>'.$header.'</h1><br><div>'.$message.'</div>'; |
||
| 168 | } |
||
| 169 | |||
| 170 | /** |
||
| 171 | * @param int $preview Flag - send letters or no |
||
| 172 | * @return array |
||
| 173 | */ |
||
| 174 | public function __async_make($preview = 0) |
||
| 175 | { |
||
| 176 | $recipients = explode(',', $_POST['recipients']); |
||
| 177 | |||
| 178 | $letters = array(); |
||
| 179 | foreach (SamsonLocale::$locales as $locale) { |
||
| 180 | if (isset($_POST['header-'.$locale]) && isset($_POST['message-'.$locale])) { |
||
| 181 | $letters[$locale] = $this->createLetter($_POST['header-'.$locale], $_POST['message-'.$locale]); |
||
| 182 | } |
||
| 183 | } |
||
| 184 | |||
| 185 | if (!$preview) { |
||
| 186 | $templates = array(); |
||
| 187 | |||
| 188 | foreach ($letters as $locale => $letter) { |
||
| 189 | $template = new email_template(); |
||
| 190 | $template->content = $letter; |
||
| 191 | $template->locale = $locale; |
||
| 192 | $template->save(); |
||
| 193 | $templates[$locale] = $template; |
||
| 194 | } |
||
| 195 | |||
| 196 | $distribution = new email_distribution(); |
||
| 197 | $distribution->template_id = $templates[SamsonLocale::$defaultLocale]->template_id; |
||
| 198 | $distribution->recipient_count = sizeof($recipients); |
||
| 199 | $distribution->active = 1; |
||
| 200 | $distribution->save(); |
||
| 201 | // Send emails to all users from POST array |
||
| 202 | foreach ($recipients as $recipient) { |
||
| 203 | $emailLetter = new email_letter(); |
||
| 204 | $emailLetter->distribution_id = $distribution->distribution_id; |
||
| 205 | $emailLetter->recipient = trim($recipient); |
||
| 206 | $emailLetter->template_id = $templates[SamsonLocale::$defaultLocale]->template_id; |
||
| 207 | $emailLetter->save(); |
||
| 208 | } |
||
| 209 | } |
||
| 210 | |||
| 211 | return array('status' => 1, 'preview' => $letters[SamsonLocale::$defaultLocale]); |
||
| 212 | } |
||
| 213 | |||
| 214 | /** |
||
| 215 | * Send manual newsletters |
||
| 216 | */ |
||
| 217 | public function __manual() |
||
| 218 | { |
||
| 219 | foreach ($this->query->entity('email_letter')->where('status', 0)->exec() as $letter) { |
||
|
0 ignored issues
–
show
The expression
$this->query->entity('em...re('status', 0)->exec() of type boolean|array<integer,ob...k\orm\RecordInterface>> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
Loading history...
|
|||
| 220 | $template = $this->query->entity('email_template')->where('template_id', $letter->template_id)->first(); |
||
| 221 | $message = $template->content; |
||
| 222 | $img = '<img width="1" height="1" src="'.url()->build('newsletter/openaction/'.$letter->distribution_id).'">'; |
||
| 223 | $message .= $img; |
||
| 224 | $message = str_replace('clickaction/', 'clickaction/'.$letter->distribution_id.'/', $message); |
||
| 225 | $this->sendEmail($message, $letter->recipient); |
||
| 226 | $letter->status = 1; |
||
| 227 | $letter->save(); |
||
| 228 | } |
||
| 229 | } |
||
| 230 | |||
| 231 | /** |
||
| 232 | * @param string $letter Letter html content |
||
| 233 | * @param string $recipient email recipient |
||
| 234 | * @param string $from Sender email |
||
| 235 | * @param string $subject Email subject |
||
| 236 | * @param string $user Sender name |
||
| 237 | */ |
||
| 238 | public function sendEmail($letter, $recipient = '', $from = '', $subject = '', $user = '') |
||
| 239 | { |
||
| 240 | mail_send($recipient, $from, $letter, $subject, $user); |
||
| 241 | } |
||
| 242 | } |
||
| 243 |
If you access a property on an interface, you most likely code against a concrete implementation of the interface.
Available Fixes
Adding an additional type check:
Changing the type hint: