Web Design/Development
Street Shooter
When I was browsing Google Maps’ Street View, a weird idea sudden popped out: Street Shooter. It’s a game where you shoot the people and cars in the Street View. To play the game, you must go to Google Maps and enter a Street View, then use a bookmarklet.
I don’t know if the implementation is possible. It seems the Maps Term of Use does not allow it and the Street View API doesn’t have capability to do that.
I also have ideas of Word and Excel macro game, where your Word document or Excel spreadsheet become a platformer action game.
PHP Flaws
You saw it, you learned it, you programmed it, it’s everywhere. Well, I’m not talking about a Microsoft product, it is PHP.
Are you annoyed by the error messages of PHP? When something wrong happened, an error message will show up, which may break the HTML being generated. To remove the error messages, you must add error_reporting(0) in front of the code, or it won’t be portable. Talking about portability… PHP is a configurable programming language. The configuration makes PHP code must detect the configurations and perform actions based on it.
Can you imagine of the php.ini setting default_php_mode exists? By turning on default_php_mode, you can start writing PHP code without , for example:
include 'header.php' ?> <!DOCTYPE html> <html> <head> ......
You won’t be able to use PHP code to detect it. Of course, that configuration does exist, for good.
Magic quotes, originally used to help newbie programmers in security, made a hassle for experienced programmers and PHP5 newbies. You must add a boilerplate code like this
<?php
if (get_magic_quotes_gpc()) {
$_REQUEST = array_map('stripslashes', $_REQUEST);
$_GET = array_map('stripslashes', $_GET);
$_POST = array_map('stripslashes', $_POST);
$_COOKIE = array_map('stripslashes', $_COOKIE);
}
?>
to make sure the text that will be used in database queries will not be quad-slashed (like 'text here \\\\').
The flags are bad. I hate these things like file_put_contents('file.txt', 'Hello corrupted world', FILE_APPEND); preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);. Also, some functions use array references, for example, preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3); will modify the variable $matches. It should be done like:
<?php
try {
$matches = preg_match_offset_capture($pattern, $subject, 3);
} catch (PregException $e) {
$matches = array();
}
?>
The variable scoping may confuse the newbie PHP programmers who had programming experience on other programming languages such as JavaScript. You can’t access global variables in the function scope. You must use $GLOBALS or global $g_variable. It’s a huge hassle.
Here is an example of PHP global variables:
<?php
$x = 0;
function f($n) {
$x += $n; // wrong, not accessing global $x
}
function g($n) {
global $x; // right
$x += $n;
}
function h($n) {
$GLOBALS['x'] += $n; // right
}
?>
Maybe you know, or maybe you don’t. There are alternative syntaxes for if and the for blocks.
<?php if ($x): else: endif; foreach ($a as $b): endforeach; ?>
Some people will use the brace syntax, and some people will use that alternative syntax, which will cause inconsistency in large coding projects. The alternative syntaxes should be removed.
Most low-class Web developers who do not know PHP, copy and paste small scripts from large script repositories, like copying full of JavaScript from DynamicDrive for vanity proposes. Because PHP attracts low-class developers, the syntax of PHP became messy to meet the needs for the low-class developers, then, more low-class developers will be attracted.
PHP needs a revolution. The revolution will change the PHP syntax to something clean, ECMAScript syntax could be fair. Yes, do break the backward compatibility, too much backward compatibility cause problems. If PHP revolution won’t start… <%= "Hello Ruby on Rails world!" %>
Processing.js Auto-Start with Apache mod_rewrite and PHP
Tired of keep adding boilerplate code for Processing.js scripts? Are you making full of Processing.js scripts and you are too lazy to share them? I wrote a script for that. You only need to upload the Processing.js scripts as .pjs file extension then you only need to type the URL to the script in your address bar. Your server will wrap it with initialization code. Very easy.
To see it in action:
- http://uniteduniversemainsite.freehostia.com/files/processingjs/sample.pjs
- http://uniteduniversemainsite.freehostia.com/files/processingjs/firework.pjs
Download the script here: http://www.mediafire.com/download.php?gfozzoymzew.
After you downloaded the script, create a new directory on your server, upload the files in the archive. To test if it works, type http://YOURSITE.com/PATH/sample.pjs (where YOURSITE.com is the domain of your site and PATH is the path to the Processing.js auto-loader you’ve uploaded), it will show you the sample file called sample.pjs.
A Simple Processing.js Game
I was trying to code something. Then I made a simple game with Processing.js. It is a game where you use your mouse to move the blue circle and avoid all red circles.
You can see it at http://uniteduniversemainsite.freehostia.com/files/processingjs/avoider.html. It uses HTML 5, so it only work for latest, beta (and higher) browsers such as Firefox 3.5, Opera 10, Safari 4 and Chrome 2. The texts such as the score and level indicator only work on Firefox 3.5.
I’m going to make a shooter game next time.
Source code:
class Enemy {
int x;
int y;
int speed;
Enemy(int x, int speed) {
this.x = x;
this.y = 0;
this.speed = constrain(speed, 0, 10);
}
void update() {
fill(255, 0, 0);
stroke(128, 0, 0);
ellipseMode(CENTER);
ellipse(x, y, 40, 40);
this.y += speed;
}
}
PFont font;
ArrayList enemies;
int level;
int score;
int timer;
int count;
int playerX;
int playerY;
byte state = 0;
void setup() {
size(400, 400);
font = loadFont("Courier New");
reset();
}
void reset() {
enemies = new ArrayList();
level = 1;
score = 0;
timer = 150;
count = 150;
playerX = 200;
playerY = 200;
}
void draw() {
background(0);
if (state == 2) {
if (score >= level * level * 10) {
level ++;
}
count = (1 / level) * 200;
timer ++;
if (timer > count) {
timer = 0;
enemies.add(new Enemy(random(400), sqrt(level) / 2));
}
for (int i = enemies.size() - 1; i > -1; i --) {
Enemy enemy = (Enemy) enemies.get(i);
if (enemy.y > height) {
enemies.remove(i);
score += level * 2;
continue;
}
if (playerX < enemy.x + 30 && playerX > enemy.x - 30 &&
playerY < enemy.y + 30 && playerY > enemy.y - 30) {
state = 1;
break;
}
enemy.update();
}
playerX += constrain(mouseX - playerX, -5, 5);
playerY += constrain(mouseY - playerY, -5, 5);
fill(0, 0, 255);
stroke(0, 0, 128);
ellipseMode(CENTER);
ellipse(playerX, playerY, 30, 30);
fill(255);
textFont(font, 16);
text("Score: " + score + " | Level: " + level, 1, 17);
} else if (state == 1) {
fill(255);
textFont(font, 48);
text("Game Over", 1, 49);
textFont(font, 16);
text("Score: " + score, 15, 93);
text("Level: " + level, 15, 110);
} else {
fill(255);
textFont(font, 18);
text("Click to start", 1, 20);
}
}
void mousePressed() {
if (state == 1) {
reset();
state = 0;
} else if (state == 0) {
state = 2;
}
}
HTTP and HTML Forms
Before start learning PHP or other server-side scripting languages, you must know how do the browser and server transmit information over the HTTP (HyperText Transfer Protocol) and how the form data are extracted.
When you typed a HTTP URL into the address bar, for example, http://www.example.com/index.html . The browser will send a request to www.example.com over your computer’s network. The request will contain many headers telling the browser’s information and which page to request. The request will look like this:
GET /index.html [The browser wants the page index.html] Host: www.example.com [The hostname on the address bar] User-Agent: Mozilla/10.0 Firefox 5.2.5 [Your browser's identifier] Accept: text/html [Your browser is looking for text/html (HTML) document] Cookie: AAA=BBB; CCC=DDD; [Your cookies]
Then the server will parse the request and respond with the content of the page.
HTTP/1.1 200 OK [200 OK means the request is successful] Date: Tue, 15 Nov 1994 08:12:31 GMT [Time on the server] Content-Type: text/html [The type of the document, text/html is the MIME type for HTML] [After one empty line, the content of the page is outputted] <html><head><title>Example Web page</title></head> [......]
Please note that the [bracketed text] are explanations I added.
There are many more HTTP headers, I’m not going to teach you all of them, you can read more at http://en.wikipedia.org/wiki/List_of_HTTP_headers.
When you submitted a HTML form, some additional information will be added to request headers. There are two (and some rare ones such as PUT and DELETE) types of HTTP requests, GET and POST. When you clicked “Search” on Google, you will send a GET request to Google’s server and you will be taken to a result page. You can bookmark the result page, and the search query will appear in the URL (look at the address bar: “http://www.google.com/search?hl=en&q=SEARCH QUERY STRING“), that means the search form’s values appeared in the URL.
POST request is different. The form values do not show up on the URL. Instead, they show up inside the headers. You cannot bookmark a form result of a POST form. Normally, GET requests are used for GETting something, such as searching. Side effects, such as registration, purchase, transaction are sent as POST requests. If you submitted a POST form and you tried to refresh the page, the browser will say “Re-submit form data?”. If you clicked Yes, you will re-purchase something, performed a transaction twice, or anything else.
The form’s method is determined by the <form>’s method attribute, and the form’s target is determined by the action attribute. Set action to “#” if the target of the form is the form itself. Here is an example registration form.
<!-- Starts a new HTML form. The method is POST because a registration is a side effect, and you don't bookmark a registration form result. --> <form action="register.php" method="POST"> <div> <!-- A text field, its name, its value will be sent to the server under the name of 'username'. so the server will access it like $_POST['username'], Request.post['username'] depending on the type of the server software. --> Username: <input type='text' name='username' value='' /><br /> <!-- A password field that does not show up what the user typed. (it will only show "*********") A password field acts like a text field. --> Password: <input type='password' name='password' /><br /> <!-- A radio button. the name will determine the radio button group. The value will determine the value to be sent when it was selected. The checked attribute tells the browser if it should be selected by default. --> Gender: <input type='radio' name='gender' value='male' checked='checked'> Male <input type='radio' name='gender' value='female'> Female<br /> <!-- Submit button submits the form (duh) --> <input type='submit' value='Submit' name='Submit' /> <!-- There are many other types of form controls, such as drop-down, image buttons, lists, they all have a name and value attribute. Please go back to the HTML tutorial you've read to learn more about other form controls. --> </div> </form>
The form values will be included in the request, and the server will read it and take action. It will either register you, or send you back and show an error message.
Here is a pseudocode that will show how the server will handle the form.
// Request.post is all values from a POST request.
// check if the submit button was clicked. (the button's name is 'Submit')
if (Request.post.has('Submit')) {
// validate form
if (!(Request.post.has('username') || Request.post.has('password') || Request.post.has('gender'))) {
output ('<p>You must fill ALL form fields correctly.</p>');
} else {
// register user
registerUser(Request.post['username'], Request.post['password'], Request.post['gender']);
output ('You are registered.')
}
}
Cookies are used to store information to the browser (and they will be read by the server). On Google.com, you can click “Preferences” to change the search preferences, then, the preferences will be saved to your browser (only if cookies are enabled in your browser). The cookies are passed to the server by the Cookie HTTP header and the server will send the Set-Cookie HTTP header to tell the browser to set the cookie. Cookies can expire, determined by the expiry date when the cookie was set.
When you log in to a website, what keeps you logged in? Cookies. The server tells the browser to set the cookie containing the login information or session identifier to keep you logged in. On most login-enabled sites, there is a “Remember Me” option. Most of the sites will make the cookie never expire if you choose “Remember Me”.
Canvas Chat
Recently, I created a new PHP application, it is like a chat room, but you can send images instead of text.
To download the source code: http://www.mediafire.com/download.php?jgm2yn2qt5z.
To try it online, go to http://www.eeveeshq.com/canvaschat/, Kat uploaded it to her site, but that one is a custom build with integration to her website, so you need to register Eevee’s HQ to use it.
I originally posted in on Eevee’s HQ, and someone spammed it, at last, Nick said he did it.
asked Kat about it, In the next day, Kat said she was joking around.
YouTube is getting worse, big companies such as Disney were trying to make advertisement videos more visible on YouTube, YouTube is not for you, it is for THEM.
Let’s use Veoh.com if YouTube is getting bad.
PHP Math Expression Parser
I created a math expression parser that evaluates math expressions and functions such as “variable = 42 * (34 + 52 – sqrt(variable + 3))”.
<?php
/**
* A math expression parser, supports:
* <ol>
* <li>add, subtract, multiply and division</li>
* <li>brackets grouping</li>
* <li>functions, custom functions' prefix can be customized.</li>
* <li>variables</li>
* </ol>
* Does not support:
* <ol>
* <li>bitwise/logical operators.</li>
* <li>if/else/for statements</li>
* <li>arrays</li>
* </ol>
* Depends on BCMath library to gain arbitrary precision features.<br />
* BNF Grammar (quotes strings and ALL CAPs are terminals):
* <pre>
* expression ::= ( IDENT '=' expression | addexpr )
* addexpr ::= term ( ( '+' | '-' ) term )*
* term ::= primary ( ( '*'|'/' ) primary )*
* primary ::= ( NUMBER | IDENT | '(' expression ')' | IDENT ( '(' expression (',' expression)* ')' | '(' ')' ) )
* </pre>
* This class implements ArrayAccess, so <code>$expr['name']</code> will access variable <code>name</code>.
* To evaluate an expression, use the <code>evaluate(string $expr)</code> method.
* To set percision, use <code>bcscale(int $scale)</code> function.
* Example usage: <code>$expr = new Expression(); $expr->evaluate('a = 12 + 5'); echo $expr['a']; //prints 17</code>
* @author SpaceMan
* @version 1.0
*/
class Expression implements ArrayAccess {
private $tokens = array();
private $expr = '';
/**
* @var array List of all variables.
*/
public $variables = array();
/**
* @var string Prefix of all custom functions, for example, <code>sqrt(10)</code> will map
* to <code>bcsqrt(10)</code> if the prefix is <code>bc</code>.
*/
public $prefix = 'bc';
/**
* Constructs a new Expression object.
* @param string $expr The initial expression to be evaluated.
*/
public function __construct($expr = '') {
$this->expr = $expr;
}
/**
* Evaluates an expression.
* @param string $expr The expression to be evaluated.
* @return string The result in string of numbers.
*/
public function evaluate($expr) {
$this->expr = $expr;
$this->tokenize();
return $this->expression();
}
public function offsetSet($offset, $value) {
$this->variables[$offset] = $value;
}
public function offsetExists($offset) {
return isset($this->variables[$offset]);
}
public function offsetUnset($offset) {
unset($this->variables[$offset]);
}
public function offsetGet($offset) {
return isset($this->variables[$offset]) ? $this->variables[$offset] : null;
}
/**
* Tokenize the expression.
* @internal
*/
private function tokenize() {
$expr = $this->expr;
$i = 0;
$c = " ";
//while there are more string to be tokenized
while ($c) {
//exit if there are no more string.
if ($i >= strlen($expr)) {
return;
}
//the code to be scanned
$c = substr($expr, $i);
if (preg_match('/^\d+(\.\d+)?/', $c, $matches, PREG_OFFSET_CAPTURE)) {
//numbers
$i += strlen($matches[0][0]);
array_push($this->tokens, array('NUMBER', $matches[0][0]));
} else if (preg_match('/^[A-Za-z0-9_]+/', $c, $matches, PREG_OFFSET_CAPTURE)) {
//variables
$i += strlen($matches[0][0]);
array_push($this->tokens, array('IDENT', $matches[0][0]));
} else if ($c[0] == ' ' or $c[0] == '\t' or $c[0] == '\r' or $c[0] == '\n') {
//whitespaces
$i ++;
} else {
//operators
array_push($this->tokens, array($expr[$i], $expr[$i]));
$i ++;
}
}
}
/**
* Determines if the next token exists.
* This function takes multiple arguments.
* @internal
*/
private function has() {
$t = $this->tokens[0];
foreach (func_get_args() as $name) {
if ($t[0] == $name) {
return true;
}
}
return false;
}
/**
* Consume the next token.
*/
private function token() {
return array_shift($this->tokens);
}
/**
* Calls a function.
* @internal
*/
private function call($name, $values = array()) {
return eval('return ' . $this->prefix . $name . '(' . implode(',', $values) . ');');
}
private function primary() {
if ($this->has('NUMBER')) {
//numbers
$t = $this->token();
return $t[1];
} else if ($this->has('-')) {
//negative numbers
$this->token();
return -$this->primary();
} else if ($this->has('(')) {
//brackets
$this->token();
$v = $this->expression();
$this->token();
return $v;
} else if ($this->has('IDENT') && $this->tokens[1][0] == '(') {
//function call
$name = $this->token();
$name = $name[1];
$this->token();
$args = array();
if ($this->has(')')) {
//zero arguments
return $this->call($name);
} else {
//one or more arguments
$args[] = $this->expression();
while ($this->has(',')) {
$this->token();
$args[] = $args[] = $this->expression();
}
$v = $this->call($name, $args);
$this->token();
return $v;
}
} else if ($this->has('IDENT')) {
//get variable
$t = $this->token();
return $this->variables[$t[1]] or '0';
} else {
throw new RuntimeException('Syntax error.');
}
}
private function term() {
$v = $this->primary();
while ($this->has('*', '/')) {
$op = $this->token();
$right = $this->primary();
switch ($op[0]) {
case '*':
$v = bcmul($v, $right);
break;
case '/':
$v = bcdiv($v, $right);
break;
default:
throw new RuntimeException('Invalid operator, expection "*" or "/".');
}
}
return $v;
}
private function addexpr() {
$v = $this->term();
while ($this->has('+', '-')) {
$op = $this->token();
$right = $this->term();
switch ($op[0]) {
case '+':
$v = bcadd($v, $right);
break;
case '-':
$v = bcsub($v, $right);
break;
default:
throw new RuntimeException('Invalid operator, expection "+" or "-".');
}
}
return $v;
}
private function expression() {
if ($this->has('IDENT') and $this->tokens[1][0] == '=') {
$left = $this->token();
$left = $left[1];
$this->token();
$right = $this->expression();
$this->variables[$left] = $right;
return $right;
} else {
return $this->addexpr();
}
}
}
?>
To use it, include that file and create a new Expression object, then call the evaluate($expr) to evaluate expressions.
An example usage:
<?php
include ('expression.php');
$expr = new Expression();
$expr['variablename'] = 12; //pre-define a variable inside the object
echo $expr->evaluate($_GET['expression']);
echo 'The variable variablename is: ' . $expr['variablename'];
//to set a prefix for custom functions
$expr->prefix = 'myfuncs_';
?>
My Sites
Other Blogs
Twitter Updates
Tags
Recent Comments
- Pinoytech on Chrome OS Leaked
- Acchan on PHP Flaws
- admin on Finished Moving
- Calvin on Finished Moving
- admin on Colony
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « Oct | ||||||
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 | ||||
Categories
Creative Commons License