深圳腾讯互联网运营部招聘运营开发工程师

By 深空, 2010年03月05日 16:45

工作职责:

1. 负责互联网海量用户社区的运营支持系统的建设和开发工作;
2. 参与系统的需求分析、设计、编码等开发工作;
3. 负责相关系统的运营和维护工作,保证系统稳定可靠运行。

工作要求:
1. 计算机相关专业本科以上学历,3年以上开发工作经验;
2. 精通PHP开发,具有大型LAMP系统设计和开发经验;
3. 熟悉数据库,精通SQL和数据结构,具有MySQL或者oracle开发经验为佳;
4. 精通HTML/XHTML、CSS、Javascript等web开发技能;
5. 了解使用linux基本操作命令,熟悉Shell脚本的编写;
6. 同时具有C/C++、CGI、XML、AJAX开发经验为佳;
7. 工作有激情,成就感强烈,热爱开发事业;
8. 学习能力强,具有良好的团队合作能力。

有兴趣的联系我 shenkong#qq.com

VN:F [1.8.4_1055]
Rating: 10.0/10 (1 vote cast)
VN:F [1.8.4_1055]
Rating: +2 (from 2 votes)

简单的PHP日历算法

By 深空, 2009年12月28日 15:22

  看看有没有比我更优的,HOHO。

/**
 * 日历
 *
 * Copyright(c) 2007 by 陈毅鑫(深空). All rights reserved
 * To contact the author write to {@link mailto:shenkong@php.net}
 * @author 陈毅鑫(深空)
 */
if (function_exists('date_default_timezone_set')) {
    date_default_timezone_set('Asia/Chongqing');
}
$date = isset($_GET['date']) ? $_GET['date'] : date('Y-m-d');
$date = getdate(strtotime($date));
$end = getdate(mktime(0, 0, 0, $date['mon'] + 1, 1, $date['year']) - 1);
$start = getdate(mktime(0, 0, 0, $date['mon'], 1, $date['year']));
$pre = date('Y-m-d', $start[0] - 1);
$next = date('Y-m-d', $end[0] + 86400);
$html = '<table border="1">';
$html .= '<tr>';
$html .= '<td><a href="' . $PHP_SELF . '?date=' . $pre . '">-</a></td>';
$html .= '<td colspan="5">' . $date['year'] . ';' . $date['month'] . '</td>';
$html .= '<td><a href="' . $PHP_SELF . '?date=' . $next . '">+</a></td>';
$html .= '</tr>';
$arr_tpl = array(0 => '', 1 => '', 2 => '', 3 => '', 4 => '', 5 => '', 6 => '');
$date_arr = array();
$j = 0;
for ($i = 0; $i < $end['mday']; $i++) {
    if (!isset($date_arr[$j])) {
        $date_arr[$j] = $arr_tpl;
    }
    $date_arr[$j][($i+$start['wday'])%7] = $i+1;
    if ($date_arr[$j][6]) {
        $j++;
    }
}
foreach ($date_arr as $value) {
    $html .= '<tr>';
    foreach ($value as $v) {
        if ($v) {
            if ($v == $date['mday']) {
                $html .= '<td><b>' . $v . '</b></td>';
            } else {
                $html .= '<td>' . $v . '</td>';
            }
        } else {
            $html .= '<td>&nbsp;</td>';
        }
    }
    $html .= '</tr>';
}
$html .= '</table>';
echo $html;
VN:F [1.8.4_1055]
Rating: 7.0/10 (12 votes cast)
VN:F [1.8.4_1055]
Rating: +4 (from 16 votes)

《Head First 设计模式》代码之PHP版

By 深空, 2009年12月28日 09:49

  《Head First 设计模式》是本不错的讲解设计模式的书,不像F4写的那么枯燥,应该算是比较容易理解的好书。书中的例子都比较浅显易懂,不过由于是外国佬写的,所以例子的习惯不是很附合中国特色,可能偶尔看起来有些别扭,还有语言习惯也不是中国风。当然��看过这本书之后,你才能深刻理解设计模式到底能为你解决哪些问题,不能为你解决哪些问题(比如不能代替你的编码)。
  我将书中部分代码改成PHP,看下代码再配合概念应该是比较容易理解了。
  策略模式

<?php
/**
 * 策略模式
 * 定义了算法族,分别封装起来,让它们之间可以互相替换,
 * 此模式让算法的变化独立于使用算法的客户。
 */
