Example #1
0
 /**
  * Создание пользователя
  * @return int userId - код нового пользователя
  */
 public final function createUser(RegFormData $data)
 {
     $email = PsCheck::email($data->getUserMail());
     //Проверим, что пользователь с таким email ещё не заведён
     check_condition(!$this->hasMail($email), "Пользователь с почтой [{$email}] уже зарегистрирован");
     //Подготовим поля для вставки
     $params[self::FIELD_NAME] = $data->getUserName();
     $params[self::FIELD_SEX] = $data->getSex();
     $params[self::FIELD_EMAIL] = $email;
     $params[self::FIELD_PASSWD] = self::hashPassword($data->getPassword());
     $params[self::FIELD_B_ADMIN] = 0;
     $params[self::FIELD_B_CAN_LOGIN] = 1;
     $params[] = Query::assocParam(self::FIELD_DT_REG, 'UNIX_TIMESTAMP()', false);
     //Выполняем вставку
     $userId = $this->register($this->insert(Query::insert('users', $params)));
     //Сохраним данные пользователя в аудит
     UserAudit::inst()->afterRegistered($userId, array_filter_keys($this->getUserDataById($userId), self::$SKIP_AUDIT_ON_CREATE_FIELDS));
     //Возвращаем код пользователя
     return $userId;
 }
