function resendActivationMessage($subject = null, $view = null, $fields = array(), $options = array()) { if (!isset($subject)) { $subject = Q_Config::get('Users', 'transactional', 'resend', 'subject', Q_Config::get('Users', 'transactional', 'activation', 'subject', 'Did you forget your passphrase?')); } if (!isset($view)) { $view = Q_Config::get('Users', 'transactional', 'resend', 'body', Q_Config::get('Users', 'transactional', 'activation', 'body', 'Users/email/activation.php')); } if (!isset($options['html'])) { $options['html'] = true; } $user = $this->get('user', null); if (!$user) { $user = new Users_User(); $user->id = $this->userId; if (!$user->retrieve()) { throw new Q_Exception_NotVerified(array('type' => 'email address'), 'emailAddress'); } } $minutes = Q_Config::get('Users', 'activation', 'expires', 60 * 24 * 7); $this->activationCode = strtolower(Q_Utils::unique(7)); $this->activationCodeExpires = new Db_Expression("CURRENT_TIMESTAMP + INTERVAL {$minutes} MINUTE"); $this->authCode = md5(microtime() + mt_rand()); $link = 'Users/activate?p=1&code=' . urlencode($this->activationCode) . ' emailAddress=' . urlencode($this->address); /** * @event Users/resend {before} * @param {string} user * @param {string} email */ Q::event('Users/resend', compact('user', 'email', 'link'), 'before'); $this->save(); $email = $this; $fields2 = array_merge($fields, array('user' => $user, 'email' => $this, 'app' => Q_Config::expect('Q', 'app'), 'baseUrl' => Q_Request::baseUrl(), 'link' => $link)); $this->sendMessage($subject, $view, $fields2, $options); // may throw exception if badly configured /** * @event Users/resend {after} * @param {string} user * @param {string} email */ Q::event('Users/resend', compact('user', 'email'), 'after'); }
/** * Saves an image, usually sent by the client, in one or more sizes. * @method save * @static * @param {array} $params * @param {string} [$params.data] the image data * @param {string} [$params.path="uploads"] parent path under web dir (see subpath) * @param {string} [$params.subpath=""] subpath that should follow the path, to save the image under * @param {string} [$params.merge=""] path under web dir for an optional image to use as a background * @param {string} [$params.crop] array with keys "x", "y", "w", "h" to crop the original image * @param {string} [$params.save=array("x" => "")] array of $size => $basename pairs * where the size is of the format "WxH", and either W or H can be empty. * @param {string} [$params.skipAccess=false] if true, skips the check for authorization to write files there * @return {array} an array of ($size => $fullImagePath) pairs */ static function save($params) { if (empty($params['data'])) { throw new Q_Exception("Image data is missing"); } $imageData = $params['data']; $image = imagecreatefromstring($imageData); if (!$image) { throw new Q_Exception("Image type not supported"); } // image dimensions $maxW = Q_Config::get('Q', 'uploads', 'limits', 'image', 'width', 5000); $maxH = Q_Config::get('Q', 'uploads', 'limits', 'image', 'height', 5000); $iw = imagesx($image); $ih = imagesy($image); if ($maxW and $iw > $maxW) { throw new Q_Exception("Uploaded image width exceeds {$maxW}"); } if ($maxH and $iw > $maxH) { throw new Q_Exception("Uploaded image width exceeds {$maxH}"); } // check whether we can write to this path, and create dirs if needed $path = isset($params['path']) ? $params['path'] : 'uploads'; $subpath = isset($params['subpath']) ? $params['subpath'] : ''; $realPath = Q::realPath(APP_WEB_DIR . DS . $path); if ($realPath === false) { throw new Q_Exception_MissingFile(array('filename' => APP_WEB_DIR . DS . $path)); } $writePath = $realPath . ($subpath ? DS . $subpath : ''); $lastChar = substr($writePath, -1); if ($lastChar !== DS and $lastChar !== '/') { $writePath .= DS; } $throwIfNotWritable = empty($params['skipAccess']) ? true : null; Q_Utils::canWriteToPath($writePath, $throwIfNotWritable, true); // check if exif is available if (self::isJPEG($imageData)) { $exif = exif_read_data("data://image/jpeg;base64," . base64_encode($imageData)); // rotate original image if necessary (hopefully it's not too large). if (!empty($exif['Orientation'])) { switch ($exif['Orientation']) { case 3: $image = imagerotate($image, 180, 0); break; case 6: $image = imagerotate($image, -90, 0); break; case 8: $image = imagerotate($image, 90, 0); break; } } } $crop = isset($params['crop']) ? $params['crop'] : array(); $save = !empty($params['save']) ? $params['save'] : array('x' => ''); // crop parameters - size of source image $isw = isset($crop['w']) ? $crop['w'] : $iw; $ish = isset($crop['h']) ? $crop['h'] : $ih; $isx = isset($crop['x']) ? $crop['x'] : 0; $isy = isset($crop['y']) ? $crop['y'] : 0; // process requested thumbs $data = array(); $merge = null; $m = isset($params['merge']) ? $params['merge'] : null; if (isset($m) && strtolower(substr($m, -4)) === '.png') { $mergePath = Q::realPath(APP_WEB_DIR . DS . implode(DS, explode('/', $m))); if ($mergePath) { $merge = imagecreatefrompng($mergePath); $mw = imagesx($merge); $mh = imagesy($merge); } } foreach ($save as $size => $name) { if (empty($name)) { // generate a filename do { $name = Q_Utils::unique(8) . '.png'; } while (file_exists($writePath . $name)); } if (strrpos($name, '.') === false) { $name .= '.png'; } list($n, $ext) = explode('.', $name); $sw = $isw; $sh = $ish; $sx = $isx; $sy = $isy; // determine destination image size if (!empty($size)) { $sa = explode('x', $size); if (count($sa) > 1) { if ($sa[0] === '') { if ($sa[1] === '') { $dw = $sw; $dh = $sh; } else { $dh = intval($sa[1]); $dw = $sw * $dh / $sh; } } else { $dw = intval($sa[0]); if ($sa[1] === '') { $dh = $sh * $dw / $sw; } else { $dh = intval($sa[1]); } } } else { $dw = $dh = intval($sa[0]); } // calculate the origin point of source image // we have a cropped image of dimension $sw, $sh and need to make new with dimension $dw, $dh if ($dw / $sw < $dh / $sh) { // source is wider then destination $new = $dw / $dh * $sh; $sx += round(($sw - $new) / 2); $sw = round($new); } else { // source is narrower then destination $new = $dh / $dw * $sw; $sy += round(($sh - $new) / 2); $sh = round($new); } } else { $size = ''; $dw = $sw; $dh = $sh; } // create destination image $maxWidth = Q_Config::get('Q', 'images', 'maxWidth', null); $maxHeight = Q_Config::get('Q', 'images', 'maxHeight', null); if (isset($maxWidth) and $dw > $maxWidth) { throw new Q_Exception("Image width exceeds maximum width of {$dw}"); } if (isset($maxHeight) and $dh > $maxHeight) { throw new Q_Exception("Image height exceeds maximum height of {$dh}"); } $thumb = imagecreatetruecolor($dw, $dh); $res = $sw === $dw && $sh === $dh ? imagecopy($thumb, $image, 0, 0, $sx, $sy, $sw, $sh) : imagecopyresampled($thumb, $image, 0, 0, $sx, $sy, $dw, $dh, $sw, $sh); if (!$res) { throw new Q_Exception("Failed to save image file of type '{$ext}'"); } if ($merge) { $mergethumb = imagecreatetruecolor($mw, $mh); imagesavealpha($mergethumb, false); imagealphablending($mergethumb, false); if (imagecopyresized($mergethumb, $merge, 0, 0, 0, 0, $dw, $dh, $mw, $mh)) { imagecopy($thumb, $mergethumb, 0, 0, 0, 0, $dw, $dh); } } switch ($ext) { case 'jpeg': case 'jpeg': $func = 'imagejpeg'; break; case 'gif': $func = 'imagegif'; break; case 'png': default: $func = 'imagepng'; break; } if ($res = call_user_func($func, $thumb, $writePath . $name)) { $data[$size] = $subpath ? "{$path}/{$subpath}/{$name}" : "{$path}/{$name}"; } } $data[''] = $subpath ? "{$path}/{$subpath}" : "{$path}"; /** * @event Q/image/save {after} * @param {string} user * @param {string} path * @param {string} subpath * @param {string} writePath * @param {string} data */ Q::event('Q/image/save', compact('path', 'subpath', 'writePath', 'data', 'save', 'crop'), 'after'); return $data; }
/** * Starts the process of adding a mobile to a saved user object. * Also modifies and saves this user object back to the database. * @method addMobile * @param {string} $mobileNumber * The mobile number to add. * @param {string} [$activationMessageView=null] * The view to use for the body of the activation message to send. * @param {array} [$fields=array()] * An array of additional fields to pass to the mobile view. * @param {array} $options=array() * Array of options. Can include:<br/> * "delay" => A delay, in milliseconds, to wait until sending email. Only works if Node server is listening. * @return {boolean} * Returns true on success. * Returns false if this mobile number is already verified for this user. * @throws {Q_Exception_WrongValue} * If the mobile number is in an invalid format, this is thrown. * @throws {Users_Exception_AlreadyVerified} * If the mobile number already exists and has been verified for * another user, then this exception is thrown. */ function addMobile($mobileNumber, $activationMessageView = null, $fields = array(), $options = array()) { if (!Q_Valid::phone($mobileNumber, $normalized)) { throw new Q_Exception_WrongValue(array('field' => 'Mobile phone', 'range' => 'a valid number'), 'mobileNumber'); } $mobile = new Users_Mobile(); $mobile->number = $normalized; if ($mobile->retrieve('*', array('ignoreCache' => true)) and $mobile->state !== 'unverified') { if ($mobile->userId === $this->id) { $mobile->set('user', $this); return $mobile; } // Otherwise, say it's verified for another user, // even if it unsubscribed or was suspended. throw new Users_Exception_AlreadyVerified(array('key' => 'mobile number', 'userId' => $mobile->userId), 'mobileNumber'); } $user = $this; // If we are here, then the mobile record either // doesn't exist, or hasn't been verified yet. // In either event, update the record in the database, // and re-send the mobile. $minutes = Q_Config::get('Users', 'activation', 'expires', 60 * 24 * 7); $mobile->state = 'unverified'; $mobile->userId = $this->id; $mobile->activationCode = strtolower(Q_Utils::unique(7)); $mobile->activationCodeExpires = new Db_Expression("CURRENT_TIMESTAMP + INTERVAL {$minutes} MINUTE"); $number = $mobile->number; if (substr($number, 0, 2) == '+1') { $number = substr($number, 2); } $mobile->authCode = md5(microtime() + mt_rand()); $link = 'Users/activate?code=' . urlencode($mobile->activationCode) . ' mobileNumber=' . urlencode($number); /** * @event Users/addIdentifier {before} * @param {string} user * @param {string} mobile */ Q::event('Users/addIdentifier', compact('user', 'mobile', 'link'), 'before'); $mobile->save(); $this->mobileNumberPending = $normalized; $this->save(); if (!isset($activationMessageView)) { $activationMessageView = Q_Config::get('Users', 'transactional', 'activation', 'sms', 'Users/sms/activation.php'); } $fields2 = array_merge($fields, array('user' => $this, 'mobile' => $mobile, 'app' => Q_Config::expect('Q', 'app'), 'baseUrl' => Q_Request::baseUrl(), 'link' => $link)); $mobile->sendMessage($activationMessageView, $fields2, $options); Q_Response::removeNotice('Users/mobile'); /** * @event Users/addIdentifier {after} * @param {string} user * @param {string} mobile */ Q::event('Users/addIdentifier', compact('user', 'mobile', 'link'), 'after'); }
function resendActivationMessage($view = null, $fields = array(), $options = array()) { if (!isset($view)) { $view = Q_Config::get('Users', 'transactional', 'resend', 'sms', Q_Config::get('Users', 'transactional', 'resend', 'sms', 'Users/sms/activation.php')); } $user = $this->get('user', null); if (!$user) { $user = new Users_User(); $user->id = $this->userId; if (!$user->retrieve()) { throw new Q_Exception_NotVerified(array('type' => 'mobile number'), 'mobileNumber'); } } $minutes = Q_Config::get('Users', 'activation', 'expires', 60 * 24 * 7); $this->activationCode = strtolower(Q_Utils::unique(5)); $this->activationCodeExpires = new Db_Expression("CURRENT_TIMESTAMP + INTERVAL {$minutes} MINUTE"); $this->authCode = md5(microtime() + mt_rand()); $number = $this->number; if (substr($number, 0, 2) == '+1') { $number = substr($number, 2); } $link = 'Users/activate?p=1&code=' . urlencode($this->activationCode) . ' mobileNumber=' . urlencode($number); /** * @event Users/resend {before} * @param {string} user * @param {string} mobile */ Q::event('Users/resend', compact('user', 'mobile', 'link'), 'before'); $this->save(); $fields2 = array_merge($fields, array('user' => $user, 'mobile' => $this, 'app' => Q_Config::expect('Q', 'app'), 'baseUrl' => Q_Request::baseUrl(), 'link' => $link)); $this->sendMessage($view, $fields2, $options); // may throw exception if badly configured /** * @event Users/resend {after} * @param {string} user * @param {string} mobile */ Q::event('Users/resend', compact('user', 'mobile'), 'after'); }