//飞行行为接口
interface FlyBehavior {
    public function fly();
}
//呱呱叫行为接口
interface QuackBehavior {
    public function quack();
}
//翅膀飞行
class FlyWithWings implements FlyBehavior {
    public function fly() {
        echo "I'm flying!!\n";
    }
}
//不会飞
class FlyNoWay implements FlyBehavior {
    public function fly() {
        echo "I can't fly!\n";
    }
}
class FlyRocketPowered implements FlyBehavior {
    public function fly() {
        echo "I'm flying with a rocket!\n";
    }
}
class Qquack implements QuackBehavior {
    public function quack() {
        echo "Quack\n";
    }
}
class Squeak implements QuackBehavior {
    public function quack() {
        echo "Squeak\n";
    }
}
class MuteQuack implements QuackBehavior {
    public function quack() {
        echo "<< Silence >>\n";
    }
}
abstract class Duck {
    protected $quack_obj;
    protected $fly_obj;
    public abstract function display();

    public function performQuack() {
        $this->quack_obj->quack();
    }
    public function performFly() {
        $this->fly_obj->fly();
    }
    public function swim() {
        echo "All ducks float, even decoys!\n";
    }
    public function setFlyBehavior(FlyBehavior $fb) {
        $this->fly_obj = $fb;
    }
    public function setQuackBehavior(QuackBehavior $qb) {
        $this->quack_obj = $qb;
    }
}

class ModelDuck extends Duck {
    public function __construct() {
        $this->fly_obj = new FlyNoWay();
        $this->quack_obj = new MuteQuack();
    }
    public function display() {
        echo "I'm a model duck!\n";
    }
}

$model = new ModelDuck();
$model->performFly();
$model->performQuack();
//提供新的能力
$model->setFlyBehavior(new FlyRocketPowered());
$model->setQuackBehavior(new Squeak());
$model->performFly();
$model->performQuack();

?>

  单件模式

<?php
/**
 * 单件模式
 * 确保一个类只有一个实例,并提供一个全局访问点。
 */
class MyClass {
    private static $uniqueInstance;
    private function __construct() {

    }
    public static function getInstance() {
        if (self::$uniqueInstance == null) {
            self::$uniqueInstance = new MyClass();
        }
        return self::$uniqueInstance;
    }
}
$myClass = MyClass::getInstance();
var_dump($myClass);
$myClass = MyClass::getInstance();
var_dump($myClass);
?>

  工厂方法模式

<?php
abstract class PizzaStore {
    public function orderPizza($type) {
        $pizza = $this->createPizza($type);

        $pizza->prepare();
        $pizza->bake();
        $pizza->cut();
        $pizza->box();
        return $pizza;
    }

    public abstract function createPizza($type);
}
class NYPizzaStore extends PizzaStore {
    public function createPizza($type) {
        if ($type == "cheese") {
            return new NYStyleCheesePizza();
        } elseif ($type == "veggie") {
            return new NYStyleVeggiePizza();
        } elseif ($type == "clam") {
            return new NYStyleClamPizza();
        } elseif ($type == "papperoni") {
            return new NYStylePapperoniPizza();
        } else {
            return null;

        }
    }
}
class ChicagoPizzaStore extends PizzaStore {
    public function createPizza($type) {
        if ($type == "cheese") {
            return new ChicagoStyleCheesePizza();
        } elseif ($type == "veggie") {
            return new ChicagoStyleVeggiePizza();
        } elseif ($type == "clam") {
            return new ChicagoStyleClamPizza();
        } elseif ($type == "papperoni") {
            return new ChicagoStylePapperoniPizza();
        } else {
            return null;
        }
    }
}
abstract class Pizza {
    public $name;
    public $dough;
    public $sauce;
    public $toppings = array();

    public function prepare() {
        echo "Preparing " . $this->name . "\n";
        echo "Yossing dough...\n";
        echo "Adding sauce...\n";
        echo "Adding toppings: \n";
        for ($i = 0; $i < count($this->toppings); $i++) {
            echo "    " . $this->toppings[$i] . "\n";
        }
    }

    public function bake() {
        echo "Bake for 25 minutes at 350\n";
    }

    public function cut() {
        echo "Cutting the pizza into diagonal slices\n";
    }

    public function box() {
        echo "Place pizza in official PizzaStore box\n";
    }

    public function getName() {
        return $this->name;
    }
}

class NYStyleCheesePizza extends Pizza {
    public function __construct() {
        $this->name = "NY Style Sauce and cheese Pizza";
        $this->dough = "Thin Crust Dough";
        $this->sauce = "Marinara Sauce";

        $this->toppings[] = "Grated Reggiano Cheese";
    }
}

class NYStyleVeggiePizza extends Pizza {
    public function __construct() {
        $this->name = "NY Style Sauce and veggie Pizza";
        $this->dough = "Thin Crust Dough";
        $this->sauce = "Marinara Sauce";

        $this->toppings[] = "Grated Reggiano veggie";
    }
}
class NYStyleClamPizza extends Pizza {
    public function __construct() {
        $this->name = "NY Style Sauce and clam Pizza";
        $this->dough = "Thin Crust Dough";
        $this->sauce = "Marinara Sauce";

        $this->toppings[] = "Grated Reggiano clam";
    }
}
class NYStylePapperoniPizza extends Pizza {
    public function __construct() {
        $this->name = "NY Style Sauce and papperoni Pizza";
        $this->dough = "Thin Crust Dough";
        $this->sauce = "Marinara Sauce";

        $this->toppings[] = "Grated Reggiano papperoni";
    }
}