Example #2
0
 public function resolve(Request $request, Response $response)
 {
     $path = $this->srcPath . $request->uri('path') . '.url';
     // Check if target file is a proxy.
     if (!is_file($path)) {
         return;
     }
     $cacheTarget = parse_ini_file($path);
     $cacheTarget = @$cacheTarget['URL'];
     unset($path);
     if (!$cacheTarget) {
         Log::warning('Proxy file has not URL parameter.', array('requestUri' => $request->uri(), 'proxyFile' => $request->uri('path') . '.uri'));
         $response->status(502);
         // Bad Gateway
         return;
     }
     /*! Cache Header Notes
      *
      *  # Cache-Control
      *  [public | private] Cacheable when public, otherwise the client is responsible for caching.
      *  [no-cache( \w+)?]  When no fields are specified, the whole thing must revalidate everytime,
      *                     otherwise cache it except specified fields.
      *  [no-store] 				 Ignore caching and pipe into output.
      *  [max-age=\d+] 		 Seconds before this cache is meant to expire, this overrides Expires header.
      *  [s-maxage=\d+] 		 Overrides max-age and Expires header, behaves just like max-age.
      *                 	   (This is for CDN and we are using it.)
      *  [must-revalidate]  Tells those CDNs which are intended to serve stale contents to revalidate every time.
      *  [proxy-revalidate] Like the "s-" version of max-age, a "must-revalidate" override only for CDN.
      *  [no-transform]     Some CDNs will optimize images and other formats, this "opt-out" of it.
      *
      *  # Expires
      *  RFC timestamp for an absolute cache expiration, overridden by Cache-Control header.
      *
      *  # ETag
      *  Hash of anything, weak ETags is not supported at this moment.
      *
      *  # vary
      *  Too much fun inside and we are too serious about caching, ignore this.
      *
      *  # pragma
      *  This guy is too old to recognize.
      *  [no-cache] Only this is known nowadays and is already succeed by Cache-Control: no-cache.
      *
      */
     // note; Use "cache-meta://" scheme for header and cache meta info, for performance.
     // 1. Check if cache exists.
     $cache = (array) Cache::get("cache-meta://{$cacheTarget}");
     // Cache expiration, in seconds.
     // expires = ( s-maxage || max-age || Expires );
     if (@$cache['expires'] && time() > $cache['expires']) {
         Cache::delete("cache-meta://{$cacheTarget}");
         Cache::delete("cache://{$cacheTarget}");
         $cache = null;
     }
     // - If not exists, make normal request to remote server.
     // - If exists, make conditional request to remote server.
     //   - Revalidation, we can skip this request and serve the content if false.
     //     revalidates = ( Cache-Control:proxy-revalidate || Cache-Control:must-revalidate )
     if (!$cache || @$cache['revalidates']) {
         $_request = array('uri' => $cacheTarget);
         if ($cache) {
             // Last-Modified
             if (@$cache['headers']['Last-Modified']) {
                 $_request['headers']['If-Modified-Since'] = $cache['Last-Modified'];
             }
             // Entity-Tag
             if (@$cache['headers']['ETag'] && strpos($cache['headers']['ETag'], 'W\\') !== 0) {
                 $_request['headers']['If-None-Match'] = $cache['ETag'];
             }
         } else {
             $cache = array();
         }
         // Make the request
         $_response = new Response(array('autoOutput' => false));
         (new Request($_request))->send(null, $_response);
         unset($_request);
         // parse headers into cache settings.
         if (in_array($_response->status(), array(200, 304))) {
             $res = preg_split('/\\s*,\\s*/', util::unwrapAssoc($_response->header('Cache-Control')));
             $res = array_reduce($res, function ($res, $value) {
                 // todo; Take care of no-cache with field name.
                 if (strpos($value, '=') > 0) {
                     $value = explode('=', $value);
                     $res[$value[0]] = $value[1];
                 } else {
                     $res[$value] = true;
                 }
                 return $res;
             }, array());
             // private, no-store, no-cache
             if (@$res['private'] || @$res['no-store'] || @$res['no-cache']) {
                 // note; in case the upstream server change this to uncacheable
                 Cache::delete("cache-meta://{$cacheTarget}");
                 Cache::delete("cache://{$cacheTarget}");
                 $_response->clearBody();
             }
             if ($_response->status() == 200 && $_response->body()) {
                 $cache['contents'] = $_response->body();
             }
             // expires = ( s-maxage || max-age || Expires );
             if (@$res['s-maxage']) {
                 $cache['expires'] = time() + $res['s-maxage'];
             } elseif (@$res['max-age']) {
                 $cache['expires'] = time() + $res['max-age'];
             } else {
                 $res = util::unwrapAssoc($_response->header('Expires'));
                 if ($res) {
                     $cache['expires'] = strtotime($res);
                 }
             }
             // revalidates = ( Cache-Control:proxy-revalidate || Cache-Control:must-revalidate )
             if (@$res['proxy-revalidate'] || @$res['must-revalidate']) {
                 $cache['revalidates'] = true;
             }
             unset($res);
         }
         $cache['headers'] = array_map('core\\Utility::unwrapAssoc', $_response->header());
         // PHP does not support chunked, skip this one.
         unset($cache['headers']['Transfer-Encoding']);
         // note; If cache is to be ignored, the $cacheTarget variable will be already unset().
         if (isset($cacheTarget)) {
             if (@$cache['contents']) {
                 Cache::set("cache://{$cacheTarget}", $cache['contents']);
             }
             Cache::set("cache-meta://{$cacheTarget}", array_filter_keys($cache, isNot('contents')));
         }
         unset($_response);
     }
     // note; Send cache headers regardless of the request condition.
     if (@$cache['headers']) {
         $response->clearHeaders();
         foreach ($cache['headers'] as $name => $value) {
             $response->header($name, $value, true);
         }
         unset($name, $value);
     }
     // note; Handles conditional request
     $ch = array_map('core\\Utility::unwrapAssoc', (array) @$cache['headers']);
     $mtime = @$ch['Last-Modified'] ? strtotime($ch['Last-Modified']) : false;
     // Request headr: If-Modified-Since
     if (@$ch['Last-Modified'] && $mtime) {
         if (strtotime($request->header('If-Modified-Since')) >= $mtime) {
             return $response->status(304);
         }
     }
     // Request header: If-Range
     if ($request->header('If-Range')) {
         // Entity tag
         if (strpos(substr($request->header('If-Range'), 0, 2), '"') !== false && @$ch['ETag']) {
             if ($this->compareETags(@$ch['ETag'], $request->header('If-Range'))) {
                 return $this->response()->status(304);
             }
         } elseif (strtotime($request->header('If-Range')) === $mtime) {
             return $this->response()->status(304);
         }
     }
     unset($mtime);
     // Request header: If-None-Match
     if (!$request->header('If-Modified-Since') && $request->header('If-None-Match')) {
         // Exists but not GET or HEAD
         switch ($request->method()) {
             case 'get':
             case 'head':
                 break;
             default:
                 return $this->response()->status(412);
         }
         /*! Note by Vicary @ 24 Jan, 2013
          *  If-None-Match means 304 when target resources exists.
          */
         if ($request->header('If-None-Match') === '*' && @$ch['ETag']) {
             return $this->response()->status(304);
         }
         if ($this->compareETags(@$ch['ETag'], preg_split('/\\s*,\\s*/', $request->header('If-None-Match')))) {
             return $this->response()->status(304);
         }
     }
     // Request header: If-Match
     if (!$request->header('If-Modified-Since') && $request->header('If-Match')) {
         // Exists but not GET or HEAD
         switch ($request->method()) {
             case 'get':
             case 'head':
                 break;
             default:
                 return $this->response()->status(412);
         }
         if ($request->header('If-Match') === '*' && !@$ch['ETag']) {
             return $this->response()->status(412);
         }
         preg_match_all('/(?:^\\*$|(:?"([^\\*"]+)")(?:\\s*,\\s*(:?"([^\\*"]+)")))$/', $request->header('If-Match'), $eTags);
         // 412 Precondition Failed when nothing matches.
         if (@$eTags[1] && !in_array($eTag, (array) $eTags[1])) {
             return $this->response()->status(412);
         }
     }
     if ($cacheTarget && empty($cache['contents'])) {
         $cache['contents'] = Cache::get("cache://{$cacheTarget}");
     }
     // Output the cahce content
     $response->send($cache['contents'], 200);
 }
