Permalink
Browse files

Improved Youtube button, support for prefix for Mongo Collections, bug

fixes, more...
  • Loading branch information...
1 parent 933ffcf commit 59b4647841ec785d2192dd5292bf6564ea318f2f @snytkine snytkine committed May 31, 2011
View
10 !config.ini.dist
@@ -10,6 +10,16 @@ Persistent = 0
[MONGO]
server = "mongodb://127.0.0.2:27017"
db = "LAMPCMS"
+; If you already have existing
+; Mongo Database with existing collections
+; you may want to set the prefix
+; all collections used by this program will
+; be prefixed with this word.
+; For example you may set prefix to "Lampcms"
+; then collection USERS will become LampcmsUSERS
+; This will take care of possible name collisions with
+; existing collections
+prefix = ""
[CACHE_MONGO]
; good option to use the same db as in "MONGO" section
View
3 !inc.php
@@ -82,6 +82,8 @@ function fastcgi_finish_request(){}
require $lampcmsClasses.'Interfaces'.DIRECTORY_SEPARATOR.'All.php';
require $lampcmsClasses.'Exception.php';
require $lampcmsClasses.'Object.php';
+require $lampcmsClasses.'Mongo'.DIRECTORY_SEPARATOR.'Collections.php';
+require LAMPCMS_PATH.DIRECTORY_SEPARATOR.'Mycollections.php';
require $lampcmsClasses.'Ini.php';
require $lampcmsClasses.'Log.php';
require $lampcmsClasses.'Request.php';
@@ -91,6 +93,7 @@ function fastcgi_finish_request(){}
require $lampcmsClasses.'SplClassLoader.php';
require $lampcmsClasses.'Registry.php';
require $lampcmsClasses.'Template'.DIRECTORY_SEPARATOR.'Template.php';
+
/**
* Points.php is in non-standard directory,
* in fact this file is not even included in distro
View
81 Mycollections.php.dist
@@ -0,0 +1,81 @@
+<?php
+/**
+ *
+ * License, TERMS and CONDITIONS
+ *
+ * This software is lisensed under the GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
+ * Please read the license here : http://www.gnu.org/licenses/lgpl-3.0.txt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ATTRIBUTION REQUIRED
+ * 4. All web pages generated by the use of this software, or at least
+ * the page that lists the recent questions (usually home page) must include
+ * a link to the http://www.lampcms.com and text of the link must indicate that
+ * the website\'s Questions/Answers functionality is powered by lampcms.com
+ * An example of acceptable link would be "Powered by <a href="http://www.lampcms.com">LampCMS</a>"
+ * The location of the link is not important, it can be in the footer of the page
+ * but it must not be hidden by style attibutes
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This product includes GeoLite data created by MaxMind,
+ * available from http://www.maxmind.com/
+ *
+ *
+ * @author Dmitri Snytkine <cms@lampcms.com>
+ * @copyright 2005-2011 (or current year) ExamNotes.net inc.
+ * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
+ * @link http://www.lampcms.com Lampcms.com project
+ * @version Release: @package_version@
+ *
+ *
+ */
+
+
+namespace Lampcms\My;
+
+/**
+ * This is not a class!
+ *
+ * The purpose of this file
+ * is to define custom
+ * Mongo Collections YOU may have created for your custom modules
+ * By default there are no values here but this file is still required!
+ *
+ * Look in lib/Lampcms/Mongo/Collections for actual file and how
+ * the actual entries look like.
+ *
+ * @author Dmitri Snytkine
+ *
+ */
+
+
+
+/**
+ * Example: If you create custom module
+ * and it requires Mongo collection named MYSTUFF
+ * then you would have an entry like the one below
+ * (but it would not be commented out of cause)
+ *
+ *
+ */
+// const MYSTUFF = 'MYSTUFF';
+
View
76 lib/Lampcms/Cache.php
@@ -133,8 +133,7 @@ class Cache extends Observer
/**
* @param Registry $oRegistry
*/
- public function __construct(Registry $oRegistry)
- {
+ public function __construct(Registry $oRegistry){
d('starting Cache');
parent::__construct($oRegistry);
$this->oTtl = new ArrayDefaults(array(), 0);
@@ -156,14 +155,12 @@ public function __construct(Registry $oRegistry)
* @return void
* @throws Cache_Proxy_User_Exception
*/
- public function __clone()
- {
+ public function __clone(){
throw new DevException('Cloning this object is not allowed.');
}
- public function __toString()
- {
+ public function __toString(){
return 'object of type CacheHandler';
}
@@ -182,17 +179,17 @@ public function __toString()
*
* @throws Cache_Proxy_User_Exception is case the requested key is not a string or array
*/
- public function get($key, array $arrExtra = array())
- {
+ public function get($key, array $arrExtra = array()){
d('$key: '.$key.' $arrExtra: '.print_r(array_keys($arrExtra), 1) );
$this->arrExtra = $arrExtra;
- if (is_string($key)) {
+ if (\is_string($key)) {
d('cp');
$res = $this->getFromCache($key);
if (false === $res) {
$res = $this->getKeyValue($key);
+
$this->setValues($key, $res);
}
@@ -245,15 +242,14 @@ public function get($key, array $arrExtra = array())
- public function setCacheEngine(Interfaces\Cache $oCache = null)
- {
+ public function setCacheEngine(Interfaces\Cache $oCache = null){
$this->oCacheInterface = $oCache;
return $this;
}
- protected function getMissingKeys()
- {
+
+ protected function getMissingKeys(){
d('Could not get all keys from memcache'.print_r($this->aMissingKeys, 1));
$arrFoundKey = array();
@@ -275,18 +271,19 @@ protected function getMissingKeys()
* @param $key
* @return mixed a data returned for the requested key or false
*/
- protected function getKeyValue($key)
- {
+ protected function getKeyValue($key){
$aRes = explode('_', $key, 2);
$arg = (array_key_exists(1, $aRes)) ? $aRes[1] : null;
+ d('aRes: '.print_r($aRes, 1));
+
/**
* Check that method exists
*/
if (method_exists($this, $aRes[0])) {
$method = $aRes[0];
d('Looking for key: '.$key.' Going to use method: '.$method);
- $res = call_user_func(array($this, $method), $arg);
+ $res = \call_user_func(array($this, $method), $arg);
d('res: '.print_r($res, true));
return $res;
@@ -342,15 +339,13 @@ public function tryKey($key)
* @return mixed a value of the requested memcache key
* @throws Cache_Proxy_User_Exception if requested key is not a string.
*/
- public function __get($key)
- {
+ public function __get($key){
if (!is_string($key)) {
throw new DevException('Cache key must be a string');
}
d('looking for '.$key);
return $this->get($key);
-
}
@@ -369,8 +364,7 @@ public function __get($key)
* $this->hdlCache->somekey = ''; is not allowed. setting value to null or
* using an empty array as value will also cause this exception.
*/
- public function __set($strKey, $val)
- {
+ public function __set($strKey, $val){
if (!is_string($strKey)) {
throw new DevException('Cache key must be a string');
@@ -395,8 +389,7 @@ public function __set($strKey, $val)
* @param $key
* @return mixed whatever is returned from $oCache object
*/
- protected function getFromCache($key)
- {
+ protected function getFromCache($key){
if(true === $this->skipCache || null === $this->oCacheInterface){
d('cp');
@@ -423,17 +416,16 @@ protected function getFromCache($key)
* @param $val
* @return bool
*/
- public function setValues($key, $val = '')
- {
+ public function setValues($key, $val = ''){
if (!$this->skipCache) {
- if (is_string($key)) {
-
+ if (\is_string($key)) {
+
/**
* @todo must ensure $val is utf-8 by
* running it through Utf8String::factory()!
* or better yet make setValue() that requires
* Utf8string as value!
- *
+ *
*/
/**
* must have a way to
@@ -446,7 +438,8 @@ public function setValues($key, $val = '')
* for the thread array.
*/
if (!empty($val) || (0 === $val)) {
-
+ d('going to set key '.$key.' val: '.var_export($val, 1));
+
return $this->oCacheInterface->set($key, $val, $this->oTtl[$key], $this->aTags);
}
} elseif (!empty($key)) {
@@ -473,8 +466,7 @@ public function setValues($key, $val = '')
*
* @throws Cache_Proxy_User_Exception is $key is not a string
*/
- public function __isset($key)
- {
+ public function __isset($key){
if (!is_string($key)) {
throw new DevException('$key can only be a string. Supplied argument was of type: '.gettype($key));
}
@@ -499,8 +491,7 @@ public function __isset($key)
*
* @throws Cache_Proxy_User_Exception is $key is not a string
*/
- public function __unset($key)
- {
+ public function __unset($key){
if (!is_string($key)) {
throw new DevException('$key can only be a string. Supplied argument was of type: '.gettype($key));
@@ -516,6 +507,7 @@ public function __unset($key)
}
}
+
/**
* Handle events
* (non-PHPdoc)
@@ -560,7 +552,7 @@ public function qrecent(){
d('html recent tags: '.$html);
$this->aTags = array('tags');
-
+
return '<div class="tags-list">'.$html.'</div>';
}
@@ -586,9 +578,9 @@ public function qunanswered(){
if($count > $limit){
$ret .= '<div class="moretags"><a href="/tags/unanswered/"><span rel="in">All unanswered tags</span></a>';
}
-
+
$this->aTags = array('tags');
-
+
return $ret;
}
@@ -599,9 +591,7 @@ public function qunanswered(){
*
* @return object of type GeoipLocation
*/
- protected function geo($strIp)
- {
-
+ protected function geo($strIp){
d('getting geodata for ip: '.$strIp);
$strKey = 'geo_'.$strIp;
@@ -616,20 +606,22 @@ protected function geo($strIp)
$this->aTags = array('geo');
+ d('returning oGeoIP: '.gettype($oGeoIP));
+
return $oGeoIP;
}
+
/**
* Creates and returns Acl object
*
* @return object of type \Lampcms\Acl\Acl
*/
- protected function Acl()
- {
+ protected function Acl(){
d('cp');
$this->aTags = array('acl', 'settings');
- return new \Lampcms\Acl\Acl();
+ return new \Lampcms\Acl\Acl();
}
View
4 lib/Lampcms/Controllers/Ask.php
@@ -105,9 +105,9 @@ protected function process(){
d('cp created new question');
d('title: '.$oQuestion['title']);
- if(LAMPCMS_DEBUG){
+ /*if(LAMPCMS_DEBUG){
Responder::sendJSON(array());
- }
+ }*/
Responder::redirectToPage($oQuestion->getUrl());
View
23 lib/Lampcms/Controllers/Logintwitter.php
@@ -488,15 +488,17 @@ protected function createNewUser(){
$aUser['i_rep'] = 1;
$oGeoData = $this->oRegistry->Cache->{sprintf('geo_%s', Request::getIP())};
- $aProfile = array(
- 'cc' => $oGeoData->countryCode,
- 'country' => $oGeoData->countryName,
- 'state' => $oGeoData->region,
- 'city' => $oGeoData->city,
- 'zip' => $oGeoData->postalCode);
- d('aProfile: '.print_r($aProfile, 1));
-
- $aUser = array_merge($aUser, $aProfile);
+ if(\is_object($oGeoData)){
+ $aProfile = array(
+ 'cc' => $oGeoData->countryCode,
+ 'country' => $oGeoData->countryName,
+ 'state' => $oGeoData->region,
+ 'city' => $oGeoData->city,
+ 'zip' => $oGeoData->postalCode);
+ d('aProfile: '.print_r($aProfile, 1));
+
+ $aUser = array_merge($aUser, $aProfile);
+ }
if(!empty($this->aUserData['url'])){
$aUser['url'] = $this->aUserData['url'];
@@ -601,9 +603,8 @@ protected function postTweetStatus(){
}
-
/**
- * Create a new record in USERS_GFC table
+ * Create a new record in USERS_TWITTER table
* or update an existing record
*
* @param unknown_type $isUpdate
View
25 lib/Lampcms/Controllers/Register.php
@@ -253,17 +253,18 @@ protected function createNewUser(){
$aData['i_rep'] = 1;
$oGeoData = $this->oRegistry->Cache->{sprintf('geo_%s', Request::getIP())};
$aProfile = array();
+
if($oGeoData){
$aProfile = array(
'cc' => $oGeoData->countryCode,
'country' => $oGeoData->countryName,
'state' => $oGeoData->region,
'city' => $oGeoData->city,
'zip' => $oGeoData->postalCode);
- d('aProfile: '.print_r($aProfile, 1));
+ d('aProfile: '.print_r($aProfile, 1));
}
-
- $aUser = array_merge($aData, $aProfile);
+
+ $aUser = \array_merge($aData, $aProfile);
d('aUser: '.print_r($aUser, 1));
@@ -310,11 +311,13 @@ protected function createEmailRecord(){
'has_gravatar' => \Lampcms\Gravatar::factory($this->email)->hasGravatar(),
'ehash' => hash('md5', $this->email),
'i_code_ts' => time(),
- 'code' => substr(hash('md5', uniqid(mt_rand())), 0, 12));
-
+ 'code' => \substr(hash('md5', \uniqid(\mt_rand())), 0, 12));
+
$this->oEmail = \Lampcms\MongoDoc::factory($this->oRegistry, 'EMAILS', $a);
- $this->oEmail->save();
-
+
+ $res = $this->oEmail->save();
+ d('$res: '.$res);
+
return $this;
}
@@ -324,18 +327,16 @@ protected function createEmailRecord(){
*
* @return string url of account activation link
*/
- protected function makeActivationLink()
- {
+ protected function makeActivationLink(){
$tpl = $this->oRegistry->Ini->SITE_URL.'/aa/%d/%s';
- $link = sprintf($tpl, $this->oEmail->_id, $this->oEmail->code);
+ $link = \sprintf($tpl, $this->oEmail['_id'], $this->oEmail['code']);
d('activation link: '.$link);
return $link;
}
- protected function sendActivationEmail()
- {
+ protected function sendActivationEmail(){
$sActivationLink = $this->makeActivationLink();
$siteName = $this->oRegistry->Ini->SITE_NAME;
$body = vsprintf(self::EMAIL_BODY, array($siteName, $this->username, $this->pwd, $sActivationLink));
View
6 lib/Lampcms/Controllers/Requestactivation.php
@@ -104,7 +104,7 @@ protected function getEmailObject(){
}
$this->oEmail = MongoDoc::factory($this->oRegistry, 'EMAILS')->byEmail($this->email);
- if('' == $this->oEmail->email){
+ if('' == $this->oEmail['email']){
throw new \Lampcms\NoemailException('You have not selected any email address for your account yet');
}
@@ -144,7 +144,9 @@ protected function makeActivationCode(){
protected function sendActivationEmail()
{
$tpl = $this->oRegistry->Ini->SITE_URL.'/aa/%d/%s';
- $link = sprintf($tpl, $this->oEmail->_id, $this->oEmail->code);
+ $link = sprintf($tpl, $this->oEmail['_id'], $this->oEmail['code']);
+ d('$link: '.$link);
+
$siteName = $this->oRegistry->Ini->SITE_NAME;
$body = vsprintf(self::EMAIL_BODY, array($siteName, $link));
$subject = sprintf(self::SUBJECT, $siteName);
View
24 lib/Lampcms/ExternalAuthFb.php
@@ -344,7 +344,7 @@ public function getFacebookUserObject(){
d('existing user $this->oUser: '.print_r($this->oUser->getArrayCopy(), 1));
$this->updateUser()->updateFbUserRecord();
d('cp');
-
+
return $this->oUser;
}
@@ -650,16 +650,18 @@ protected function createNewUser(){
}
$oGeoData = $this->oRegistry->Cache->{sprintf('geo_%s', Request::getIP())};
- $aProfile = array(
- 'cc' => $oGeoData->countryCode,
- 'country' => $oGeoData->countryName,
- 'state' => $oGeoData->region,
- 'city' => $oGeoData->city,
- 'zip' => $oGeoData->postalCode);
- d('aProfile: '.print_r($aProfile, 1));
-
- $aUser = \array_merge($aUser, $aProfile);
-
+ if(\is_object($oGeoData)){
+ $aProfile = array(
+ 'cc' => $oGeoData->countryCode,
+ 'country' => $oGeoData->countryName,
+ 'state' => $oGeoData->region,
+ 'city' => $oGeoData->city,
+ 'zip' => $oGeoData->postalCode);
+ d('aProfile: '.print_r($aProfile, 1));
+
+ $aUser = \array_merge($aUser, $aProfile);
+ }
+
if(!empty($this->aFbUserData['locale'])){
$aUser['locale'] = $this->aFbUserData['locale'];
}
View
51 lib/Lampcms/ExternalAuthGfc.php
@@ -125,8 +125,7 @@ public function __construct(Registry $oRegistry, $gfcSiteId){
*
* @param string $fcauth value of fcauth cookie
*/
- protected function getGfcData()
- {
+ protected function getGfcData(){
$url = 'http://www.google.com/friendconnect/api/people/@viewer/@self?fcauth='.$this->fcauth;
$oHTTP = new Curl();
@@ -211,15 +210,13 @@ protected function getGfcData()
*
*
*/
- protected function revokeFcauth()
- {
+ protected function revokeFcauth(){
if(!empty($this->aGfcData['id'])){
- $this->oRegistry->Mongo->getCollection('USERS_GFC')
- ->update(array('_id' => $this->aGfcData['id']), array('$set' => array('fcauth' => null)));
+ $this->oRegistry->Mongo->USERS_GFC->update(array('_id' => $this->aGfcData['id']), array('$set' => array('fcauth' => null)));
d('cp');
}
-
+
$this->oUser->offsetUnset('fcauth');
$this->oUser->save();
$this->oRegistry->Dispatcher->post($this, 'onGfcUserDelete');
@@ -235,8 +232,7 @@ protected function revokeFcauth()
* @return object of type UserGfc which is either a newly
* created user or existing user found by GFC id
*/
- public function getUserObject()
- {
+ public function getUserObject(){
$this->getGfcData();
@@ -247,8 +243,7 @@ public function getUserObject()
*
*/
- $aGfc = $this->oRegistry->Mongo->getCollection('USERS_GFC')
- ->findOne(array('_id' => $this->aGfcData['id']));
+ $aGfc = $this->oRegistry->Mongo->USERS_GFC->findOne(array('_id' => $this->aGfcData['id']));
if(empty($aGfc) || empty($aGfc['i_uid'])){
d('cp');
@@ -278,8 +273,8 @@ public function getUserObject()
*
* @return object $this
*/
- protected function getGfcCookieVal()
- {
+ protected function getGfcCookieVal(){
+
$cookieName = null;
$fcauthSession = 'fcauth'.$this->gfcSiteId.'-s';
$fcauthRegular = 'fcauth'.$this->gfcSiteId;
@@ -315,8 +310,7 @@ protected function getGfcCookieVal()
* post notification onUserUpdate
*
*/
- protected function updateUser()
- {
+ protected function updateUser(){
$oldAvatar = $this->oUser->avatar_external;
$newAvatar = $this->aGfcData['thumbnailUrl'];
@@ -375,16 +369,18 @@ protected function createNewUser(){
$oGeoData = $this->oRegistry->Cache->{sprintf('geo_%s', Request::getIP())};
- $aProfile = array(
- 'cc' => $oGeoData->countryCode,
- 'country' => $oGeoData->countryName,
- 'state' => $oGeoData->region,
- 'city' => $oGeoData->city,
- 'zip' => $oGeoData->postalCode);
- d('aProfile: '.print_r($aProfile, 1));
-
- $aUser = array_merge($aUser, $aProfile);
-
+ if(\is_object($oGeoData)){
+ $aProfile = array(
+ 'cc' => $oGeoData->countryCode,
+ 'country' => $oGeoData->countryName,
+ 'state' => $oGeoData->region,
+ 'city' => $oGeoData->city,
+ 'zip' => $oGeoData->postalCode);
+ d('aProfile: '.print_r($aProfile, 1));
+
+ $aUser = array_merge($aUser, $aProfile);
+ }
+
d('aUser: '.print_r($aUser, 1));
$this->oUser = UserGfc::factory($this->oRegistry, $aUser);
@@ -426,8 +422,7 @@ protected function createNewUser(){
*
* @param unknown_type $isUpdate
*/
- protected function updateGfcUserRecord($isUpdate = false)
- {
+ protected function updateGfcUserRecord($isUpdate = false){
/**
* Create new record or update in USERS_GFC collection
@@ -444,7 +439,7 @@ protected function updateGfcUserRecord($isUpdate = false)
d('$aGfc: '.print_r($aGfc, 1));
- $this->oRegistry->Mongo->getCollection('USERS_GFC')->save($aGfc, array('fsync' => true));
+ $this->oRegistry->Mongo->USERS_GFC->save($aGfc, array('fsync' => true));
return $this;
}
View
25 lib/Lampcms/Forms/Answerform.php
@@ -51,9 +51,10 @@
namespace Lampcms\Forms;
+
-
-use Lampcms\LoginForm;
+use \Lampcms\LoginForm;
+use \Lampcms\String\HTMLString;
/**
* Class responsible for processing the
* Answer form as well as rendering the ask form
@@ -160,23 +161,19 @@ public function getAnswerForm(\Lampcms\Question $oQuestion){
* @return object $this
*/
protected function doValidate(){
- $body = $this->oRegistry->Request['qbody'];
+
$minChars = $this->oRegistry->Ini->MIN_ANSWER_CHARS;
$minWords = $this->oRegistry->Ini->MIN_ANSWER_WORDS;
- /**
- * We really need to check the length of
- * the content not couning html tags
- * otherwise it's possible to submit
- * even an empty question as long as it
- * has some line breaks and empty tags
- */
- $body = trim(strip_tags($body));
- if(\mb_strlen($body) < $minChars){
+ $body = $this->oRegistry->Request->getUTF8('qbody');
+ $oHtmlString = HTMLString::factory($body);
+ $wordCount = $oHtmlString->getWordsCount();
+ $len = $oHtmlString->length();
+
+ if($len < $minChars){
$this->setError('qbody', 'Answer must contain at least '.$minChars.' letters');
}
- $aWords = explode(' ', $body);
- if(count($aWords) < $minWords){
+ if($wordCount < $minWords){
$this->setError('qbody', 'Answer must contain at least '.$minWords.' words');
}
View
23 lib/Lampcms/Forms/Askform.php
@@ -52,7 +52,7 @@
namespace Lampcms\Forms;
-
+use \Lampcms\String\HTMLString;
/**
* Class responsible
* for processing the "Ask" form
@@ -149,26 +149,23 @@ protected function validateTitle(){
* @return object $this
*/
protected function validateBody(){
- $body = $this->oRegistry->Request['qbody'];
+
$minChars = $this->oRegistry->Ini->MIN_QUESTION_CHARS;
$minWords = $this->oRegistry->Ini->MIN_QUESTION_WORDS;
- /**
- * We really need to check the length of
- * the content not couning html tags
- * otherwise it's possible to submit
- * even an empty question as long as it
- * has some line breaks and empty tags
- */
- $body = trim(strip_tags($body));
- if(\mb_strlen($body) < $minChars){
+ $body = $this->oRegistry->Request->getUTF8('qbody');
+ $oHtmlString = HTMLString::factory($body);
+ $wordCount = $oHtmlString->getWordsCount();
+ $len = $oHtmlString->length();
+
+ if($len < $minChars){
/**
* @todo Translate string
*/
$this->setError('qbody', 'Question must contain at least '.$minChars.' letters');
}
- $aWords = explode(' ', $body);
- if(count($aWords) < $minWords){
+
+ if($wordCount < $minWords){
/**
* @todo Translate string
*/
View
54 lib/Lampcms/Geoip.php
@@ -388,7 +388,7 @@ public function getIP(){
}
/**
- * Getter for $this->ip
+ * Getter for $this->ipnum
* @return string
*/
public function getIpnum(){
@@ -455,9 +455,13 @@ public static function getInstance($filename = null, $flags = null){
self::$instances[$filename] = new self($filename, $flags);
}
- d('returning instance for $filename '.$filename);
+ d('returning instance for $filename: '.$filename);
+ $ret = self::$instances[$filename];
+ d('ret: '.gettype($ret));
+ $class = (is_object($ret)) ? get_class($ret) : 'No GeoIP object = NULL';
+ d('class: '.$class);
- return self::$instances[$filename];
+ return $ret;
}
@@ -632,7 +636,7 @@ public function close(){
* - if database type is incorrect
*/
protected function lookupCountryId($addr){
- $ipnum = ip2long($addr);
+ $ipnum = \ip2long($addr);
if ($ipnum === false) {
throw new Exception("Invalid IP address: " . var_export($addr, true));
}
@@ -753,6 +757,8 @@ public function lookupRegion($addr){
*/
public function lookupLocation($addr){
if ($this->databaseType !== self::CITY_EDITION_REV0 && $this->databaseType !== self::CITY_EDITION_REV1) {
+ d('cp Error Invalid database type!');
+
throw new Net_GeoIP_DB_Exception("Invalid database type; lookupLocation() method expects City database.");
}
@@ -828,25 +834,30 @@ protected function getRegion(){
* Seek and populate
* Net_GeoIP_Location object for converted IP addr.
*
- * @return mixed object of type Net_GeoIP_Location | null
+ * @return object of type Net_GeoIP_Location
*/
protected function getRecord(){
+ $record = new GeoipLocation();
$seek_country = $this->seekCountry($this->ipnum);
if ($seek_country == $this->databaseSegments) {
- return null;
+
+ d('Country not found! for ip: '.$this->ipnum);
+
+ return $record;
}
$record_pointer = $seek_country + (2 * $this->recordLength - 1) * $this->databaseSegments;
if ($this->flags & self::SHARED_MEMORY) {
+
$record_buf = shmop_read($this->shmid, $record_pointer, self::FULL_RECORD_LENGTH);
} else {
+
+
fseek($this->filehandle, $record_pointer, SEEK_SET);
$record_buf = fread($this->filehandle, self::FULL_RECORD_LENGTH);
}
- $record = new GeoipLocation();
-
$record_buf_pos = 0;
$char = ord(substr($record_buf, $record_buf_pos, 1));
$record->set('countryCode', self::$COUNTRY_CODES[$char])
@@ -863,7 +874,7 @@ protected function getRecord(){
$char = ord(substr($record_buf,$record_buf_pos+$str_length,1));
}
if ($str_length > 0){
- $record->set('region', \substr($record_buf,$record_buf_pos,$str_length)) ;
+ $record->set('region', \substr($record_buf,$record_buf_pos, $str_length)) ;
}
$record_buf_pos += $str_length + 1;
$str_length = 0;
@@ -874,25 +885,31 @@ protected function getRecord(){
$str_length++;
$char = ord(substr($record_buf,$record_buf_pos+$str_length,1));
}
+
if ($str_length > 0){
$record->set('city', \substr($record_buf,$record_buf_pos,$str_length) );
}
+
$record_buf_pos += $str_length + 1;
$str_length = 0;
//get postal code
$char = ord(substr($record_buf,$record_buf_pos+$str_length,1));
+
while ($char != 0){
$str_length++;
$char = ord(substr($record_buf,$record_buf_pos+$str_length,1));
}
+
if ($str_length > 0){
$record->set('postalCode', \substr($record_buf,$record_buf_pos,$str_length));
}
+
$record_buf_pos += $str_length + 1;
$str_length = 0;
$latitude = 0;
$longitude = 0;
+
for ($j = 0;$j < 3; ++$j){
$char = ord(substr($record_buf, $record_buf_pos++, 1));
$latitude += ($char << ($j * 8));
@@ -939,7 +956,7 @@ protected function validateIP($addr){
}
$this->ip = $addr;
- $this->ipnum = ip2long($addr);
+ $this->ipnum = \ip2long($addr);
return $this;
}
@@ -953,20 +970,22 @@ protected function validateIP($addr){
* @return object $objGeoData geolocation information data
*/
public static function getGeoData($strIp){
-
+
if(!defined('GEOIP_FILE')){
d('GEOIP_FILE not defined');
return new GeoipLocation();
}
$file = constant('GEOIP_FILE');
+ d('$file: '.$file);
if(empty($file)){
d('GeoIP lookup not enabled because name of GEOIP_FILE is left blank in !config.ini');
return new GeoipLocation();
}
if (!is_string($strIp)) {
+
throw new \Lampcms\DevException('$strIp MUST be a string. Supplied value was: '.gettype($strIp));
}
@@ -998,6 +1017,7 @@ public static function getGeoData($strIp){
}
$strFileGeoipRegion = LAMPCMS_PATH.DS.$file;
+ d('$strFileGeoipRegion: '.$strFileGeoipRegion);
/**
* This will set the empty object
@@ -1007,19 +1027,25 @@ public static function getGeoData($strIp){
* @var object
*/
if(!is_readable($strFileGeoipRegion)){
+ d('unable to load geoIP file: '.$strFileGeoipRegion);
+
throw new DevException('Unable to read geoIP file: '.$strFileGeoipRegion.' make sure file exists and is readable');
}
-
-
+
try {
$hdlGeoIp = self::getInstance($strFileGeoipRegion, self::SHARED_MEMORY);
$objGeoData = $hdlGeoIp->lookupLocation($strIp);
+
}catch(Net_GeoIP_Exception $e) {
$err = 'Location data not found for IP: '.$strIp.' message: '.$e->getMessage();
e($err);
$objGeoData = new GeoipLocation();
}
-
+
+ $class = (is_object($objGeoData)) ? get_class($objGeoData) : 'No objGeoData class = NULL';
+ d('returning: '.gettype($objGeoData).' class: '.$class);
+
return $objGeoData;
}
+
}
View
2 lib/Lampcms/GeoipLocation.php
@@ -174,7 +174,7 @@ public function unserialize($serialized){
* @return object $this object
*/
public function set($name, $val){
- if(array_key_exists($name, $this->aData)){
+ if(\array_key_exists($name, $this->aData)){
$this->aData[$name] = \utf8_encode($val);
}
View
2 lib/Lampcms/Modules/Observers/EmailNotifier.php
@@ -287,7 +287,7 @@ public static function factory(\Lampcms\Registry $oRegistry){
/**
* @todo Finish this by adding handling
- * updates onNewComment, onEditedQuestion, onQuestionVote,
+ * updates onEditedQuestion, onQuestionVote,
* onAcceptAnswer, etc...
* and later deal with comment replies
*
View
52 lib/Lampcms/Mongo.php
@@ -50,6 +50,7 @@
*/
+
namespace Lampcms;
@@ -95,6 +96,20 @@ class Mongo extends LampcmsObject
*/
protected $aInsertOption = array('safe' => true);
+ /**
+ * Prefix for collection names
+ * If set to any non-empty string then
+ * ALL collections will be prefixed
+ * with this string. This option
+ * allows to override default collection names
+ * used in this program in case the existing
+ * database already has collections with same names
+ * as in the program.
+ *
+ * @var string
+ */
+ protected $prefix = "";
+
public function __construct(Ini $oIni){
@@ -124,6 +139,10 @@ public function __construct(Ini $oIni){
e($err);
throw new DevException($err);
}
+
+ if(!empty($aConfig['prefix'])){
+ $this->prefix = (string)$aConfig['prefix'];
+ }
}
@@ -295,13 +314,40 @@ public function getDb(){
* @return object of type MongoCollection
*/
public function getCollection($collName){
- if(!is_string($collName)){
+ if(!\is_string($collName)){
throw new \InvalidArgumentException('Param $collName must be a string. was: '.gettype($collName));
}
+
+
+ $coll = defined('Lampcms\Mongo\\'.$collName) ? \constant('Lampcms\Mongo\\'.$collName) : \constant('Lampcms\My\\'.$collName);
+ d('$coll: '.$coll);
- return $this->conn->selectCollection($this->dbname, $collName);
+ return $this->conn->selectCollection($this->dbname, $this->prefix.$coll);
+ }
+
+
+ /**
+ * Getter for prefix
+ *
+ * @return string by default prefix is an empty String
+ * which is perfectly fine
+ *
+ */
+ public function getPrefix(){
+ return $this->prefix;
+ }
+
+
+ /**
+ * Setter for $this->prefix
+ *
+ * @param string $prefix
+ */
+ public function setPrefix($prefix){
+ $this->prefix = (string)$prefix;
}
+
/**
* Alias of getCollection()
* This is the same name as in php's MongoDB class
@@ -324,7 +370,7 @@ public function selectCollection($collName){
* @return object of type MongoCollection
*/
public function __get($name){
- return $this->conn->selectCollection($this->dbname, $name);
+ return $this->getCollection($name);
}
View
258 lib/Lampcms/Mongo/Collections.php
@@ -0,0 +1,258 @@
+<?php
+/**
+ *
+ * License, TERMS and CONDITIONS
+ *
+ * This software is lisensed under the GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
+ * Please read the license here : http://www.gnu.org/licenses/lgpl-3.0.txt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * ATTRIBUTION REQUIRED
+ * 4. All web pages generated by the use of this software, or at least
+ * the page that lists the recent questions (usually home page) must include
+ * a link to the http://www.lampcms.com and text of the link must indicate that
+ * the website\'s Questions/Answers functionality is powered by lampcms.com
+ * An example of acceptable link would be "Powered by <a href="http://www.lampcms.com">LampCMS</a>"
+ * The location of the link is not important, it can be in the footer of the page
+ * but it must not be hidden by style attibutes
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This product includes GeoLite data created by MaxMind,
+ * available from http://www.maxmind.com/
+ *
+ *
+ * @author Dmitri Snytkine <cms@lampcms.com>
+ * @copyright 2005-2011 (or current year) ExamNotes.net inc.
+ * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
+ * @link http://www.lampcms.com Lampcms.com project
+ * @version Release: @package_version@
+ *
+ *
+ */
+
+namespace Lampcms\Mongo;
+
+/**
+ * This is not a class!
+ *
+ * The purpose of this file
+ * is to define namespace-specific constants
+ * that hold names of Mongo Collections
+ * use in this project
+ * as well as to provide some basic
+ * documentation about these collections
+ * via docblocks
+ *
+ * By using these constants instead of directly
+ * using the names of collections developers have
+ * a way of preventing inadvertantly
+ * misspeling of a collection name
+ *
+ * If you designing a custom module that will be
+ * requiring creation of a new Mongo Collection
+ * you should define that collection name in this file
+ *
+ * @author Dmitri Snytkine
+ *
+ */
+
+
+
+/**
+ * This collection is very important
+ * as it keeps track of the next value
+ * of Auto Increment counters per collection
+ *
+ *
+ */
+const Autoincrements = 'Autoincrements';
+
+/**
+ * Holds Answers to question
+ * each record has i_qid with is
+ * the value if _id from QUESTIONS collection
+ * privary key _id is an integer
+ *
+ */
+const ANSWERS = 'ANSWERS';
+
+const BANNED_IP = 'BANNED_IP';
+
+/**
+ * This collection does NOT
+ * hold actual comments but
+ * only meta data about comments
+ *
+ * Important data in this collection
+ * is the "coll" which is the name of collection
+ * where the actual comment is stored. ANSWERS or QUESTIONS
+ * actual comments are stored as nested arrays
+ * in ANSWERS and QUESTIONS collection
+ *
+ * Having this collection makes it possible
+ * to quickly find the actual comment just
+ * by the comment id - just find a record, then
+ * find out if this is comment for QUESTION or ANSWER,
+ * the id or QUESTION or ANSWER is the value if i_res
+ * and the value of i_qid is the Question ID - so if this
+ * comment is for the answer we will also know the question id
+ * that the answer belongs to.
+ *
+ * get it's parent id (if it's a reply),
+ * get id of user who posted it, get timestamp of comment,
+ * ip address of where it came from as well as hash - the hash
+ * (md5)
+ * is used to prevent duplicate comments
+ */
+const COMMENTS = 'COMMENTS';
+
+const COMMENTS_LIKES = 'COMMENTS_LIKES';
+
+const C_Cache = 'C_Cache';
+
+/**
+ * Email addresses of users are stored
+ * in this collection. Since user may have more than
+ * one email address, (extra email addresses),
+ * this collection has values of address and
+ * i_uid - the value of USER id as well
+ * as flags indicating whether of not this email
+ * address has gravatar of gravatars site.
+ *
+ * Also when new user is registered, an activation
+ * code is generated and stored in this collection
+ * The code is emailed to user and then we use the data
+ * in this collection to validate that user has clicked
+ * on the account activation link.
+ * Also activation links have expiration time, so time
+ * of creation of activation code is also stored here as timestamp
+ */
+const EMAILS = 'EMAILS';
+
+const LOGIN_ERROR = 'LOGIN_ERROR';
+
+/**
+ * User logins are stored
+ * in this collection to keep
+ * track on who logged in and when
+ * and what type of login it was (by cookie, by
+ * external authentication like Facebook, etc...)
+ *
+ * It also keeps Geo location data
+ * for each login as well as useragent.
+ * The data can be used for datamining
+ * @var unknown_type
+ */
+const LOGIN_LOG = 'LOGIN_LOG';
+
+const PASSWORD_CHANGE = 'PASSWORD_CHANGE';
+
+const QUESTIONS = 'QUESTIONS';
+
+const QUESTION_TAGS = 'QUESTION_TAGS';
+
+/**
+ * This collection holds value
+ * of qid - Question ID
+ * and uid - User id of user who viewed the question
+ * as well as timestamp i_ts of when the user first
+ * viewed the question.
+ * This is the way we enforce one view count per user.
+ *
+ * For anonymous viewer (not logged in) the value
+ * of session_id is used instead of user id - this way
+ * one view per session is counted.
+ */
+const QUESTION_VIEWS = 'QUESTION_VIEWS';
+
+const RELATED_TAGS = 'RELATED_TAGS';
+
+const REPORTED_ITEMS = 'REPORTED_ITEMS';
+
+/**
+ * Every Question and Answer
+ * are a "Resource" - just have different resource type
+ * Even time a new Question or Answer is created,
+ * a record is created in this collection and the
+ * auto-increment value is generated for it.
+ * Every Question and Answer has it's privary key _id equals
+ * to corresponding key in the collection.
+ *
+ * This collection holds values of _id and string value of type
+ * which is ANSWER or QUESTION, but can possibly be other
+ * types of resources if we decide to use different resource types
+ * later on.
+ *
+ * This collection also holds timestamps (in form on MongoDate)
+ * of the time of resource creation.
+ *
+ */
+const RESOURCE = 'RESOURCE';
+
+/**
+ * When user sends Q or A to Twitter
+ * the Tweet status from Twitter API
+ * is stored in this collection
+ */
+const TWEETS = 'TWEETS';
+
+const UNANSWERED_TAGS = 'UNANSWERED_TAGS';
+
+const USERS = 'USERS';
+
+const USERS_FACEBOOK = 'USERS_FACEBOOK';
+
+const USERS_TWITTER = 'USERS_TWITTER';
+
+const USERS_GFC = 'USERS_GFC';
+
+const USER_TAGS = 'USER_TAGS';
+
+/**
+ * USER_REFERRER contain the url
+ * from which use initially came from on his first visit
+ */
+const USER_REFEREF = 'USER_REFEREF';
+
+const VOTES = 'VOTES';
+
+const VOTE_HACKS = 'VOTE_HACKS';
+
+/**
+ * This is a collection used during
+ * tests. This is a temporary collection which
+ * is created only during run of test suite and
+ * then dropped at end of test
+ * Enter description here ...
+ * @var unknown_type
+ */
+const MY_MONGO_TEST_COLLECTION = 'MY_MONGO_TEST_COLLECTION';
+
+/**
+ * Another test collection, only used during run of tests
+ * and then dropped at end of test
+ * Enter description here ...
+ * @var unknown_type
+ */
+const MY_TEST_COLLECTION = 'MY_TEST_COLLECTION';
+
+
View
23 lib/Lampcms/MongoIncrementor.php
@@ -63,23 +63,18 @@
*/
class MongoIncrementor
{
- protected $oMongoDB;
+
+ /**
+ * Object of type Lampcms\Mongo
+ * Enter description here ...
+ * @var object of type \Lampcms\Mongo
+ */
+ protected $oMongo;
public function __construct(Mongo $oMongo){
- $this->oMongoDB = $oMongo->getDb();
+ $this->oMongo = $oMongo;
}
- /**
- * Name of collection where to
- * store the auto-increment values
- * You can change it but only before you
- * store your first value.
- * Once you begin storing values of you
- * auto-increments, it's best not to change this, ever!
- *
- * @var string name of collection
- */
- const COLLECTION_NAME = 'Autoincrements';
/**
* The pseudo auto increment handling is done
@@ -114,7 +109,7 @@ public function nextValue($collName, $initialId = 0, $try = 1){
}
$prevRecordID = null;
- $coll = $this->oMongoDB->selectCollection(self::COLLECTION_NAME);
+ $coll = $this->oMongo->Autoincrements;
$coll->ensureIndex(array('coll' => 1, 'id' => 1), array('unique' => true));
/**
View
2 lib/Lampcms/Object.php
@@ -52,7 +52,7 @@
namespace Lampcms;
-const JS_MIN_ID = '051220112';
+const JS_MIN_ID = '05312011';
const LF = "\n";
const CR = "\r";
View
7 lib/Lampcms/PostRegistration.php
@@ -78,15 +78,12 @@ class PostRegistration
*
* @return void
*/
- public static function createReferrerRecord(Registry $oRegistry, User $oUser)
- {
+ public static function createReferrerRecord(Registry $oRegistry, User $oUser){
$ref = (!empty($_COOKIE['ref'])) ? filter_input(INPUT_COOKIE, 'ref', FILTER_SANITIZE_URL) : '';
if(!empty($ref)){
$a = array('users_id' => $oUser->getUid(), 'referer_url' => $ref);
- $oRegistry->Mongo->getCollection('USER_REFEREF')->insert($a);
-
+ $oRegistry->Mongo->USER_REFEREF->insert($a);
}
}
-
}
View
9 lib/Lampcms/String.php
@@ -351,6 +351,15 @@ public function asPlainText(){
return $this->handleReturn(\trim($text));
}
+
+
+
+
+ public function stripTags(array $aAllowed = null){
+ $ret = \strip_tags($this->string, $aAllowed);
+
+ return $this->handleReturn($ret);
+ }
/**
View
52 lib/Lampcms/String/HTMLString.php
@@ -52,6 +52,7 @@
namespace Lampcms\String;
+use \Lampcms\Utf8String;
/**
* Class for parsing html fragment
@@ -238,6 +239,57 @@ public function length(){
return \mb_strlen($this->getText());
}
+
+ /**
+ * Get all text nodes of this HTML string
+ *
+ * @return object of type DOMNodeList
+ */
+ public function getTextNodes(){
+ return $this->xpath('//text()');
+ }
+
+
+ /**
+ * Get count of words in this html document
+ * This is the right way to get word count
+ * from HTML doc. The simple way of strip_tags and
+ * then explode by spaces will not work if
+ * html string is just one long
+ * string run together without white spaces
+ * and using regex is usually not the best way
+ * to deal with html string.
+ *
+ * Each Text Node element is then treated
+ * as separate UTF8String object
+ *
+ * This way each text node is split by UTF-8 specific word
+ * delimeters, making it return correct word count
+ * for Any type of language (not only splitting by spaces but
+ * by other accepted delimiters)
+ *
+ * The resulting word count will be accurate for arabic, chinese,
+ * and probably all other languages
+ *
+ * @return int count of words in this html string
+ */
+ public function getWordsCount(){
+ $count = 0;
+ $Nodes = $this->getTextNodes();
+ $len = $Nodes->length;
+ if(!$Nodes || 0 === $len){
+
+ return 0;
+ }
+
+ for($i = 0; $i < $len; $i += 1){
+ $UTF8String = Utf8String::factory($Nodes->item($i)->data, 'utf-8', true);
+ $count += $UTF8String->getWordsCount();
+ }
+
+ return $count;
+ }
+
/**
*
View
1 lib/Lampcms/String/HTMLStringParser.php
@@ -274,6 +274,7 @@ public function unhilight(){
}
+
/**
*
* Parse text nodes and replace text that looks like
View
5 lib/Lampcms/TagsTokenizer.php
@@ -55,10 +55,7 @@
/**
- * Parser of title of one question
- * title is tokenized and array is stored
- * in QUESTION_TITLE_TAGS
- *
+ * Parser of tags of one question
*
* @author Dmitri Snytkine
*
View
2 lib/Lampcms/TitleTokenizer.php
@@ -55,8 +55,6 @@
/**
* Parser of title of one question
- * title is tokenized and array is stored
- * in QUESTION_TITLE_TAGS
*
*
* @author Dmitri Snytkine
View
20 lib/Lampcms/User.php
@@ -659,14 +659,30 @@ public function getReputation(){
}
+ /**
+ * Get Location of user based on GeoIP data
+ * (or data
+ * that user has entered in profile, which will
+ * override the GeoIP data that we get during
+ * the registration)
+ *
+ * @return string
+ */
public function getLocation(){
$country = $this->offsetGet('country');
$state = $this->offsetGet('state');
$city = $this->offsetGet('city');
+ $hasCity = false;
$ret = '';
- if(!empty($city) && !empty($state)){
- $ret .= $city.', '.$state;
+
+ if(!empty($city)){
+ $hasCity = true;
+ $ret .= $city;
+ }
+
+ if(!empty($state) && !\is_numeric($state)){
+ $ret = ($hasCity) ? ', '.$state : $state;
}
if(!empty($country)){
View
10 lib/Lampcms/Utf8String.php
@@ -1164,13 +1164,6 @@ public function htmlspecialchars(){
}
- public function stripTags(array $aAllowed = null){
- $ret = \strip_tags($this->string, $aAllowed);
-
- return $this->handleReturn($ret);
- }
-
-
public function htmlentities(){
$ret = \htmlentities($this->string, ENT_NOQUOTES, 'UTF-8', false);
@@ -1195,8 +1188,7 @@ public function htmlentities(){
*
* @return object of this class
*/
- public function toHtmlEntities()
- {
+ public function toHtmlEntities(){
}
View
1 lib/Lampcms/WebPage.php
@@ -467,6 +467,7 @@ protected function initPageVars(){
$this->addMetaTag('fb', ('' !== (string)$Viewer->getFacebookToken()) );
$js = (true === LAMPCMS_DEBUG) ? '/qa.js' : '/min/qa_'.JS_MIN_ID.'.js';
+ //$js = (true === LAMPCMS_DEBUG) ? '/temp1.js' : '/min/qa_'.JS_MIN_ID.'.js';
$src = $oIni->JS_SITE.'/js'.$js;
$this->aPageVars['JS'] = $src;
View
6 tests/bootstrap.php
@@ -56,7 +56,7 @@
* LampcmsArray X
* ArrayDefaults X
* String X
- * Utf8String
+ * Utf8String X
* Dom\Document
* String\HTMLString
* String\HTMLStringParser
@@ -71,6 +71,7 @@
* Dispatcher
* HtmlSafe
* Template
+ * Validate
*
* User X
* Answer X
@@ -89,7 +90,7 @@
* AnswerParser
* QuestionParser
*
- * Validate
+ *
* Acl
* Base
* UserAuth
@@ -193,6 +194,7 @@ function fastcgi_finish_request(){}
require $lampcmsClasses.'Object.php';
require $lampcmsClasses.'SplClassLoader.php';
require LAMPCMS_PATH.DIRECTORY_SEPARATOR.'Points.php';
+require LAMPCMS_PATH.DIRECTORY_SEPARATOR.'Mycollections.php';
function d($message){}
View
BIN www/images/media.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN www/js/min/clipboard.swf
Binary file not shown.
View
273 www/js/min/qa_05312011.js
@@ -0,0 +1,273 @@
+/**
+ * @author Dmitri Snytkine
+ * @copyright Dmitri Snytkine
+ */
+var oSL={Regform:function(){}};var $Y=YAHOO,$D=YAHOO.util.Dom,$C=$D.getElementsByClassName,$CONN=YAHOO.util.Connect,$=YAHOO.util.Dom.get,$LANG=YAHOO.lang,$COOKIE=YAHOO.util.Cookie,$J=YAHOO.lang.JSON,$W=YAHOO.widget,$L=YAHOO.log;LampcmsException=function(message,exceptionName){this.message=message;this.name=exceptionName||"LampcmsException";};oAjaxObject={handleSuccess:function(o){var eLastDiv,json,sDoc,sTpl,errDiv,strMessage='',eLogin=$("loginHead"),strContentType=$LANG.trim(o.getResponseHeader["Content-Type"]);switch(strContentType){case'text/json; charset=UTF-8':case'text/javascript; charset=UTF-8':try{json=$J.parse(o.responseText);}catch(e){alert("Invalid json data in responceText "+$LANG.dump(e)
++" strContentType "+strContentType+"<br>oRespnose: "
++$LANG.dump(o.responseText));}
+switch(true){case json.hasOwnProperty('exception'):alert(json.exception);break;case json.hasOwnProperty('redirect'):window.location.assign(json.redirect);break;case json.hasOwnProperty('message'):eLogin.innerHTML=json.message;oSL.fColorChange(eLogin,'#00FF00','#FFFFFF');break;case json.hasOwnProperty('quickreg'):eLastDiv=document.createElement('div');eLastDiv.innerHTML=json.quickreg;document.body.appendChild(eLastDiv);oSL.Regform.getInstance().show();break;}
+break;}},handleFailure:function(o){alert($LANG.dump(o));}};oSL={toString:function(){return'object oSL';},getQuickRegForm:function(){if(oSL.Regform&&oSL.Regform.hasDialog()){oSL.Regform.getInstance().show();}else{$CONN.asyncRequest("GET","/index.php?a=getregform",oSL.oCallback);}},hideRegForm:function(){if(oSL.Regform){oSL.Regform.getInstance().hide();window.location.reload();}
+return false;},getMeta:function(sMetaName,bAsElement){$L('182 looking for meta tag '+sMetaName);var el,i,aMeta=document.getElementsByTagName('meta');$L('43 '+$LANG.dump(aMeta)+' total metas: '+aMeta.length);if(!aMeta){$L('45 no meta tags in document','error');return false;}
+for(i=0;i<aMeta.length;i+=1){if(aMeta[i].name&&(aMeta[i].name===sMetaName)&&aMeta[i].content){if(bAsElement){el=aMeta[i];$L('213 meta tag element '+el);return el;}
+return aMeta[i].content;}}
+return false;},getToken:function(){$L('166 getToken');var token=this.getMeta('version_id');return token;},isLoggedIn:function(){$L('64 this is: '+this);var ret,uid=this.getMeta('session-uid');$L('148 uid: '+uid);ret=(uid&&(uid!=='')&&(uid!=='0'));$L('66 ret: '+ret);return ret;},getTZO:function(){var tzo,nd=new Date();tzo=(0-(nd.getTimezoneOffset()*60));return tzo;},setTZOCookie:function(){$L('109 this is: '+this);var tzo=this.getTZO();$L('117 tzo: '+tzo);$COOKIE.set("tzo",tzo,{path:"/"});},oCallback:{success:oAjaxObject.handleSuccess,failure:oAjaxObject.handleFailure,scope:oAjaxObject},fAddIcon:function(s,b){var el=(typeof(s)==='string')?$(s):s;if(!this.eLoader){this.eLoader=document.createElement("img");this.eLoader.src='/images/ajax-loader.gif';this.eLoader.id="loadericon";}
+if(this.eLoader){if(b&&b===true){el.innerHTML='';}
+el.appendChild(this.eLoader);}},fRemoveIcon:function(){if(this.eLoader&&this.eLoader.parentNode){$L('include.js 118 eLoader parent: '+this.eLoader.parentNode
++' id: '+this.eLoader.parentNode.id);this.eLoader.parentNode.removeChild(this.eLoader);}},fCompareForms:function(oNewForm,oOldForm){$L($CONN.setForm(oNewForm));$L($CONN.setForm(oOldForm));if($CONN.setForm(oNewForm)===$CONN.setForm(oOldForm)){return true;}
+return false;},fColorChange:function(el,sFromColor,sToColor){$L('starting fColorChange for '+el);var myChange,curBg,myChangeBack,element=(typeof el==='string')?$(el):el,sToColor=(sToColor&&typeof sToColor==='string')?sToColor:'#FF0000',sFromColor=(sFromColor&&typeof sFromColor==='string')?sFromColor:'#FFFFFF';$L('element is: '+element);if(element){curBg=$D.getStyle(element,'background-color');$D.setStyle(element,'background-color',sFromColor);myChange=new YAHOO.util.ColorAnim(element,{backgroundColor:{to:sToColor}});myChangeBack=function(){element.style.backgroundColor=curBg;};myChange.onComplete.subscribe(myChangeBack);myChange.animate();}},fParseQf:function(json){$L($LANG.dump(json));var strMessage='',aAvatars,i=0,el,formField,eMessageDiv=$('qfe');switch(true){case json.hasOwnProperty('exception'):if(json.hasOwnProperty('errHeader')){strMessage+='<u>'+json.errHeader+'</u><br>';}
+eMessageDiv.innerHTML='<div id="qfErrors">'+strMessage
++json.exception+'</div>';break;case json.hasOwnProperty('errors'):if(json.hasOwnProperty('errHeader')){strMessage+='<u>'+json.errors.errHeader+'</u><br>';}
+eMessageDiv.innerHTML='<div id="qfErrors">'+strMessage
++json.errors.errMessage+'</div>';this.aEls=[];for(formField in json){if(json.hasOwnProperty(formField)&&json[formField].hasOwnProperty('err')){el=$('a'+formField);if(el){el.style.backgroundColor='#FFFFCC';this.aEls.push(el);}}}
+this.fColorChange('qfmessage','#FF0000','#FFFFFF');break;}
+if(oSL.oFrm&&oSL.oFrm.elBtnSubmit){oSL.oFrm.elBtnSubmit.disabled=false;}
+var elPbar=$('progressBar'),elAvatarField=$('aavatar');if(elPbar){elPbar.parentNode.removeChild(elPbar);}
+if(elAvatarField){$D.setStyle(elAvatarField,'display','block');}}};oSL.tweet=(function(){var oDialog;var siteTitle=oSL.getMeta('site_title');var siteUrl=oSL.getMeta('site_url');var token=oSL.getToken();return{getInstance:function(){var eRootDiv,oFrm,siteDescription,sForm;if(!oDialog){if(!$('dialog1')){sForm='<div class="hd">Please enter your information</div>'
++'<div class="bd"><hr/>'
++'<form method="POST" action="/index.php">'
++'<input type="hidden" name="a" value="tweet">'
++'<input type="hidden" name="token" value="'
++token
++'">'
++'<h3 class="tweetdlg">Tweet this:</h3>'
++'<div class="clear"></div>'
++'<textarea cols="44" rows="5" name="tweet">'
++$('twinvite').title
++' '
++siteTitle
++' '
++siteUrl
++'</textarea>'
++'<div class="clear"></div>'+'</form>';eRootDiv=document.createElement('div');eRootDiv.id='dialog1';document.body.appendChild(eRootDiv);eRootDiv.innerHTML=sForm;}
+oDialog=new $W.Dialog("dialog1",{width:"30em",fixedcenter:true,visible:false,constraintoviewport:true,buttons:[{text:"Submit",handler:function(){this.submit();},isDefault:true},{text:"Cancel",handler:function(){this.cancel();}}]});oDialog.beforeSubmitEvent.subscribe(function(){$L('before submit tweet');});oDialog.callback={success:function(o){alert('Tweet sent');},failure:function(o){alert('Tweet not sent');}};oDialog.setHeader("Invite Your Friends");oDialog.render(document.body);}
+return oDialog;},destroy:function(){if(oDialog){oDialog.destroy();}},hide:function(){if(oDialog){oDialog.hide();}},setTextArea:function(s){},toString:function(){return'object oDialog created with oSL.dialog()';}};})();oSL.Regform=(function(){var errDiv,oDialog,aDialogs={},oPrompt,handleSubmit=function(){this.submit();},handleCancel=function(){$L('41 clicked on Cancel this is: '+this);oSL.Regform.getPrompt().show();},handleContinue=function(){this.hide();},handleExit=function(){var eAvatar=$('regext');$L('handling exit');this.hide();oSL.Regform.getInstance().hide();if(eAvatar){$COOKIE.set("dnd","1",{path:"/"});}},handleSuccess=function(o){var response,i,aButtons,oMyDialog=oSL.Regform.getInstance();oSL.Regform.enableButtons();aButtons=oSL.Regform.getInstance().getButtons();for(i=0;i<aButtons.length;i+=1){$L('button '+i+' is '+aButtons[i]);}
+response=o.responseText;try{json=$J.parse(o.responseText);switch(true){case(json.hasOwnProperty('exception')):setError(json);break;case(json.hasOwnProperty('action')&&(json.action==='done')):oMyDialog.setHeader('Welcome!');oMyDialog.setFooter('');oMyDialog.setBody(json.body);break;}}catch(e){alert("Invalid json data in responceText "+$LANG.dump(e)+"Respnose: "+$LANG.dump(o.responseText));}},handleFailure=function(o){oSL.Regform.enableButtons();oSL.Regform.getInstance().setBody('<p>boo hoo, something is wrong</p>');$L('47 fail ','warn');},setError=function(oError){var i,errDiv=$('form_error'),aInputs,message=oError.exception,oRegform=oSL.Regform.getInstance(),myForm=oRegform.form;errDiv.innerHTML=message;oSL.fColorChange(errDiv,'#FFFFFF','#FF0000');if(oError.type&&('LampcmsCaptchaLimitException'===oError.type)){$LANG.later(2000,oRegform,'destroy');}
+if(oError.hasOwnProperty('fields')){aInputs=oError.fields;for(i=0;i<aInputs.length;i+=1){if(myForm.hasOwnProperty(aInputs[i])){myForm[aInputs[i]].style.backgroundColor="#CCFFCC";}}}
+if(oError.hasOwnProperty('captcha')){if(oError.captcha.public_key&&oError.captcha.hncaptcha&&oError.captcha.img){myForm.public_key.value=oError.captcha.public_key;myForm.private_key.value='';myForm.hncaptcha.value=oError.captcha.hncaptcha;$('imgcaptcha').innerHTML=oError.captcha.img;}}else{if(myForm.private_key&&oError.type){myForm.private_key.disabled=true;}}},aButtonsDone=[{text:"<-- Return to page",handler:function(){alert('this is '+this);},isDefault:true},{text:"Go to Profile editor -->",handler:function(){alert('go to profile');}}],startProgress=function(o){oSL.Regform.disableButtons();};return{getInstance:function(){$L('cp 13','warn');if(!oDialog){$L('cp 15','warn');$D.removeClass("regdiv","yui-pe-content");$L('cp 17','warn');oDialog=new $W.Dialog("regdiv",{width:"50em",fixedcenter:"contained",visible:false,constraintoviewport:false,hideaftersubmit:false,draggable:true,close:false,modal:true,buttons:[{text:"Create Your Account",handler:handleSubmit,isDefault:true},{text:"Cancel",handler:handleCancel}]});oDialog.callback={success:handleSuccess,failure:handleFailure};oDialog.validate=function(){var at,checkEmail,tzo,message,aInputs=[],myForm=this.form,nd=new Date(),data=this.getData();$L('data: '+$LANG.dump(data));tzo=(0-(nd.getTimezoneOffset()*60));if((myForm.tzo)&&(tzo)){myForm.tzo.value=tzo;}
+checkEmail=function(str){var at="@",dot=".",lat=str.indexOf(at),lstr=str.length,ldot=str.indexOf(dot);if(str.indexOf(at)===-1||str.indexOf(at)===0||str.indexOf(at)===lstr){return false;}
+if(str.indexOf(dot)===-1||str.indexOf(dot)===0||str.indexOf(dot)===lstr){return false;}
+if(str.substring(lat-1,lat)===dot||str.substring(lat+1,lat+2)===dot){return false;}
+if((str.indexOf(at)===-1)||(str.indexOf(at,(lat+1))!==-1)||(str.indexOf(dot,(lat+2))===-1)||(str.indexOf(" ")!==-1)){return false;}
+return true;};switch(true){case(data.email===""):message="Please enter email address";aInputs.push('email');break;case(data.username===""):message="Please enter Username";aInputs.push('username');break;case(data.hasOwnProperty('private_key')&&(""===data.private_key)):message="Please enter the text from image";aInputs.push('private_key');break;case(!checkEmail(data.email)):message="Email address appears to be invalid<br>Please enter a valid Email";aInputs.push('email');break;default:return true;}
+setError({exception:message,fields:aInputs});return false;};oDialog.asyncSubmitEvent.subscribe(function(type,args){var connectionObject=args[0];startProgress();});oDialog.render($('lastdiv'));}
+return oDialog;},toString:function(){return'object oSL.Regform';},getPrompt:function(){if(!oPrompt){$L('making prompt');oPrompt=new $W.SimpleDialog("simpledialog1",{width:"300px",fixedcenter:true,zindex:99,visible:false,draggable:false,close:true,modal:true,text:"Do you want to continue?",icon:$W.SimpleDialog.ICON_ALARM,constraintoviewport:true,buttons:[{text:"Continue registration",handler:handleContinue,isDefault:true},{text:"Exit registration",handler:handleExit}],effect:[{effect:$W.ContainerEffect.FADE,duration:0.2}]});oPrompt.setHeader("Are you sure?");oPrompt.render(document.body);}
+$L('176 oPrompt: '+oPrompt,'warn');return oPrompt;},disableButtons:function(){var i,aBtns;$L('105 this is: '+this,'warn');if(oDialog){aBtns=oDialog.getButtons();for(i=0;i<aBtns.length;i+=1){aBtns[i].set('disabled',true);}}},enableButtons:function(){var i,aBtns;$L('105 this is: '+this,'warn');if(oDialog){aBtns=oDialog.getButtons();for(i=0;i<aBtns.length;i+=1){aBtns[i].set('disabled',false);}}},setButtonsDone:function(){oDialog.cfg.queueProperty("buttons",aButtonsDone);},destroy:function(){if(oDialog){oDialog.destroy();}},hasDialog:function(){if(oDialog&&oDialog.body){return true;}
+return false;}};})();YUI({}).use('node','dump','event','escape','gallery-storage-lite','gallery-overlay-extras','dd-plugin','anim','transition','yui2-container','yui2-editor','yui2-resize','io-form','json','jsonp','imageloader','autocomplete','autocomplete-filters','autocomplete-highlighters','gallery-node-tokeninput','cookie',function(Y,result){var YAHOO=Y.YUI2,TTT2=Y.all('.ttt2'),ttB,ttB2,oMetas={},loader,getMeta,setMeta,getToken,ensureLogin,initTooltip,getEditedText,previewDiv,preview,MysubmitForm,showDeleteForm,showRetagForm,showShredForm,showCommentForm,addAdminControls,checkExtApi,showFlagForm,showCloseForm,codeButtons={},initAutoComplete,getAlerter,isModerator,isEditable,initFBSignup,Twitter,showEditComment,setToken,getReputation,isLoggedIn,getViewerId,oCTabs={},foldGroup,revealComments,dnd=false,res=Y.one('#body_preview'),write=function(str){var d=new Date();str+=' :: '+d.toTimeString();if(res){res.set('innerHTML',str);}},saveToStorage=function(){Y.StorageLite.on('storage-lite:ready',function(){var tags,html=editor.saveHTML();saveTitle();saveTags();Y.StorageLite.setItem(getStorageKey(),html);write('Draft saved..');});},commentTip='<tr><td></td><td colspan="2" class="lighttext">Enter at least 16 characters<br>Allowed mini-Markdown formatting: _italic_ and **bold**</td></tr>',eForm=Y.one('.qa_form'),eAskTA,reputation,viewerId=null,bModerator=1,eInputTitle,eInputTags,eTagsHint,eBodyHint,eTitleHint,aComHand,oVotes={},editor,oAlerter,loadingMasks=[],getStorageKey=function(){var formName;if(!eForm){return null;}
+return eForm.get('name');},initTagInput=function(el){var input=(el)?el:Y.one("#id_tags");if(input){Y.one(input).plug(Y.Plugin.TokenInput,{delimiter:' '});}},mmdDecode=function(s){var bold,ret,em=/(\<em>|\<\/em>)/g;bold=/(\<strong>|\<\/strong>)/g;ret=s.replace(em,'_');ret=ret.replace(bold,'**');return ret;},_handleWindowClose=function(){var el=this.currentElement[0];el=new Y.Node(el);if(el&&el.hasClass('yui-media')){el.remove();}
+Y.one("#embed_url").set('value','');Y.Event.purgeElement("#btn_addvideo");this.nodeChange();},parseUri=function(sourceUri){var uriParts,i=0,uri={},uriPartNames=["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];uriParts=new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri);for(i=0;i<10;i++){uri[uriPartNames[i]]=(uriParts[i]?uriParts[i]:"");}
+if(uri.directoryPath.length>0){uri.directoryPath=uri.directoryPath.replace(/\/?$/,"/");}
+return uri;},getYTVidId=function(url){var myID,getID,path,a=parseUri(url),re=/(?:v=)([^&\?]*)(?:[&]*)/gi;path=a['path'];if(path.length<2||(-1===path.indexOf('/'))){return false;}
+path=path.substr(1);if('watch'!==path){if(/(\?|&)/.test(path)){return false;}
+return path;}else if(!a.hasOwnProperty('query')||!a['query']||a['query'].length<3){return false;}else{myID=re.exec(a['query']);if(!myID||myID.length<2||myID[1].length<1){return false;}
+return myID[1];}},parseYTInput=function(){var url,apiURL='http://gdata.youtube.com/feeds/api/videos/{id}?v=2&alt=jsonc&callback=',handleJSONP,imgId,myinput1=(Y.one("#embed_url"))?Y.one("#embed_url").get('value'):null;handleJSON