class ChicagoStyleCheesePizza extends Pizza {
    public function __construct() {
        $this->name = "Chicago Style Deep Dish Cheese Pizza";
        $this->dough = "Extra Thick Crust Dough";
        $this->sauce = "Plum Tomato Sauce";

        $this->toppings[] = "Shredded Mozzarella Cheese";
    }

    public function cut() {
        echo "Cutting the pizza into square slices\n";
    }
}

$myStore = new NYPizzaStore();
$chicagoStore = new ChicagoPizzaStore();
$pizza = $myStore->orderPizza("cheese");
echo "Ethan ordered a " . $pizza->getName() . "\n";

$pizza = $chicagoStore->orderPizza("cheese");
echo "Ethan ordered a " . $pizza->getName() . "\n";

?>

  工厂模式

<?php
abstract class PizzaStore {
    public function orderPizza($type) {
        $pizza = $this->createPizza($type);

        $pizza->prepare();
        $pizza->bake();
        $pizza->cut();
        $pizza->box();
        return $pizza;
    }

    public abstract function createPizza($type);
}
class NYPizzaStore extends PizzaStore {
    public function createPizza($type) {
        $pizza = null;
        $ingredientFactory = new NYPizzaIngredientFactory();
        if ($type == "cheese") {
            $pizza = new CheesePizza($ingredientFactory);
            $pizza->setName('New York Style Cheese Pizza');
        } elseif ($type == "veggie") {
            $pizza = new VeggiePizza($ingredientFactory);
            $pizza->setName('New York Style Veggie Pizza');
        } elseif ($type == "clam") {
            $pizza = new ClamPizza($ingredientFactory);
            $pizza->setName('New York Style Clam Pizza');
        } elseif ($type == "papperoni") {
            $pizza = new PapperoniPizza($ingredientFactory);
            $pizza->setName('New York Style Papperoni Pizza');
        }
        return $pizza;
    }
}
class ChicagoPizzaStore extends PizzaStore {
    public function createPizza($type) {
        if ($type == "cheese") {
            return new ChicagoStyleCheesePizza();
        } elseif ($type == "veggie") {
            return new ChicagoStyleVeggiePizza();
        } elseif ($type == "clam") {
            return new ChicagoStyleClamPizza();
        } elseif ($type == "papperoni") {
            return new ChicagoStylePapperoniPizza();
        } else {
            return null;
        }
    }
}
interface PizzaIngredientFactory {
    public function createDough();
    public function createSauce();
    public function createCheese();
    public function createVeggies();
    public function createPepperoni();
    public function createClam();
}
class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    public function createDough() {
        return new ThinCrustDough();
    }
    public function createSauce() {
        return new MarinaraSauce();
    }
    public function createCheese() {
        return new ReggianoCheese();
    }
    public function createVeggies() {
        $veggies = array(
        new Garlic(),
        new Onion(),
        new Mushroom(),
        new RedPepper(),
        );
        return $veggies;
    }
    public function createPepperoni() {
        return new SlicedPepperoni();
    }
    public function createClam() {
        return new FreshClams();
    }
}
class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
    public function createDough() {
        return new ThickCrustDough();
    }
    public function createSauce() {
        return new PlumTomatoSauce();
    }
    public function createCheese() {
        return new Mozzarella();
    }
    public function createVeggies() {
        $veggies = array(
        new BlackOlives(),
        new Spinach(),
        new EggPlant(),
        );
        return $veggies;
    }
    public function createPepperoni() {
        return new SlicedPepperoni();
    }
    public function createClam() {
        return new FrozenClams();
    }
}
abstract class Pizza {
    public $name;
    public $dough;
    public $sauce;
    public $veggies = array();
    public $cheese;
    public $pepperoni;
    public $clam;

    public abstract function prepare();

    public function bake() {
        echo "Bake for 25 minutes at 350\n";
    }

    public function cut() {
        echo "Cutting the pizza into diagonal slices\n";
    }

    public function box() {
        echo "Place pizza in official PizzaStore box\n";
    }

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function __toString() {

    }
}

class CheesePizza extends Pizza {
    public $ingredientFactory;

    public function __construct(PizzaIngredientFactory $ingredientFactory) {
        $this->ingredientFactory = $ingredientFactory;
    }

    public function prepare() {
        echo "Preparing " . $this->name . "\n";
        $this->dough = $this->ingredientFactory->createDough();
        $this->sauce = $this->ingredientFactory->createSauce();
        $this->cheese = $this->ingredientFactory->createCheese();
    }
}

class ClamPizza extends Pizza {
    public $ingredientFactory;