Example #3
0
 /**
  * Perform cURL requests and throw appropriate exceptions.
  *
  * An array of parameters used in a curl_setopt_array,
  * multiple calls can be passed in.
  *
  * This function make use of curl_multi no matter it is
  * single request or not.
  *
  * Callbacks are used to handle results inside the array.
  *
  * $option['callbacks'] = array(
  *   'progress' => [Function]
  * , 'success' => [Function]
  * , 'failure' => [Function]
  * , 'always'  => [Function]
  * );
  *
  * @return void
  */
 public static function curlRequest($options)
 {
     $options = Utility::wrapAssoc(array_values((array) $options));
     $multiHandle = curl_multi_init();
     // Initialize cUrl options
     array_walk($options, function (&$option) {
         // 1. Request headers
         $option['response'] = array('headers' => '');
         $option[CURLOPT_HEADERFUNCTION] = function ($curl, $data) use(&$option) {
             $option['response']['headers'] .= $data;
             return strlen($data);
         };
         // 2. Progress function
         $progressCallback =& $option['callbacks']['progress'];
         if ($progressCallback) {
             $option[CURLOPT_NOPROGRESS] = false;
             $option[CURLOPT_PROGRESSFUNCTION] = function () use(&$progressCallback) {
                 if (func_num_args() == 4) {
                     list($dSize, $dLen, $uSize, $uLen) = func_get_args();
                 } else {
                     list($req, $dSize, $dLen, $uSize, $uLen) = func_get_args();
                 }
                 if ($dSize || $dLen) {
                     static $_dLen = 0;
                     if ($_dLen != $dLen) {
                         $_dLen = $dLen;
                         /*! Note by Vicary @ 2.Oct.2012
                          *  Total download size is often 0 if server doesn't
                          *  response with a Content-Length header.
                          *
                          *  Total size guessing logic:
                          *  1. if $dLen < 1M, assume 1M.
                          *  2. if $dLen < 10M, assume 10M.
                          *  3. if $dLen < 100M, assume 100M.
                          *  4. if $dLen < 1G, assume 1G.
                          */
                         if (!$dSize) {
                             // Do not assume when size under 1K
                             if ($dLen < 5000) {
                                 return;
                             } elseif ($dLen < 10000000) {
                                 $dSize = 20000000;
                             } elseif ($dLen < 100000000) {
                                 $dSize = 200000000;
                             } elseif ($dLen < 1000000000) {
                                 $dSize = 2000000000;
                             } else {
                                 $dSize = 20000000000;
                             }
                             // $dSize = $dLen / .05;
                         }
                         // Download progress, from 0 to 1.
                         $progressArgs = array($dLen / $dSize, $dLen, $dSize);
                     }
                 } else {
                     if ($uSize) {
                         static $_uLen = 0;
                         if ($_uLen != $uLen) {
                             $_uLen = $uLen;
                             $uSize *= -1;
                             $uLen += $uSize;
                             // Upload progress, from -1 to 0.
                             $progressArgs = array($uLen / $uSize, $uLen, $uSize);
                         }
                     }
                 }
                 // Fire the event for each µSeconds.
                 static $_tOffset = 0;
                 $tOffset = microtime(1);
                 if (isset($progressArgs) && $tOffset - $_tOffset > self::progressInterval()) {
                     $_tOffset = $tOffset;
                     Utility::forceInvoke($progressCallback, $progressArgs);
                 }
             };
         }
         unset($progressCallback);
         // 3. Apply cUrl options, numeric keys only.
         $option['handle'] = curl_init();
         curl_setopt_array($option['handle'], array_filter_keys($option, 'is_int'));
     });
     $requestIndex = 0;
     while ($requestIndex < self::$maximumRequests && isset($options[$requestIndex])) {
         curl_multi_add_handle($multiHandle, $options[$requestIndex++]['handle']);
     }
     // Start the multi request
     do {
         $status = curl_multi_exec($multiHandle, $active);
         /* Added by Vicary @ 6.Nov.2012
               Blocks until there is a message arrives.
            */
         curl_multi_select($multiHandle);
         do {
             $info = curl_multi_info_read($multiHandle, $queueLength);
             if ($info === FALSE) {
                 continue;
             }
             $optionIndex = array_search($info['handle'], array_map(prop('handle'), $options));
             if ($optionIndex === FALSE) {
                 continue;
             }
             $curlOption =& $options[$optionIndex];
             $callbacks =& $curlOption['callbacks'];
             // Success handler
             if ($info['result'] === CURLE_OK) {
                 // Fire a 100% downloaded event.
                 if (@$callbacks['progress']) {
                     Utility::forceInvoke($callbacks['progress'], array(1, 1, 1));
                     usleep(self::progressInterval() * 1000000);
                 }
                 // Append HTTP status code
                 $curlOption['status'] = curl_getinfo($info['handle'], CURLINFO_HTTP_CODE);
                 Utility::forceInvoke(@$callbacks['success'], array(curl_multi_getcontent($info['handle']), $curlOption));
             } else {
                 $errorNumber = curl_errno($info['handle']);
                 $errorMessage = curl_error($info['handle']);
                 // libcurl errors, try to parse it.
                 if ($errorNumber === 0) {
                     if (preg_match('/errno: (\\d+)/', $errorMessage, $matches)) {
                         $errorNumber = (int) $matches[1];
                         $curlErrors = unserialize(FRAMEWORK_NET_CURL_ERRORS);
                         if (isset($curlErrors[$errorNumber])) {
                             $errorMessage = $curlErrors[$errorNumber];
                         }
                     }
                 }
                 Utility::forceInvoke(@$callbacks['failure'], array($errorNumber, $errorMessage, $curlOption));
                 unset($errorNumber, $errorMessage);
             }
             // Always handler
             Utility::forceInvoke(@$callbacks['always'], array($curlOption));
             if (isset($options[$requestIndex])) {
                 curl_multi_add_handle($multiHandle, $options[$requestIndex++]['handle']);
                 // Keep the loop alive.
                 $active = TRUE;
             }
             curl_multi_remove_handle($multiHandle, $info['handle']);
             curl_close($info['handle']);
             unset($info, $callbacks, $curlOption, $options[$optionIndex], $optionIndex);
         } while ($queueLength > 0);
     } while ($status === CURLM_CALL_MULTI_PERFORM || $active);
     curl_multi_close($multiHandle);
 }
