Monday, November 22, 2010
Борис Гребенщиков
Psi (Пси) - Аквариум (CD)
Сварог
/////////////////
Bardo - Русско-Абиссинский Оркестр (CD)
/////////////////
Прибежище - БГ, Gabroelle Roth & The Mirrors (CD)
Example of using fastcgi_finish_request() in php 5.3
http://php-fpm.org/
fastcgi_finish_request() is extremely powerful optimization trick. It's even more powerful if you use it together with closure functions in php 5.3
This is how I started using it now:
suppose I have a method somewhere in the middle of my script that has to call some API, let's say Facebook API, download recent user data and if something changed in user's Facebook profile, then update my database.
Since facebook API response time is unpredictable, I don't want to hold up the page load waiting, so I want to defer this call till after the page is rendered.
But how do I do this if the Facebook api check is somewhere in the middle of my script and the page has not finished rendering yet?
The way this can be done is with closure.
Pass anonymous function as callback to register_shutdown_function() like this:
This script snipped is somewhere inside a class method which is called about half way through the script:
Note: the d() and e() functions are for logging debug and error messages,
you can ignore these...
$oAuthFB = new clsExternalAuthFb($oGlobal, $sAppId, $aCookieParams);
register_shutdown_function(function() use ($oAuthFB){
try{
d('before facebook auth post precessing $oAuthFB: '.$oAuthFB);
$oAuthFB->getFbData()->getFacebookUserObject();
d('after facebook auth post precessing');
} catch (Exception $e){
e('Unable to run post processing of FB data: '.$e->getFile().' '.$e->getLine().' '.$e->getMessage());
}
});
See what's going on here? I am basically cutting out the piece of code and sticking it to be executing all the way at the end of the script, after the php is done parsing everything else.
The only thing left to do is to add
fastcgi_finish_request();
somewhere after the output is sent to browser.
For example, in my index.php I have
$oController = new Controller();
echo $oController->getHtml();
fastcgi_finish_request();
That would ensure that all registered shutdown functions are run after the output is sent.
Because of the closure, the context, the object $oAuthFB is remembered it the state it was just before the callback anonymous function was created, all instance variables are in place, so the shutdown function is executed with the complete context of $oAuthFB object in the same state it was back in the middle of that method where I registered the shutdown callback.
This is extremely powerful way to basically cut out the code from the middle of you script and defer its execution till after the page has been rendered.
Tuesday, November 16, 2010
To update classes to make use of php 5.3 static magic
Even better have clsEmailRecord::factory($oRegistry)->get($email)
Then we can also create new record this way! it should extend clsMongoDocument
Just extend static class MongoDocument then use get_calling_class()
and call_static() magic
then it will be as easy as just
creating blank classes than extend clsMongoDocument
Heck, we can even make it serializable, just
use clsRegistry::getInstance() in unserialize and we good to go
clsMongoDocument::getByEmail($email)
clsMongoEmail::getByEmail($oMongo, $email)
clsMongoEmail::create($oMongo, $aData);
clsMongoEmail::factory($oMongo, $aData); the normal object
Monday, October 18, 2010
How to setup Apache with php on home Windows PC
It has own installer, so its very easy to download/install
Don't install Apache from official Apache website, MAMP is much easier and it installs php, apache and mysql all at once and has a nice little control panel where you can start and stop the server.
You can still install extra php pecl modules later by just copying the .dll files to appropriate dir, I'll show you how to do it later.
Sunday, September 26, 2010
Tuesday, September 21, 2010
Php class for simulating Auto Increment in MongoDB
/**
* Static class for generating and
* maintaining records of per-collection
* auto-increment ids
*
* @author Dmitri Snytkine
*
*/
class MongoIncrementor
{
/**
* 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 = 'Autoincrement';
/**
* The pseudo auto increment handling is done
* by storing collectionName => id
* in Autoincrements collection
*
* We get value, increment it and resave it
* but watch for Errors/Exceptions in order
* to prevent race condition
*
* @param obj $db must pass object of type MongoDB
*
* @param string $collName which collection this id
* is for. This has nothing to do with the name of the collection
* where these generated sequence numbers are stored.
* For example if you need the next id for collection 'STUDENTS',
* then you pass the 'STUDENTS' as $collName value
* This way different values of 'next id' are maintained
* per collection name
*
* @param int initialId if there is no record
* for the collection yet, then start the increment counter
* with this value.
*
* @param int $try this is used for recursive calling this method
* You should NEVER pass this value yourself
*
* @return int value of next id for the collection
*/
public static function nextValue(MongoDB $db, $collName, $minId = 0, $try = 1)
{
if( $try > 100 ){
throw new RuntimeException('Unable to get nextID for collection '.$collName.' after 100 tries');
}
$prevRecordID = null;
$coll = $db->selectCollection(self::COLLECTION_NAME);
$coll->ensureIndex(array('coll' => 1, 'id' => 1), array('unique' => true));
/**
* We use find() instead of findOne() for a reason!
* It's just more reliable this way
*/
$cursor = $coll->find(array('coll' => $collName))->sort(array('id' => -1))->limit(1);
if($cursor && $cursor->hasNext()){
$a = $cursor->getNext();
$prevRecordID = $a['_id'];
} else {
$a = array('coll' => $collName, 'id' => $minId);
}
$prevID = $a['id'];
$newId = ($a['id'] + 1);
/**
* Remove the _id from record, otherwise
* we will be unable to insert
* a new record if it already has the same _id
* This way a new _id will be auto-generated for us
*/
unset($a['_id']);
$a['id'] = $newId;
/**
* Wrapping this inside try/catch so that if
* another process inserts the same value of coll/id
* between the time we selected and updated this
* it will throw exception or return false and then
* we will try again up to 100 times
*
* In Case of duplicate key Mongo throws Exception,
* but just in case it will change in the future,
* we also test if $ret is false
*/
try{
/**
* Using fsync=>true because its very critically important
* to actually write the row to disc, otherwise if database
* goes down we will lose the correct value
* of our increment ID
*/
$ret = $coll->insert($a, array('fsync' => true));
if(!$ret){
$try++;
return self::nextValue($db, $collName, $initialId, $try);
}
/**
* Insert successfull
* now delete previous record(s)
*/
if(null !== $prevRecordID){
$removed = $coll->remove(array('_id' => $prevRecordID)); //, array('fsync' => true) // not very important to fsync
}
} catch (MongoException $e){
$try++;
return self::nextValue($db, $collName, $initialId, $try);
}
return $newId;
}
}
Monday, September 20, 2010
In Java always use braces
This is funny: from Standford Java course professor Mehram Sahami
In Java programming follow the rule of orthodontist:
"You need braces"
Orthodontist will always say this to EVERY patient!
What he means is: don't write a shorthand "no braces" code blocks,
like these:
if(num % 2 == 0)
println ('num is even');
always use braces:
if(num % 2 == 0){
println ('num is even');
}
It's just easier for another programmer to read.
Saturday, September 18, 2010
random.h library in C++ but not in php
RandomChance(doublce probability)
You pass it a probability chance like 0.25
and the it will return true 1/4 of the times, other times
if will return false.
There is no such function in php, so that's one more area where php could improve,
perhaps add the "Random" class into SPL and include all the functions from the C++ random.h
Strings in Java, php and C++
Strings in php are also mutable
Strings in Java are immutable, but there is a string builder class
to make string building in mutable fashion.
Sunday, September 12, 2010
sorry, you must have a tty to run sudo
check the /var/log/secure log
If you are seeing this message:
"sorry, you must have a tty to run sudo"
Then you should edit /etc/sudoers file and comment out this line:
Defaults requiretty
(just add the # in front of this line and save the file)
This this will fix your sudo error.
Saturday, September 11, 2010
Unable to login to mysql as root user access denied
Could not login to mysql as root user
Kept getting messages access denied for user 'root'@'localhost'
using password yes
I tried with and without the password for root user
I then tried instructions for resetting the mysql root user password from
mysql website
Nothing worked!
Finally what I did was:
Stopped mysql
/etc/rc.d/init.d/mysqld stop
Deleted everything from /var/lib/mysql
so the default database 'mysql' was removed
Then reinstalled mysql and mysql-server from yum
yum reinstall mysql
yum reinstall mysql-server
Then started the mysql server again
/etc/rc.d/init.d/mysqld start
This time the startup automatically created
brand new 'mysql' database.
This time I was able to login to mysql with as root user and without a password:
/usr/bin/mysql -u root
Once Logged in I changed password:
mysql> UPDATE mysql.user SET Password = PASSWORD('newpwd')
-> WHERE User = 'root';
mysql> FLUSH PRIVILEGES;
Done!
How to build and install Postfix on 64 Bit CentOS or RedHat
64 bit Linux (CentOS or RHEL)
First make sure you have Mysql and pcre libraries installed, in not, then install them
#yum install mysql-devel pcre-devel
Then download the latest source for Postfix, cd into the Postix directory,
it should have several fines, and MUST have Makefile.init
From this directory type:
make -f Makefile.init makefiles \
'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DHAS_PCRE -I/usr/include' \
'AUXLIBS=-L/usr/lib64/mysql -lmysqlclient -lz -lm -L/usr/lib64 -lpcre'
Then type make
then "make install"
if will ask several questions, just accept defaults by hitting "Enter"
This is it
Now stop and restart your sendmail
/etc/rc.d/init.d/sendmail stop
/etc/rc.d/init.d/sendmail start
Now check to make sure that mysql and pcre are on the list
of supported posfix maps:
type: /usr/sbin/postconf -m
You should see mysql and pcre in the list of maps
Of cause make sure to properly edit the configuration files
in the /etc/postfix directory.
That's a whole new big article (more like a small book), so I am not going to explain about postix
configuration here.
Friday, September 10, 2010
php 5.3.3 skipping incompatible /usr/lib/mysql/libmysqlclient.so
skipping incompatible /usr/lib/mysql/libmysqlclient.so when searching for -lmysqlclient
You just need to specify the correct path to where the 64bit libs are for mysql
Do this before running ./configure:
export LDFLAGS=-L/usr/lib64/mysql
Sunday, August 29, 2010
Php suddenly died, no error messages
A very nasty error occurs in php is you declare the same instance variable more than once
in the same class (you know, if the beginning of the class file)
or for that matter the method with the same name is declared twice in the same class
This is an easy mistake to make, but it causes the php to die with very little
error. In fact, depending on your error reporting level you may never even see
any errors in the error log, no errors on the screen, nada!
All you will see is that suddenly your script is dead. I mean completely dead, objects
not even instantiating.
This is nasty, so watch our for that!
Saturday, August 28, 2010
How to make php DOMDocument Serializable
That is, if you run $myDOM = serialize($oDOM), then unserialize($myDOM)
you will get back the object of type DOMDocument, but the data
will be lost, so you will basically get back the empty DOM Document,
not even the root element will be there, nada!
But it's easy to fix that. All you have to do is
extend the DOMDocument and implement Serializable interface
This is how you do it:
class MyDOMDocument extends DOMDocument implements Serializable
{
public function __construct(){
parent::__construct();
}
public function serialize(){
$s = $this->saveXML();
return $s;
}
public function unserialize($serialized)
{
$this->loadXML($serialized);
}
}
Ok, now if you serialize() and then unserialize() you will get back
the object of type MyDOMDocument and it will have the same data
as it had before serialization.
Of cause this will only work with PHP 5.2 or better and SPL libraries enabled (they are by default in php5)
Friday, August 27, 2010
Weird stuff with ArrayObject after exchangeArray()
then set extra property in object,
then exchangeArray() with new array
What happends to that extra property?
Right now it looks like that property is gone, which is odd
because only the internal array should be changed but it looks
like as if the whole object has been recreated.
Interesting to know. I must do an experiment and
get a definitive answer.
Monday, August 9, 2010
Common mistake that prevents Google from using your sitemap.xml file
(here: http://sitemaps.org/protocol.php#lastmoddef )
the format of the lastmod element in sitemaps file should be in the W3C Datetime format
but the actual time can be omitted.
One common mistake people make when generating sitemap file is to make the lastmod value in a format like this: YYYY-DD-MM HH:MM:SS
This is a wrong format and will not be understood by Google.
The correct W3C timestamp format is quite ugly, and looks like this:
(example) 1997-07-16T19:20:30.45+01:00
The best advice I can give you is to remove the HH:MM:SS and only leave the date part of the datetime, like this for example: 2010-03-23
This format is understood by all search engines and will not cause any problems.
Tuesday, July 6, 2010
How to get LogCat view pane in Eclipse Android SDK
Window > Show View > Other
Then expand Android and then select LogCat
You may also select other useful Views like Threads and Emulator Controls
Tuesday, June 29, 2010
Monday, June 28, 2010
Firefox browser freezes up a lot
This is what it feels like when using Firefox with many tabs opened. I don't mean too many, I mean like 5 or 6 tabs, especially if one tab was using flash player like maybe you were watching youtube in one tab.
I just keep restarting Firefox like 5 times a day or more, while I never have to restart the Chrome, I mean in days and even weeks, my Chrome is just open, many tabs are running, no problem.
Sunday, June 6, 2010
Best source for Apache server discussion lists
If you want to keep up with all the discussions about these projects, there is a superb web based archive for the Apache projects mailings lists and forums, here is the url:
apacheserver.net
Check it out.
Sunday, May 30, 2010
New blog for Apache server admin tips
Here is the url: http://apacheservertips.blogspot.com/
Sunday, March 28, 2010
SQL_BUFFER_RESULT may return stale result
While this may speed up the selects (sometimes by a lot), it will also get you the cached result, in some cases the result may be stale, not reflecting the changes that took place after the previous result was cached.
This was probably not intended to be like that, may be just a weird behavior when using PDO and somehow temporary table that was created for that BUFFER_RESULT was not removed. I don't know why, I am not a mysql developer, I just know what I see - when using SELECT HIGH_PRIORITY SQL_BUFFER_RESULT .... with php PDO class, the result may be stale.
Thursday, March 25, 2010
MySQL table locks up
Saturday, March 20, 2010
Looks like memcached was freezing Apache 2.2
I think this was causing the unexplained freezing of Apache 2.2
It was very difficult to track down the cause of Apache just freezing - no timeout error, no errors at all, just sitting there waiting forever for page to load.
After trying everything else, I decided to comment out loading memcached php extension and only load and use the good old reliable memcache extension.
Some tests claim that memcached is faster than memcache, but the difference is basically in single milliseconds, like who cares.... Not important when you usually saving couple of seconds worth of complex sql selects (some long sql selects that have several LEFT JOINS sometimes take 15 seconds when mysql has to create temporary table).
Anyway, I don't know if the problem was that some of the sites on the server were using memcache and some were using memcached, so I needed to load both extensions in php.ini
After ditching the memcached and only using memcache, the problems with Apache seemed to go away. Keeping my fingers crossed, so far so good.
Wednesday, March 17, 2010
Eclipse PDT freezes like a cunt
Google friend connect integration thoughts
but user has unjoined your site, then when you
request the data from gfc server you get the 401 error status with this message:
Anonymous requests are not allowed to fetch data
Error 401
This is an easy way to know that the fcauth cookie is not good anymore and you should delete it from the table in case you are storing that value in a table.
It also indicates that user is not a member of your site via his GFC thingy.
What is the best way to auto-login GFC user to your site? The oblivious choice is via fcauth cookie, get data from GFC server and login/create oViewer object.
But this can slow down the page load in case the GFC server is slow to respond.
A faster choice is to log him in via your own uid cookie, then add some DIV tag to your page and then have JavaScript on your page to make ajax call back to your server, on your server check with GFC server and upon success return a couple of links to the browser. The links will be to 'Friend connect settings' and 'invite friends', then have your JavaScript callback to add these links to the page
If GFC auth in unsuccessful then remove fcauth cookie from user record, indicating that user in not subscribed to your site anymore. In this case have your http response to delete the fcauth cookie so you don't have to go through this again.
The downside to this is that you have to make an extra request to server right after the page renders (via ajax this time)
Tuesday, March 16, 2010
php setcookie for array of cookie
is says you can use setcookie() to set array of cookies
http://us2.php.net/manual/en/function.setcookie.php
This is convenient, but also a bit misleading. It leads you to believe that you are setting just one cookie with the array of values, but in fact the browser actually setting new cookie for each new array element.
So you may be setting 10 different cookies and not even knowing about it. A better solution is to set just one cookie with the name/value pairs like
userid=12331&name=john&group=admins&firstvisit=20091010
You can use http_build_query() to build a string that will then become your cookie value.
See, it looks similar to url.
To get values from the cookie, just get the cookie using the
$val = $_COOKIE['cookiename'];
and then:
parse_str($val, $aVars);
now the $aVars contains the name => value pairs
Just treat the values with caution just like any other user-passed variables. Validate, sanitize, whatever you normally do with values passed by user.
Friday, March 12, 2010
username-less paradigm
Everyone is known by their real first and last name. So Facebook API in most cases does not return value for username because it's optional and most people never set it up.
I just find this unusual but at the same time they may be on to something.
This makes it so much easier to integrate the Facebook Connect into your existing login system - because there could not be any name collisions with existing users in your database
Wednesday, March 10, 2010
Php can only count to 10 (sort of)
You probably used to do this $val = (int)$val;
in php as a way to be sure that $val is an integer.
Some people do this for added security, since integers cannot contain any type of
script or html tags, so it's an easy way to sort-of sanitize the string.
But.. but... but ..... but....
Php like a child that can only count to 10, can only count to 2147483647
That's right, I did not expect this either.
Any number larger than 2147483647 php just does not know!
This means when you try to case any number larger than 2147483647 to integer using (int)$val, php will just return 2147483647
This is terribly wrong, certainly should be considered a bug!
If php does not know any integers larger than 2147483647, then it should raise error when you try to convert a larger number, not return the largest number it knows!
This can cause some weird problems in your code.
In my case I discovered this bug when working with Twitter API
The Twitter has billions of status messages, so all the latest status_ids are larger than 2147483647, so I was doing what I thought was a good practice and casting these status ids to integer with (int), but php was quietly replacing all the actual values with the 2147483647
By the way, it was php version 5.2.9, which is fairly new version. I mean, I would not be surprised to see this bug in php prior to 5, but in 5.2.9?!
That's crazy.
Monday, March 8, 2010
Some near-term todos for qod site
use javascript api to see if logged in user is following question owner and if not, then add "Follow " button which will point to user server and we can follow the user of behalf of the logged in user.
Add 'Other questions by this member'
Add 'Invite friends to join' but not sure how this will work - show a list of friends or just tweet about the link?
Sunday, March 7, 2010
Normalizing utf-8 string for Twitter API
This class comes with php 5.3 but before the 5.3 you need to build the lib yourself and then install extension from pecl
Then, once you have the Normalizer class, just do this:
Normalize::normalize($string,Normalizer::FORM_C)
This is not always necessary as most utf-8 strings and chars are already "just fine", it's just that some fairly rare chars can be considered 'not normalized'.
This means that Twitter will still accept them, they will even be rendered by the end user browser in most cases, it's just that Twitter may count such chars as 2 chars instead of just one, and you know in Twitter every char counts.
Basically you really want to make sure that utf-8 strings are normalized before you send then to Twitter from your API because otherwise you may run into situation that your message unexpectedely exceeds 140 chars and will be rejected by Twitter API.
Normalize::normalize($string,Normalizer::FORM_C)
And here is the info from php
http://www.php.net/manual/en/book.intl.php
http://php.net/manual/en/class.normalizer.php
Saturday, February 20, 2010
changing value of meta tag with javascript
if you assign value of meta tag element in javascript
using the
eMeta.setAttribute('content', somenewvalue);
it will not be found if looking for for it this way:
eMeta.content but the attribute value of 'content' will actually
be set and could be seen in Firebug right away.
But it will work if just setting value by assignment, like this
eMeta.content = 'somenewval';
This is in Firefox, not sure how it will work in other browsers
Tuesday, February 16, 2010
oAuth Signin with Twitter via popup window design pattern
The DISCUSS widgets have this pattern:
Dsq.Twitter = new function() {
var that = this;
this.startTwitterConnect = function() {
var popupParams = 'location=0,status=0,width=800,height=400';
that._twitterWindow = window.open(Dsq.jsonData.settings.disqus_url + '/_ax/twitter/begin/', 'twitterWindow', popupParams);
that._twitterInterval = window.setInterval(that.completeTwitterConnect, 1000);
};
this.completeTwitterConnect = function() {
if (that._twitterWindow.closed) {
window.clearInterval(that._twitterInterval);
window.location.reload();
}
};
};
and the twitgoo.com also have very similar pattern:
TG.util.oauth = {
win: null,
timer: null,
loginUpdate: function() {
$.getJSON('/-login/check?format=json', TG.util.oauth.loginCallback);
},
loginCallback: function(data) {
if (data && data.loggedin) {
TG.util.login.update(data);
}
},
winCheck: function() {
if (!TG.util.oauth.win || TG.util.oauth.win.closed) {
window.clearInterval(TG.util.oauth.timer);
return TG.util.oauth.loginUpdate();
}
},
loginClick: function() {
TG.util.oauth.win = window.open('/-oauth-twitter/request?gotoafter=1&gotor=oauthtwitter&gotop=action%3Dwindowend',
'OAuthTwitterRequest',
'width=800,height=450,modal=yes,alwaysRaised=yes');
if (!TG.util.oauth.win) return true;
TG.util.oauth.timer = window.setInterval(TG.util.oauth.winCheck, 300);
return false;
}
};
This means that the callback url - the one that Twitter redirects to after the oAuth dance is complete contains ONLY the window.close() javascript and basically does nothing else at the browser. It's main job is do populate the oViewer object on the server so that when the main window is reloaded it will determine that user is now logged in. OK, one more thing that callback window can do is to set some sort of cookie.
I can see a legitimate reason to do this because what if user closes the browser popup window manually? Then we will never get to the part where the JS in the popup window calls the window.opener
So there is a very small chance that user will be successfully logged in but because he closed what window manually, the main window will never know.
I guess I'll go with that pattern now, after all, I've seen in on 2 well built sites and also the same pattern is recommended on Google OpenSocial developers page.
This is actually very easy to code because you don't need anything special as far as in php of the callback url, only static HTML and OK, possibly setting of cookie, but I'm not even sure that it's even necessary to set this cookie.
Monday, February 15, 2010
CakePHP pages shows ads for wedding cakes
Google shows ads for wedding cakes, birthday cakes,
even geo-targeted bakeries based on my IP address when I view the page about CakePHP
Another proof that Google is not very smart when it comes to parsing words that have more than one meaning.
Tuesday, February 9, 2010
Firefox consumes too much memory
Thursday, January 28, 2010
Google live search is shockingly stupid
Ok, I searched for "REST or RPC" which are the 2 technical terms for protocols, so I was looking for find the answer which one I should be using in my application.
So, Google added results from live twitter stream on the first page, some of them go like this "I should go get some rest"
or "the rest of the album is..."
Com'on Google, my son can write a smarter search engine - just filter out the VERY common words or at least don't show results for words that can have more than one meaning if you don't know which one of the meanings I am searching for.
What's the name for such words anyway, (words with more than one meaning)? I forgot, I better go Google it.
Thursday, January 21, 2010
Programming discussions tips
popular php and javascript projects is to keep an eye on the
mailing lists.
One good place to watch the latest lists is on this discussions site
It's updated in real time as soon as any new message arrives to any of the many programming lists they track.
There is also a way to reply, you just need to register and you good to go.
Friday, January 15, 2010
Enhances Search Results on Yahoo Serp pages
Just want to bookmark this page.
It contains valuable info on how to enhance the site markup to allow extra cool snippets on yahoo search results page - right on SERPS.
I especially like the Discussion, News and Video section, but Documents and Events and even Games look very promising too. The Games, however require them to be written in flash. I am not 100% sure but at least the example on Yahoo site is in flash.
It would be cool if Javascript games were also allowed.
Very interesting: at the bottom of the page there is a link to "Build a Custom App", so basically Yahoo also allows to build custom app and have it included in enhances SERP.
Yahoo allows microformats to hint discussion
Very interesting. Yahoo allows to add
a microsofmat or RDF to indicate that a blog with comments or a forum discussion takes place.
Yahoo will then include this data in the enhanced search results page.
http://developer.search.yahoo.
"Description Display blog or forum information directly in Yahoo! Search. Add code to indicate to Yahoo! that a discussion exists on your page, and when we next crawl your site, we'll take care of the rest. From your markup, we’ll be able to extract structured data from your site and render it automatically in an enhanced result in search results."
- SearchMonkey - Discussion (view on Google Sidewiki)
Wednesday, January 13, 2010
2 Interfaces cannot contain the same method names
implemented in the same class
For example:
interface LampcmsResourceInterface
{
/**
* Returnes id of user (USERS.id)
* who owns the resource
*
* @return int
*/
public function getOwnerId();
public function getResourceId();
}
and then a
interface Zend_Acl_Resource_Interface
{
/**
* Returns the string identifier of the Resource
*
* @return string
*/
public function getResourceId();
}
This is not a problem as long as you don't try to implement
both in the same class.
You may assume that if your class has a method
getResourceId() then you can safely say it implements both LampcmsResourceInterface and Zend_Acl_Resource_Interface
but this is not true
if you try to write a class like this
class MyResource implements LampcmsResourceInterface, Zend_Acl_Resource_Interface
{
protected $resourceID = 100;
public function getResourceId(){
return $this->resourceID;
}
}
You will get fatal error when you try to instantiate this class:
Fatal error: Can't inherit abstract function Zend_Acl_Resource_Interface::getResourceId() (previously declared abstract in LampcmsResourceInterface)
The best course of action now would be to
change the LampcmsResourceInterface to only have one required method getOwnerId();
Then if you need an object that MUST have getOwnerID() and getResourceId()
just make a class and declare it as implements LampcmsResourceInterface, Zend_Acl_Resource_Interface
Tuesday, January 12, 2010
Thursday, January 7, 2010
Correct way to handle deleted messages and posts
Sure, we can also delete a record from MESSAGE_BODY if we keep a separate table just for message bodies.
Don't just mark it as deleted, but actually use a timestamp value for the 'deleted_ts' column.
The reason for that is that we will them be able to spot that the message has been deleted and not just 'does not exist'.
One advantage of knowing that it has actually been deleted and not just 'not found' is that we will be able to return a 410 response code instead of the normal 404
The difference between 410 and 404 is that search engines will not attempt to retry getting the same page again and again. The 410 basically says 'gone permanently' instead of just 'not found'
It may actually cause Google to delete this page from Google cache very fast.
Actually we can even give Google another hint to remove such page from cache. When we catch the 410 exception we may add an extra meta tag NOCACHE or NOARCHIVE, whatever it is that Google understands as 'don't use cached version'
This can be very helpful. And of cause by marking message as deleted instead of actually deleting it, we are not breaking the 'next', 'previous' navigation.
The 'next'/'previous' nav is another story, and maybe we actually should not use the 'next'/'prev' links of deleted pages because if many messages have been deleted we don't want to point to 'prev' which has also been deleted, we want to point to the first non-deleted page, but that will require a different logic. Later...
Also when we know that timestamp of when the message has been deleted we can show it to the user on the 410 page. So, we not only sending 410 response code but we can also show 'message was deleted on Dec 12, 2009' for example
This is also extremely helpful to the user.
Monday, January 4, 2010
Google's official paid links ban policy
http://www.mattcutts.com/blog/how-to-report-paid-links/
It also explains how to report paid links to google, which is great!
Sunday, January 3, 2010
You can have your blog included on Google news
in the Google news.
I did not know that, but here it is:
http://www.google.com/support/news_pub/bin/answer.py?hl=en&answer=40787
Submitting Your Content: Google News
If you'd like your news site or blog to be included in Google News, please send us the URL and we'll be happy to review it. Please note, however, that we can't guarantee we'll be able to include your site in Google News.
Shocking rel nofollow abuse by major players
content to the search engine than to the average user:
To the average user it looks like a link, yet to the search engine it looks like
it's not a link.
This is indeed a reverse cloaking - a reverse because it's initiated not by
a user with the purpose to trick, scam, screw! the search engine, but it was invented
by a search engine with a purpose to screw the user.
What do you think? Do you think I'm right?
Anyway, the nofollow originally was made popular by google, so other search
engines agreed that it was a good idea and decided to follow suit.
nofollow abuse:
digg
stubledupon
but also: (just a random example) http://stackoverflow.com/users/191837/kevin-peno
On personal pages of registered user!
How lame is that! If admin suspects that a user is a spammer, he should
just remove the user.
Also, stackoverflow has such thing as ;reputation;
so they at the very least should remove nofollow from
members with decent reputation!
I like the stackoverflow but I wold not give them
my time of day and contribute anything to them
if all I get in return is a lame 'nofollow' link
back to me.
===============
Also on github.com
How lame is that - accounts on github are basically
open source software projects. If I contribute an open
source project, then the least you can do is give me a fully
normal link, not a nofollow shit.
you want me as another user of github, you want me
to link to you, yet you treat me like a spammer?
No, thank you. You can keep your github to yourself
and I will just setup my own site to host my own project.
-----------------
At least DIGG has some in-house algorythm that would remove nofollow links
once they establish a repuration for your resource, but it's not clear
how this works. Once thing is clear that if your have many diffs (like 100+)
then the nofollow is gone. What is not clear is what they take into account
They should take into account the user who submitted the diggs - an old
user who has not been flagged as spammer and submitted certain number of diggs should
be able to submit dofollow links.
By the way, do you know why they call it dofollow? You know, there is no such thing as
dofollow attribute,.... it's just because the other way to describe links without a nofollow tag
is to call them nonofollow link. And that sounds pretty stupid.
========================
The right way to use nofollow is ONLY in comment or user submitted content like
a forum. Even then, a system should be in place that would allow good members to
post good links. Period! Don't slap a cookie-cutter nofollow attribute on all
links!
==============
Who else got it wrong? Probably the blogger. They are right to add nofollow to links
in comments, but they probably should not be slapping the nofollow to links
to other members who commented. I mean if it's a spam fighting technique, then
Blogger should be able to develop the best anti comment spam in the world, after all
they have access to real-time blog comments from millions of users.
If a user is a spammer, then blogger can just remove the whole user's account, making
all the hard work the user made in adding comments totally useless.
==================
Who's got it right? youtube! Then don't slap nofollow to links to user accounts from comments,
to links to friends and subscribers.
They even allow 1 normal link to your external website from youtube account page. More than one
link is OK, you can just add it by the way of editing the HTML of your channel description
but all such links are indeed nofollow links.
Who else got it right? livejournal does not add nofollow links to members from the comment pages
but it also does not add nofollow to any links in comments. This creates comment spam problem on
livejournal which they fight by letting user to require captcha on their comment pages.
=======================================
Who else is abusing it? Some forum software like vbulletin usually adds nofollow
to all incoming posts and there is no way to use any intelligent algorythm to
no add nofollow from trusted members.
also they seem to add a nofollow link even to links from personal profile pages
and many webmasters don't even allow viewing a profile page for not logged in user.
=======================
Once forum sofware that is pretty good with not abusing nofollow is simplemachines forum
The link from profile page is a normal link and is usually seen by not logged in user
require_once inside the method in php class
require_once inside one of your methods in a php class then php will still evaluate
this require_once statement at compile time.
What these people were trying to say is that you should not have require_once or any other
similar statement inside your methods because it will slow down your script since php
will have to look at every such statement and make sure that there files are actually available.
I don't know, but I think it's a myth.
I took one of the classes from Zend, the Zend_Acl class
and inside the add() method there is a statement:
if (!$role instanceof Zend_Acl_Role_Interface) {
require_once 'Zend/Acl/Exception.php';
throw new Zend_Acl_Exception('addRole() expects $role to be of type Zend_Acl_Role_Interface');
}
So I just changed the require_once 'Zend/Acl/Exception.php';
to require_once 'nd/Acl/Exception.php';
This of cause points to non-existent php file, and would raise an error.
But php loaded my Acl class just fine. Not only it loaded my Acl class fine, but it even allowed
me to call the add() method. So as long as my script did not
pass this test: if (!$role instanceof Zend_Acl_Role_Interface)
php did not complain at all.
So there you have it, a proof that php does not care about your require_once statements until it actually executes these statements.
So, don't worry about this silly issue then - it is OK to have require_once inside the methods
but it's just as OK to completely rely on autoloader.
Personally I always use autoloader, so when I decided to use Zend_Acl class my first instinct was to just comment out all the require_once statements since they really hurt my eyes. Hey, I am not used to seeing require_once in my classes at all - that's what the spl_autoload and __autoload are for.
But then I though that I am going to be a good programmer and will not mess with an existing class - if I need some changes in the class, then I will extended like any good programmer should. And that what lead me to this test - I just wanted to be sure that having require_once inside the method will not cause any type of performance penalty. And it did not.
OK, I said too much already about this tiny issue.
Bye now.