    public function __construct(PizzaIngredientFactory $ingredientFactory) {
        $this->ingredientFactory = $ingredientFactory;
    }

    public function prepare() {
        echo "Preparing " . $this->name . "\n";
        $this->dough = $this->ingredientFactory->createDough();
        $this->sauce = $this->ingredientFactory->createSauce();
        $this->cheese = $this->ingredientFactory->createCheese();
        $clam = $this->ingredientFactory->createClam();
    }
}

$nyPizzaStore = new NYPizzaStore();
$nyPizzaStore->orderPizza('cheese');
?>

  观察者模式

<?php
/**
 * 观察者模式
 * 定义了对象之间的一对多依赖,当一个对象改变状态时,
 * 它的所有依赖者都会收到通知并自动更新。
 */
interface Subject {
    public function registerObserver(Observer $o);
    public function removeObserver(Observer $o);
    public function notifyObservers();
}
interface Observer {
    public function update($temperature, $humidity, $pressure);
}
interface DisplayElement {
    public function display();
}
class WeatherData implements Subject {
    private $observers = array();
    private $temperature;
    private $humidity;
    private $pressure;
    public function __construct() {
        $this->observers = array();
    }
    public function registerObserver(Observer $o) {
        $this->observers[] = $o;
    }
    public function removeObserver(Observer $o) {
        if (($key = array_search($o, $this->observers)) !== false) {
            unset($this->observers[$key]);
        }
    }
    public function notifyObservers() {
        foreach ($this->observers as $observer) {
            $observer->update($this->temperature, $this->humidity, $this->pressure);
        }
    }
    public function measurementsChanged() {
        $this->notifyObservers();
    }
    public function setMeasurements($temperature, $humidity, $pressure) {
        $this->temperature = $temperature;
        $this->humidity = $humidity;
        $this->pressure = $pressure;
        $this->measurementsChanged();
    }
}
class CurrentConditionsDisplay implements Observer, DisplayElement {
    private $temperature;
    private $humidity;
    private $weatherData;
    public function __construct(Subject $weatherData) {
        $this->weatherData = $weatherData;
        $weatherData->registerObserver($this);
    }
    public function update($temperature, $humidity, $pressure) {
        $this->temperature = $temperature;
        $this->humidity = $humidity;
        $this->display();
    }
    public function display() {
        echo "温度:" . $this->temperature . "; 湿度:" . $this->humidity . "%\n";
    }
}
class StatistionsDisplay implements Observer, DisplayElement {
    private $temperature;
    private $humidity;
    private $pressure;
    private $weatherData;
    public function __construct(Subject $weatherData) {
        $this->weatherData = $weatherData;
        $weatherData->registerObserver($this);
    }
    public function update($temperature, $humidity, $pressure) {
        $this->temperature = $temperature;
        $this->humidity = $humidity;
        $this->pressure = $pressure;
        $this->display();
    }
    public function display() {
        echo "温度:" . $this->temperature . "; 湿度:" . $this->humidity . "%; 气压:" . $this->pressure . "\n";
    }
}
$weatherData = new WeatherData();
$currentDisplay = new CurrentConditionsDisplay($weatherData);
$statistionDisplay = new StatistionsDisplay($weatherData);
$weatherData->setMeasurements(10, 20, 30);
$weatherData->removeObserver($currentDisplay);
$weatherData->setMeasurements(30, 40, 50);
?>

  命令模式

<?php

class Light {
    public function __construct() {

    }

    public function on() {
        echo "Light On\n";
    }

    public function off() {
        echo "Light Off\n";
    }
}

interface Command {
    public function execute();
}

class LightOnCommand implements Command {
    public $light;

    public function __construct(Light $light) {
        $this->light = $light;
    }

    public function execute() {
        $this->light->on();
    }
}

class SimpleRemoteControl {
    public $slot;

    public function __construct() {

    }

    public function setCommand(Command $command) {
        $this->slot = $command;
    }

    public function buttonWasPressed() {
        $this->slot->execute();
    }
}

class RemoteControlTest {
    public static function main() {
        $remote = new SimpleRemoteControl();
        $light = new Light();
        $lightOn = new LightOnCommand($light);
        $remote->setCommand($lightOn);
        $remote->buttonWasPressed();
    }
}

RemoteControlTest::main();

?>

  装饰者模式

<?php
/**
 * 装饰着模式
 * 动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
 */
abstract class Beverage {
    public $description = "Unknown Beverage";

    public function getDescription() {
        return $this->description;
    }

    public abstract function cost();
}

abstract class CondimentDecorator extends Beverage {
    //JAVA代码里这里是个抽象类,PHP不允许这么做
    public function getDescription() {
        return $this->description;
    }
}

class Espresso extends Beverage {
    public function __construct() {
        $this->description = "Espresso";
    }

    public function cost() {
        return 1.99;
    }
}