Example #4
0
 /**
  * Upsert function.
  *
  * @param $table Target table name.
  * @param $data Key-value pairs of field names and values.
  *
  * @returns True on update succeed, insertId on a row inserted, false on failure.
  */
 public static function upsert($table, array $data, $update = null)
 {
     $fields = static::escapeField(array_keys($data), $table);
     $values = array_values($data);
     $query = sprintf('INSERT INTO %s (%s) VALUES (%s)', static::escapeField($table), implode(', ', $fields), implode(', ', array_fill(0, count($fields), '?')));
     // append "ON DUPLICATE KEY UPDATE ..."
     $keys = static::getFields($table, 'PRI');
     $fields = array_intersect($fields, static::escapeField($keys, $table));
     if ($fields) {
         // selective update
         if ($update !== null) {
             $data = array_select($data, (array) $update);
         }
         foreach ($data as $field => $value) {
             $data["`{$field}` = ?"] = $value;
             unset($data[$field]);
         }
         // full dataset appended with non-key fields
         $values = array_merge($values, array_values(array_filter_keys($data, notIn($keys))));
         $query .= ' ON DUPLICATE KEY UPDATE ';
         if ($data) {
             $query .= implode(', ', array_keys($data));
         } else {
             // note: key1 = key1; We do not use INSERT IGNORE because it'll ignore other errors.
             $value = reset($fields);
             $query .= "{$value} = {$value}";
             unset($value);
         }
     }
     unset($keys, $fields);
     $res = static::query($query, $values);
     unset($query, $values);
     if ($res !== false) {
         $res->closeCursor();
         // Inserted, return the new ID.
         if ($res->rowCount() == 1) {
             // Note: mysql_insert_id() doesn't do UNSIGNED ZEROFILL!
             $res = (int) static::getConnection()->lastInsertId();
             //$res = static::fetchField("SELECT MAX(ID) FROM `$table`;");
         } else {
             $res = true;
         }
     }
     return $res;
 }