class HouseBlend extends Beverage {
    public function __construct() {
        $this->description = "HouseBlend";
    }

    public function cost() {
        return .89;
    }
}

class DarkRoast extends Beverage {
    public function __construct() {
        $this->description = "DarkRoast";
    }

    public function cost() {
        return .99;
    }
}

class Mocha extends CondimentDecorator {
    public $beverage;

    public function __construct(Beverage $beverage) {
        $this->beverage = $beverage;
    }
    public function getDescription() {
        return $this->beverage->getDescription() . ", Mocha";
    }
    public function cost() {
        return .20 + $this->beverage->cost();
    }
}

class Whip extends CondimentDecorator {
    public $beverage;

    public function __construct(Beverage $beverage) {
        $this->beverage = $beverage;
    }
    public function getDescription() {
        return $this->beverage->getDescription() . ", Whip";
    }
    public function cost() {
        return .10 + $this->beverage->cost();
    }
}

class Soy extends CondimentDecorator {
    public $beverage;

    public function __construct(Beverage $beverage) {
        $this->beverage = $beverage;
    }
    public function getDescription() {
        return $this->beverage->getDescription() . ", Soy";
    }
    public function cost() {
        return .15 + $this->beverage->cost();
    }
}

$beverage = new Espresso();
echo $beverage->getDescription() . "\n";
$beverage2 = new DarkRoast();
$beverage2 = new Mocha($beverage2);
$beverage2 = new Mocha($beverage2);
$beverage2 = new Whip($beverage2);
echo $beverage2->getDescription() . " $" . $beverage2->cost() . "\n";

$beverage3 = new HouseBlend();
$beverage3 = new Soy($beverage3);
$beverage3 = new Mocha($beverage3);
$beverage3 = new Whip($beverage3);
echo $beverage3->getDescription() . " $" . $beverage3->cost() . "\n";
?>

  状态模式

<?php

class GumballMachine {
    const SOLD_OUT = 0;
    const NO_QUARTER = 1;
    const HAS_QUARTER = 2;
    const SOLD = 3;

    public $state = self::SOLD_OUT;
    public $count = 0;

    public function __construct($count) {
        $this->count = $count;
        if ($count > 0) {
            $this->state = self::NO_QUARTER;
        }
    }

    public function insertQuarter() {
        if ($this->state == self::HAS_QUARTER) {
            echo "You can't insert another quarter!\n";
        } else if ($this->state == self::NO_QUARTER) {
            $this->state = self::HAS_QUARTER;
            echo "You inserted a quarter!\n";
        } else if ($this->state == self::SOLD_OUT) {
            echo "You can't insert a quarter, the machine is sold out!\n";
        } else if ($this->state == self::SOLD) {
            echo "Please wait, we're already giving you a gumball!\n";
        }
    }
}

$obj = new GumballMachine(0);
print_r($obj)

?>
VN:F [1.8.4_1055]
Rating: 10.0/10 (4 votes cast)
VN:F [1.8.4_1055]
Rating: +3 (from 3 votes)

基于HTTP长连接的“服务器推”技术的简易聊天室

By 深空, 2009年10月28日 19:43

  关于HTTP长连接的“服务器推”技术原理可以查看IBM的这篇文章,我简单的做了个DEMO:
  首先是首页,包含一个文本输入和一个显示聊天内容的iframe,还有一个隐藏iframe用来提交form表单:

<?php
//chat.php
header('cache-control: private');
header('Content-Type: text/html; charset=utf-8');
?>
<html>
<script type="text/javascript">
function submitChat(obj) {
    obj.submit();
    document.getElementsByName('content')[0].value = '';
}
</script>
<iframe src="./chat_content.php" height="300" width="100%"></iframe>
<iframe name="say" height="0" width="0"></iframe>
<form method="POST" target="say" action="./say.php" onsubmit="submitChat(this)">
<input type="text" size="30" name="content" /> <input type="button" value="say" onclick="submitChat(this.form)" />
</form>
</html>

  另外一个就是保存用户提交的聊天内容了,我简单的写一下文本,而且没有做什么锁定,这个只是简易版本:

<?php
$content = trim($_POST['content']);
if ($content) {
    $fp = fopen('./chat.txt', 'a');
    fwrite($fp, $content . "\n");
    fclose($fp);
    clearstatcache();
}
?>

  接下来看主要的HTTP长连接部分,也就是chat_content.php文件:

<?php
header('cache-control: private');
header('Content-Type: text/html; charset=utf-8');

//测试设置30秒超时,一般会设置比较长时间。
set_time_limit(30);

//这一行是为了搞定IE这个BT
echo str_repeat(' ', 256);