Example #5
0
 /**
  * Handles saving updated category information from the category editor
  *
  * @author Jonathan Davis
  * @since 1.0
  * @return void
  **/
 public function save($Category)
 {
     $Shopp = Shopp::object();
     check_admin_referer('shopp-save-category');
     if (!current_user_can('shopp_categories')) {
         wp_die(__('You do not have sufficient permissions to access this page.'));
     }
     shopp_set_formsettings();
     // Save workflow setting
     if (empty($Category->meta)) {
         $Category->load_meta();
     }
     if (isset($_POST['content'])) {
         $_POST['description'] = $_POST['content'];
     }
     $Category->name = $_POST['name'];
     $Category->description = $_POST['description'];
     $Category->parent = $_POST['parent'];
     $Category->prices = array();
     // Variation price templates
     if (!empty($_POST['price']) && is_array($_POST['price'])) {
         foreach ($_POST['price'] as &$pricing) {
             $pricing['price'] = Shopp::floatval($pricing['price'], false);
             $pricing['saleprice'] = Shopp::floatval($pricing['saleprice'], false);
             $pricing['shipfee'] = Shopp::floatval($pricing['shipfee'], false);
             $pricing['dimensions'] = array_map(array('Shopp', 'floatval'), $pricing['dimensions']);
         }
     }
     $_POST['prices'] = isset($_POST['price']) ? $_POST['price'] : array();
     if (empty($_POST['specs'])) {
         $Category->specs = array();
     }
     /* @todo Move the rest of category meta inputs to [meta] inputs eventually */
     if (isset($_POST['meta']) && isset($_POST['meta']['options'])) {
         // Moves the meta options input to 'options' index for compatibility
         $_POST['options'] = $_POST['meta']['options'];
     }
     if (empty($_POST['meta']['options']) || count($_POST['meta']['options']['v']) == 1 && !isset($_POST['meta']['options']['v'][1]['options'])) {
         $_POST['options'] = $Category->options = array();
         $_POST['prices'] = $Category->prices = array();
     }
     $metaprops = array('spectemplate', 'facetedmenus', 'variations', 'pricerange', 'priceranges', 'specs', 'options', 'prices');
     $metadata = array_filter_keys($_POST, $metaprops);
     // Update existing entries
     $updates = array();
     foreach ($Category->meta as $id => $MetaObject) {
         $name = $MetaObject->name;
         if (isset($metadata[$name])) {
             $MetaObject->value = stripslashes_deep($metadata[$name]);
             $updates[] = $name;
         }
     }
     // Create any new missing meta entries
     $new = array_diff(array_keys($metadata), $updates);
     // Determine new entries from the exsting updates
     foreach ($new as $name) {
         if (!isset($metadata[$name])) {
             continue;
         }
         $Meta = new MetaObject();
         $Meta->name = $name;
         $Meta->value = stripslashes_deep($metadata[$name]);
         $Category->meta[] = $Meta;
     }
     $Category->save();
     if (!empty($_POST['deleteImages'])) {
         $deletes = array();
         if (strpos($_POST['deleteImages'], ",")) {
             $deletes = explode(',', $_POST['deleteImages']);
         } else {
             $deletes = array($_POST['deleteImages']);
         }
         $Category->delete_images($deletes);
     }
     if (!empty($_POST['images']) && is_array($_POST['images'])) {
         $Category->link_images($_POST['images']);
         $Category->save_imageorder($_POST['images']);
         if (!empty($_POST['imagedetails']) && is_array($_POST['imagedetails'])) {
             foreach ($_POST['imagedetails'] as $i => $data) {
                 $Image = new CategoryImage($data['id']);
                 $Image->title = $data['title'];
                 $Image->alt = $data['alt'];
                 $Image->save();
             }
         }
     }
     do_action_ref_array('shopp_category_saved', array($Category));
     $this->notice(Shopp::__('%s category saved.', '<strong>' . $Category->name . '</strong>'));
 }