ob_flush();
flush();
$fp = new SplFileObject('./chat.txt', 'r+');
$line = 0;
$totalLine = 0;
while (!$fp->eof()) {
    $fp->current();
    $totalLine++;
    $fp->next();
}
$fp->seek($totalLine);
$i = $totalLine - 1;
while (true) {
    if (!$fp->eof()) {
        if ($content = trim($fp->current())) {
            echo '<div>';
            echo htmlspecialchars($content);
            echo "</div>";
            flush();
            $fp->next();
            $i++;
        }
    } else {
        $fp->seek($i - 1);
        $fp->next();
    }

    {
        //这里可以添加心跳检测后退出循环
    }
    usleep(1000);
}
?>

  我一行行解释一下,其实也比较容易理解:
  06. 设置一个超时时间,由于要保持HTTP长连接,这个时间肯定要比较长,可能要几个小时吧,上面提到的文章里也有说明,这种HTTP长连接只能打开两个,由于浏览器的限制。另外其实即使你设置了一个永不超时,其实上服务器部分(如Apache)的配置文件也可能对HTTP请求设置了最长等待时间,所以也可能效果会不是你想的,一般默认可能都是15分钟超时。如果有兴趣可以自己尝试修改。

  09. 这里输出了一段空白,主要是手册上已经说明了,IE浏览器在前面256个字符是不会直接输出的,所以我们先随便输出些空白,以便让后面的内容输出来,可能其他浏览器也有其他浏览器的设置,具体可以查看PHP手册的frush函数的说明。接下去11、12行就是强制把这些空白符丢给浏览器输出。

  13. ~ 20. 这里主要是为了计算文件行数,以便从这一行后面开始读内容。

  接下去的while循环就是一个死循环了,就是循环输出文件内容,每次判断是否到达文件末尾,如果有用户写入文件,则当前检测肯定不是文件末尾,就将该行读取出来输出,否则将指针往前移动一行,继续循环,每次等待1000微秒,

  39. 如果一直保持长连接,那么即使客户端断开,服务端也不一定能知道客户端已经断开,所以这里可能还需要做一些心跳记录,比如每个用户保持一个心跳flag,每格几秒更新一下最后心跳时间,当检测最后时间很久没更新后,推出这个死循环,关闭这个HTTP连接。

  OK,基本上原理就是这样了,当然这个性能不清楚,有兴趣的自己试试,欢迎交流。

VN:F [1.8.4_1055]
Rating: 7.4/10 (27 votes cast)
VN:F [1.8.4_1055]
Rating: +9 (from 11 votes)

我的第一个Windows窗体程序

By 深空, 2009年10月20日 22:20

  虽然之前也用JAVA编写过窗体程序,但毕竟不是原装的,这次采用C来写Windows窗体,发现比JAVA简单一些,HOHO

#include <windows.h>
#include <windowsx.h>

int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd) {
    MessageBox(NULL, "Hello world!", "你好世界!", MB_OK | MB_ICONASTERISK);
    return 0;
}

  采用Visual Studio 2008,创建的空项目,直接编译竟然就可以了。

我的第一个Windows窗体程序

我的第一个Windows窗体程序

VN:F [1.8.4_1055]
Rating: 7.8/10 (9 votes cast)
VN:F [1.8.4_1055]
Rating: +4 (from 8 votes)

我的新书架

By 深空, 2009年10月18日 09:59

  手头书有点小多,乱七八糟铺了一沙发,昨天去宜家买了个CD架当书架使,小一点不过貌似够用了,研究结果就是一般书架都很高,超过两米,只有几款比较矮的,另外深度都是28cm左右,其实我不太喜欢太深的书架,一方面占地方,另外一方面书陷进去很不好看。最后选了个小的CD架,这样可以放在电脑旁边,随手可以拿到咯,好了废话不多说上图:

安装中,宜家的东西都是需要动手安装的

安装中,宜家的东西都是需要动手安装的


来一张近焦的,嘿嘿

来一张近焦的,嘿嘿


只有技术书,全貌

只有技术书,全貌

VN:F [1.8.4_1055]
Rating: 7.0/10 (5 votes cast)
VN:F [1.8.4_1055]
Rating: +5 (from 5 votes)

用线性回归方法计算直线斜率

By 深空, 2009年10月13日 19:25

  最近在做设备负载预测,考虑到负载波动,需要拿出近似增长率来计算未来数天的设备负载增长状况,想想看以前的数学都没有学好,算法也没有搞好,只能求助同事和百度Google,最终还是折腾出来了。

点分布和趋近的直线

点分布和趋近的直线


  关于线性回归可以参考百度知道。其中采用最小二乘法可以比较容易的算出过往设备负载增长的斜率,具体公式如下:
最小二乘法公式

最小二乘法公式


  下面代码简单枚举历史10个点来计算该设备负载增长率:

//Y坐标值表示设备历史负载
$y = array(52.09, 52.4, 53.29, 54.22, 55.15, 55.83, 56.89, 56.98, 57.55, 57.8);

//X坐标值表示顺序天数
$x = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

//计算X和Y均值
$ax = array_sum($x)/count($x);
$ay = array_sum($y)/count($y);