Example #6
0
 /**
  * Because POST can be JSON, or other formats in the future, we cannot simply
  * use $_REQUEST.
  *
  * Another difference with $_REQUEST is this also counts $_COOKIE.
  */
 public function param($name = null, $type = null)
 {
     /*! Note @ 23 Apr, 2015
      *  POST validation should be simple, just match it with some hash key stored in sessions.
      */
     // TODO: Do form validation, take reference from form key of Magento.
     $result = $this->_param($type);
     if (is_array($result)) {
         // remove meta keys and sensitive values
         $result = array_filter_keys($result, funcAnd(notIn([ini_get('session.name')]), compose('not', startsWith($this->metaPrefix))));
     }
     if ($name === null) {
         return $result;
     } else {
         $fx = prop($name);
         return $fx($result);
     }
 }
 /**
  * 
  */
 public function testArrayFilterKeys()
 {
     $array = ['fii' => 3, 'faa' => 2, 'foo' => 1];
     $this->assertEquals(array_filter_keys($array, ['faa']), ['faa' => 2]);
 }
Example #8
0
function require_method($Method, $Target = false)
{
    // A simple way to enforce usage of the intended HTTP method for a given page
    if (strcasecmp($_SERVER['REQUEST_METHOD'], $Method) === 0) {
        return;
    }
    error_log("Rejected non-{$Method} request for {$_SERVER['REQUEST_URI']}. \$_SERVER=" . unwrap(var_export(array_filter_keys($_SERVER, array("HTTP_REFERER", 'HTTP_USER_AGENT', 'HTTP_HOST', 'REQUEST_METHOD', 'REQUEST_URI', 'QUERY_STRING')), true)));
    redirect($Target);
}