//计算斜率公式中的分母(em)和分子(ez)
$em = 0;
$ez = 0;
for ($i = 0; $i < count($x); $i++) {
    //分母求和
    $em += (($x[$i] - $ax) * ($y[$i] - $ay));
    //分子求和
    $ez += pow(($x[$i] - $ax), 2);
}

//斜率0.69
echo $em/$ez;

//第十一个点预测负载值58.34
echo $em/$ez * 10 + $ay - ($em/$ez)*$ax;

  很多概念都不甚懂,反正数学是没有学好的,找来公式代一代,嘿嘿,还算可以,对于波动比较大的就比较难以预测,这个近似值还是很有参考意义的。

VN:F [1.8.4_1055]
Rating: 7.5/10 (11 votes cast)
VN:F [1.8.4_1055]
Rating: -1 (from 7 votes)

由会话重定向看到的对象销毁问题

By 深空, 2009年10月12日 15:58

  今天和同事又讨论到DB类中析构函数是否要关闭数据库连接的问题,粗略看起来貌似在DB对象销毁之前关闭数据库连接再正常不过:

class DB {
    public $conn;

    public function __construct() {
        $this->conn = mysql_connect('localhost', 'root', '');
        mysql_select_db('test', $this->conn);
    }

    public function query($sql) {
        return mysql_query($sql, $this->conn);
    }

    public function __destruct() {
        echo "destruct:close<br />";
        mysql_close($this->conn);
    }
}

  执行:

<?php
//class DB ..
$db = new DB;
?>

  正常打印 destruct:close
  再来看看下面的会话重定向到DB:

<?php

class DB {
    public $conn;

    public function __construct() {
        $this->conn = mysql_connect('localhost', 'root', '');
        mysql_select_db('test', $this->conn);
    }

    public function query($sql) {
        return mysql_query($sql, $this->conn);
    }

    public function __destruct() {
        echo "destruct:close<br />";
        mysql_close($this->conn);
    }
}

class SessionHandler {
    public static $db;

    function open() {
    }

    function close() {
    }

    function read() {
    }

    function write($id, $data) {
        echo "session:write<br />";
        $sql = "REPLACE INTO session VALUES('$id', '$data')";
        self::$db->query($sql);
    }

    function destroy() {
    }

    function gc() {
    }
}

SessionHandler::$db = new DB;
session_set_save_handler(array('SessionHandler', 'open'), array('SessionHandler', 'close'), array('SessionHandler', 'read'), array('SessionHandler', 'write'), array('SessionHandler', 'destroy'), array('SessionHandler', 'gc'));

session_start();
$_SESSION['user'] = '深空';

?>

  这次析构正常,只不过会话写入出错了,析构在会话写入之前被执行了:

destruct:close
session:write

Warning: mysql_query(): 2 is not a valid MySQL-Link resource on line 12

  厄,见鬼了吧,PHP竟然在脚本执行结束后先执行析构函数,然后才处理会话。

  我再稍微修改一下 SessionHandler:

<?php

class DB {
    public $conn;

    public function __construct() {
        $this->conn = mysql_connect('localhost', 'root', '');
        mysql_select_db('test', $this->conn);
    }

    public function query($sql) {
        return mysql_query($sql, $this->conn);
    }

    public function __destruct() {
        echo "destruct:close<br />";
        mysql_close($this->conn);
    }
}

class SessionHandler {
    function open() {
    }

    function close() {
    }

    function read() {
    }

    function write($id, $data) {
        global $db;
        echo "session:write<br />";
        $sql = "REPLACE INTO session VALUES('$id', '$data')";
        $db->query($sql);
    }

    function destroy() {
    }

    function gc() {
    }
}

$db = new DB();
session_set_save_handler(array('SessionHandler', 'open'), array('SessionHandler', 'close'), array('SessionHandler', 'read'), array('SessionHandler', 'write'), array('SessionHandler', 'destroy'), array('SessionHandler', 'gc'));

session_start();
$_SESSION['user'] = '深空';

?>

  输出如下:

destruct:close
session:write

Fatal error: Call to a member function query() on a non-object on line 35

  这次报错让我感到意外,根据提示可以认定35行的$db变量不是个对象,后来想想也确实应该是这样,因为__destruct方法已经执行了,那么其实对象在write之前已经被销毁了,所以找不到$db变量已经是空的,不足为奇。我又测试了一些字符串和数组变量,发现write执行的时候,这些变量还没有被销毁,我又做了如下修改:

<?php

class DB {
    public $conn;

    public function __construct() {
        $this->conn = mysql_connect('localhost', 'root', '');
        mysql_select_db('test', $this->conn);
    }

    public function query($sql) {
        return mysql_query($sql, $this->conn);
    }

    public function __destruct() {
        echo "destruct:close<br />";
        mysql_close($this->conn);
    }
}

class SessionHandler {
    function open() {
    }

    function close() {
    }

    function read() {
    }

    function write($id, $data) {
        global $db;
        echo "session:write<br />";
        $sql = "REPLACE INTO session VALUES('$id', '$data')";
        $db['session']->query($sql);
    }

    function destroy() {
    }

    function gc() {
    }
}

$db['session'] = new DB();
session_set_save_handler(array('SessionHandler', 'open'), array('SessionHandler', 'close'), array('SessionHandler', 'read'), array('SessionHandler', 'write'), array('SessionHandler', 'destroy'), array('SessionHandler', 'gc'));

session_start();
$_SESSION['user'] = '深空';

?>

  输出:

destruct:close
session:write

Warning: mysql_query(): 2 is not a valid MySQL-Link resource on line 12

  呵呵,这次$db没有被销毁,因为它是个数组变量,后来和同事分析觉得可能是这些变量和对象的存储方式不一样,销毁的顺序也不一样导致的。不过__destruct仍然是在write前执行,基本上可以判断会话是在很后面才执行的。要解决这个问题,只能去掉DB的__destruct方法。

  我没有去深究PHP内部对变量的处理和回收方式,只是在重定向会话处理方法的时候这个问题才显露出来,是个比较有趣的问题,发出来和大家分享我的发现主要是想让大家在碰到这个问题的时候不会太浪费时间在调试上。

  希望明真相的高手不吝指点。

VN:F [1.8.4_1055]
Rating: 6.0/10 (6 votes cast)
VN:F [1.8.4_1055]
Rating: +2 (from 4 votes)

读取和修改大文件的某行内容

By 深空, 2009年09月27日 21:17

  最近碰到一个比较有趣的问题,就是修改某个文件的某一行字符,不过文件太大,file()直接读取是不可能的,我使用fgets来跳转到指定行,并用fwrite修改某个字符串:

$fp = fopen('d:/file.txt', 'r+');
if ($fp) {
    $i = 1;
    while (!feof($fp)) {
        //修改第二行数据
        if ($i == 2) {
            fseek($fp, 2, SEEK_CUR);
            fwrite($fp, '#');
            break;
        }
        fgets($fp);
        $i++;
    }
    fclose($fp);
}

  这里需要注意的是fgets获取到一行后,文件指针指向行尾(也就是下一行开头),所以fwrite操作的是fgets后的下一行开头,至于从该行的第几个字符开始写,可以使用fseek函数来移动文件指针。另外一个需要注意的是,这里fwrite写入是执行替换操作,而不是插入操作,所以指针后面的字符会一个个被替换掉。至于怎么插入我就没研究了。估计很困难。为了效率可能只能写入另外一个临时文件了,不知道有没有其他更好的方法。

  另外今天还看到了使用SPL进行操作的方法:

$fp = new SplFileObject('d:/file.txt', 'r+');
//转到第二行, seek方法参数从0开始计数, 经我测试指针指向行尾了, 所以修改的是第三行
$fp->seek(1);
//获取当前行内容(第二行)
$line = $fp->current();
//下面是对第三行的操作
$fp->fseek(2, SEEK_CUR);
$fp->fwrite('#');

  SplFileObject提供的方法比基本的文件操作函数更丰富一些,包括采用key/value方法遍历文件行等。SPL应该是PHP5增加进去的吧,还有其他很多很有用的对象。包括数组、文件目录操作、异常处理、一些基本类型操作等,这些功能还在陆续增加,可以通过继承SPL扩展这些方法让我们处理底层的操作更方便。

VN:F [1.8.4_1055]
Rating: 7.8/10 (14 votes cast)
VN:F [1.8.4_1055]
Rating: +3 (from 5 votes)

入手两台BENQ G2220HD

By 深空, 2009年09月27日 19:10

  为了省去和电视机来回切换的麻烦,昨天入手了两台BENQ G2220HD,换下当前的DELL 2209WA,问我为什么换下IPS屏而用TN屏呢,因为这个是1920*1080分辨率,DELL这台只有1680*1050,以前买台17′CRT的价格可以买现在两台22′LCD,呵呵,两台嘛,一台送姐姐。这样换下来的DELL 2209WA准备拿公司里用。

  BENQ这个是目前我看了最便宜的型号,当然我比较少作图,所以比较无所谓,至于看电影有电视机。分辨率和价格是我选择它的主要原因,HOHO。外观也还可以,就是竟然不带DVI线。

BENQ G2220HD

BENQ G2220HD


  另外赞一下Windows7的显示设置,设置分辨率比以前方便多了,支持多种模式,包括复制、扩展等。
Windows7的显示设置

Windows7的显示设置

VN:F [1.8.4_1055]
Rating: 8.3/10 (4 votes cast)
VN:F [1.8.4_1055]
Rating: +2 (from 2 votes)

京ICP备05002071号 ©2003-2009 深空