你还要些什么

 

《财经》

------

    2503年,一个婴儿养育室里。护士们在地板上摆了一堆图书和鲜花,然后把一群长得一摸一样的、8个月大的婴儿放到了地板上。婴儿们看到图书和鲜花,飞快地爬过去,拿起来玩耍。这时候,长官一声令下,护士长启动电路装置,一时间,刺耳的警报响起,地板被通上了电,触电的婴儿们在痛苦中痉挛并尖叫不已。过了一会儿,护士长关上了电闸。

    “这样的试验大约重复200次左右,”长官微笑着对参观者说:“这些孩子们就会对图书和花朵形成本能的憎恨,他们的条件反射就这样被限定了。”

    “限定”,大约是《Brave New World》一书中的最关键词汇。在Aldous Huxley笔下的那个美好盛世里,人从受精开始就被“限定”了。精子和卵子在试管里被调制好,不健康的胚胎被“限定”出局,健康胎儿在孵化器里长大。然后从婴儿养育室开始,孩子们一路被“限定”得厌恶书籍和自然、厌恶独处、厌恶家庭、厌恶宗教和艺术,同时被“限定”得热爱集体、热爱消费、热爱滥交。

    当然,并不是所有的人被限定的方式都一样。美好新世界里,人类被分成了五级,Alpha、Beta、Gamma、Delta以及Epsilon——Alpha被限定得聪明漂亮,而Gamma以下的人不但被限定得矮小愚钝,还批量生产。不过没关系,虽然在那个世界里人有等级贵贱,但是他们都一样幸福——因为无论哪个等级,其接受的“睡梦教育”都会告诉他,他所在的等级最美好最幸运。

    这样的世界,有什么问题吗?

    美好新世界的首长Mustapha,问质疑者“野人”John。

    有什么人类跋山涉水追求了几千年的东西,新世界里没有呢?经济发展?新世界里如此富足,上至Alphas下至Epsilons,人们不愁吃穿。健康?生物学家们早就把人类限定得不再有疾病。青春?这里人们青春永驻,直到突然死亡。美女帅哥的青睐?这个更不用担心,因为新世界里“每个人都属于他人”,滥交是最大的美德,你要是长期只跟一个美女上床,会成为该世界里骇人的丑闻。

    不错,这个世界里没有艺术、诗歌、撕心裂肺的爱情、没有毕加索或者莎士比亚,但是,当你每天都幸福得晕眩时,为什么还会需要毕加索或者莎士比亚?文学艺术往往是为了表达冲突超越痛苦,那么,在一个冲突和痛苦根本不存在的世界里,文学艺术也就变成了社会的阑尾。更不要说“爱情”,那简直是高速公路上突然蹦出来的一头羚羊,如此危险,通通地,限定了之。

    所以,这样的世界,有什么问题吗?

    柏拉图估计不会觉得有什么问题,因为新世界里政治家和科学家就是智慧非凡的哲学王。老子估计也不会觉得有什么问题,“劳心者治人,劳力者治于人”在这个桃花源里被充分实施。希特勒更是会欣喜若狂,因为将人类的未来当作一个巨大的生物工程来建设,简直是他的毕生追求。还有斯大林,荡漾在新世界人们脸上的微笑,与沉浸在丰收喜悦里的社会主义农民如出一辙,而新世界的“睡梦教育”,简直可以说是对苏式灌输教育赤裸裸的抄袭。所有那些信奉“精英治国”、信奉“稳定高于一切”、信奉“老百姓无非就是关心吃饱穿暖”的人,都会是“美好新世界”的热情粉丝。

    这个新世界如此美好,它只有一个小小的缺陷——在那里,幸福的人们全都是“被幸福”的。

    就是说,在那里,人们的幸福是政治家和科学家呕心沥血的科研成果,与每个个体自己的创造力、情感体验能力、审美能力都毫无关系。 民众只需像儿童那样,系上围兜,张口吞下哲学王或者先锋队一勺一勺送过来的食物,就乘坐直升电梯抵达了极乐世界。而精英们为了民众,制作食物既考虑营养,又考虑消化,可以说是殚精竭虑。有如此鞠躬尽瘁的统治者,民众的个体自由意志完全是多此一举。 如果说奥威尔的《1984》里,人们为失去自由而痛苦,那么Huxley的《勇敢新世界》里,人们则为摆脱了自由的重负而狂喜。真的,如果政治家科学家给民众带来如此丰盛的快乐,民众何必要自己去斗争?就像如果你可以从父亲那里继承一大笔遗产,何必要自己去辛苦挣钱?除非——

    你认为得到的过程比得到本身更有意义。除非你不识抬举地认为,通过个体努力去争取幸福比“被幸福”更体现生命的价值。

    也正是在这个意义上,我在一切精英治国观里读到的是对生命的藐视。当统治者的恩赐被视为民众幸福的源泉时,统治者越高大,民众就越渺小。对有些人来说,幸福如此简单,无非是对着送过来的汤勺不断张嘴,而对另一些人来说,它如此复杂,需要汗滴禾下土粒粒皆辛苦。由于运气和能力,也许耕耘未必能带来收获,但是恩赐来的幸福和捕猎来的痛苦之间,你选什么呢?在幸福药丸soma和跌宕起伏的莎士比亚之间,野人John选择了莎士比亚。但是当然,对于美好新世界里的绝大多数人,这根本不是一个问题。他们从来没有选择的权利,无处不在的幸福不由分说,一把把他们给罩住,他们只能躺在幸福的牙缝里,被咀嚼,然后变成一堆残渣,被气势磅礴地给吐出来。

《Head First 设计模式》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)

?>

服务器推技术简介及php实现服务器推技术的聊天室

IBM:Comet:基于 HTTP 长连接的“服务器推”技术

DEMO1:

  首先是首页,包含一个文本输入和一个显示聊天内容的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连接。

 

 

DEMO2:

 

传统的B/S结构的应用程序,都是采用\"客户端拉\"结束来实现客户端和服务器端的数据交换。 

本文将通过结合Ticks,来实现一个服务器推的PHP聊天室简单构想。 

 

PHPer,尤其是用过set_cookie, header的,一定见过这样的提示信息:\"Warning: Cannot modify header information - headers already sent by.....\", 这是因为通过HTTP协议通信,数据包会包含俩个部分,一个是Header,一个是data。一般来说,都是先Header部分,在Heaer部分指明了Data部分的长度,然后使用\\r\\n\\r\\n来表示header部分结束,接下来是Data部分。 

 

当我们有任何输出的时候,Header部分就发送了,这个时候,你再想header函数来改变一些Header部分的域信息,就会得到上面的提示信息。 

    

一个简单的办法就是使用output_buffering。让它来缓存服务器的输出,不要太早将Header部分发给客户端。 

 

那么,如果不使用output_buffering,是不是就可以实现,每当服务器有输出,就立即发送给客户端呢? 

 

做个如下试验://设置php.ini中output_buffering=0 或者使用ob_end_flush()关闭缓存 

 

set_time_limit(0); 

for($i=0;$i<10;$i++){ 

  echo \"Now Index is :\". $i; 

  sleep(1); 

  结果我们发现,还是要等到脚本全部执行完以后,才能一次看到所有的结果。。 

  为什么呢? 

  这是因为我们只是解决了缓存问题,但是还有一个缓冲问题,PHP会缓冲程序的输出。所以,这个时候,我们还需要调用,flush(), 来强制使得PHP将所有的程序输出发送给客户端。//设置php.ini中output_buffering=0 

ob_end_flush();//关闭缓存 

 

set_time_limit(0); 

for($i=0;$i<10;$i++){ 

  echo \"Now Index is :\". $i; 

  flush(); 

  sleep(1); 

    现在是不是看到了,不断有服务器的数据显示出来? 

 

    有几个概念之间的关系,我这里补充以下: 

    在代码中使用ob_start(), 就相当于在php.ini中使用output_buffering=on一样,使用服务器缓存。 

    在代码中使用ob_end_flush() 就相当于在php.ini中使用output_buffering = false一样,关闭服务器缓存。 

     

     基于前面的讨论,我们就有可能使用Ticks来实现,一个无刷新,无ajax的聊天室: 页面中包含俩个iframe,一个是不断获取聊天室的聊天内容,一个包含用户发表聊天内容的form. 这样,在第一个frame的脚本中: 

ob_end_clear();//关闭缓存 

set_time_limit(0); 

ob_implicit_flush(); //这个语句将强制每当有输出就自动刷新,相当于在每个echo后,调用flush() 

$new_mesg = NULL; 

register_tick_function(\"getNewMesg\"); 

declare(ticks=1){ 

  while(1){ 

     if(!is_null($new_mesg)){ 

          foreach($new_mesg as $msg){ 

                echo $msg; 

          } 

          $new_mesg = null; 

     }      

  } 

 

function getNewMesg(){ 

//通过查询数据库,或者共享内存,来获取现在的聊天室大厅的内容。 

//返回一个数组,包含所有的新的聊天内容 

 

 这样就实现了一个简单的使用服务器推技术的聊天室的框架。 

 当然,关于实时输出,还有一些其他的限制,比如在PHP5手册中讲到的: 

个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。 

 

有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。 [Page]

 

甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在接受到 </table> 标记之前,不会显示出整个表格。 

 

一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。 

 

 接下来,我贴一个很有趣的代码,有兴趣的同学,可以试试: 

<?php

header('Content-type: multipart/x-mixed-replace;boundary=endofsection'); 

print "endofsection"; 

for( $i = 0; $i <10;$i ++ ) 

        sleep(1); 

        print "Content-type: text/plain "; 

        print "Part $i "; 

        print "--endofsection "; 

        ob_flush(); //强制将缓存区的内容输出 

        flush(); //强制将缓冲区的内容发送给客户端 

  } 

print "Content-type: text plain "; 

print "The end "; 

print "--endofsection-- ";

 

?>

 

  使用firefox打开,看看你看到了什么。 

  这个例子,使用了ob_flush(), 这样可以在代码中控制缓存区内容的输出时机,更加灵活一些。

深入Mysql字符集设置

基本概念

• 字符(Character)是指人类语言中最小的表义符号。例如’A’、’B’等;

• 给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给字符’A’赋予数值0,给字符’B’赋予数值1,则0就是字符’A’的编码;

• 给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就是字符集(Character Set)。例如,给定字符列表为{’A’,’B’}时,{’A’=>0, ‘B’=>1}就是一个字符集;

• 字符序(Collation)是指在同一字符集内字符之间的比较规则;

• 确定字符序后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;

• 每个字符序唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);

• MySQL中的字符序名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感)、_cs(表示大小写敏感)或_bin(表示按编码值比较)结尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等价的;

 

MySQL字符集设置

• 系统变量:

– character_set_server:默认的内部操作字符集

– character_set_client:客户端来源数据使用的字符集

– character_set_connection:连接层字符集

– character_set_results:查询结果字符集

– character_set_database:当前选中数据库的默认字符集

– character_set_system:系统元数据(字段名等)字符集

– 还有以collation_开头的同上面对应的变量,用来描述字符序。

• 用introducer指定文本字符串的字符集:

– 格式为:[_charset] ’string’ [COLLATE collation]

– 例如:

• SELECT _latin1 ’string’;

• SELECT _utf8 ‘你好’ COLLATE utf8_general_ci;

– 由introducer修饰的文本字符串在请求过程中不经过多余的转码,直接转换为内部字符集处理。

MySQL中的字符集转换过程

1. MySQL Server收到请求时将请求数据从character_set_client转换为character_set_connection;

2. 进行内部操作前将请求数据从character_set_connection转换为内部操作字符集,其确定方法如下:

• 使用每个数据字段的CHARACTER SET设定值;

• 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);

• 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

• 若上述值不存在,则使用character_set_server设定值。

3. 将操作结果从内部操作字符集转换为character_set_results。

图片1

常见问题解析

• 向默认字符集为utf8的数据表插入utf8编码的数据前没有设置连接字符集,查询时设置连接字符集为utf8

– 插入时根据MySQL服务器的默认设置,character_set_client、character_set_connection和character_set_results均为latin1;

– 插入操作的数据将经过latin1=>latin1=>utf8的字符集转换过程,这一过程中每个插入的汉字都会从原始的3个字节变成6个字节保存;

– 查询时的结果将经过utf8=>utf8的字符集转换过程,将保存的6个字节原封不动返回,产生乱码……

图片2

• 向默认字符集为latin1的数据表插入utf8编码的数据前设置了连接字符集为utf8

– 插入时根据连接字符集设置,character_set_client、character_set_connection和character_set_results均为utf8;

– 插入数据将经过utf8=>utf8=>latin1的字符集转换,若原始数据中含有\u0000~\u00ff范围以外的Unicode字 符,会因为无法在latin1字符集中表示而被转换为“?”(0×3F)符号,以后查询时不管连接字符集设置如何都无法恢复其内容了。

图片3

检测字符集问题的一些手段

• SHOW CHARACTER SET;

• SHOW COLLATION;

• SHOW VARIABLES LIKE ‘character%’;

• SHOW VARIABLES LIKE ‘collation%’;

• SQL函数HEX、LENGTH、CHAR_LENGTH

• SQL函数CHARSET、COLLATION

使用MySQL字符集时的建议

• 建立数据库/表和进行数据库操作时尽量显式指出使用的字符集,而不是依赖于MySQL的默认设置,否则MySQL升级时可能带来很大困扰;

• 数据库和连接字符集都使用latin1时虽然大部分情况下都可以解决乱码问题,但缺点是无法以字符为单位来进行SQL操作,一般情况下将数据库和连接字符集都置为utf8是较好的选择;

• 使用mysql C API时,初始化数据库句柄后马上用mysql_options设定MYSQL_SET_CHARSET_NAME属性为utf8,这样就不用显式地用 SET NAMES语句指定连接字符集,且用mysql_ping重连断开的长连接时也会把连接字符集重置为utf8;

• 对于mysql PHP API,一般页面级的PHP程序总运行时间较短,在连接到数据库以后显式用SET NAMES语句设置一次连接字符集即可;但当使用长连接时,请注意保持连接通畅并在断开重连后用SET NAMES语句显式重置连接字符集。

其他注意事项

• my.cnf中的default_character_set设置只影响mysql命令连接服务器时的连接字符集,不会对使用libmysqlclient库的应用程序产生任何作用!

• 对字段进行的SQL函数操作通常都是以内部操作字符集进行的,不受连接字符集设置的影响。

• SQL语句中的裸字符串会受到连接字符集或introducer设置的影响,对于比较之类的操作可能产生完全不同的结果,需要小心!

MySQL 编码机制

 

一般在MYSQL使用中文查询 都是用 set NAMES character

character_set_client ,这是用户告诉MySQL查询是用的什么字符集。 

character_set_connection ,MySQL接受到用户查询后,按照character_set_client将其转化为character_set_connection设定的字符集。 

character_set_results , MySQL将存储的数据转换成character_set_results中设定的字符集发送给用户。 

 

DISCUZ并没有使用set NAMES character 

SET NAMES 'x'语句与这三个语句等价: 

mysql> SET character_set_client = x; mysql> SET character_set_results = x; mysql> SET character_set_connection = x; 

 

而DISCUZ里面是 

@mysql_query("SET character_set_connection=$dbcharset, character_set_results=$dbcharset, character_set_client=binary", $this->link); 

 

SET character_set_client = binary;使用二进制字符集查询 

此三处的字符设定很大程度上会解决乱码问题,那么着三个设定具体有什么作用呢? 

character_set_client指定的是Sql语句的编码,如果设置为 binary,mysql就当二进制来处理,character_set_connection指定了mysql 用来运行sql语句的时候使用的编码,也就是说,程序发送给MySQL 的SQL语句,会首先被MySQL从character_set_client指定的编码转换到character_set_connection指定的编码,如果character_set_clien指定的是binary,则MySQL就会把SQL语句按照character_set_connection指定的编码解释执行. 

当执行SQL语句的过程中,比如向数据库中插入字段的时候,字段也有编码设置,如果字段的编码设置和character_set_connection指定的不同,则MySQL 会把插入的数据转换成字段设定的编码。SQL语句中的条件判断和SQL插入语句的执行过程类似. 

当SQL执行完毕像客户端返回数据的时候,会把数据从字段指定的编码转换为character_set_results指定的编码,如果character_set_results=NULL 则不做任何转换动作,(注意这里设置为NULL不等于没有设置,没有设置的时候MySQL会继承全局设置), 

工作中比较有用的就是利用MySQL进行转码、不同编码的数据库之间共用数据。

MySQL客户端HeidiSQL

 

HeidiSQL个人使用感受如下:

 

体积小,安装文件只有1.7M

 

速度:操作流畅,终于不卡了

 

用户体验:,查看表数据和结构只需要切换选项卡即可,不需要复杂鼠标的操作

 

高级功能,提供查看数据库状态和维护功能

 

不足:不能图形管理触发器和作业

 

最后还要注意一点:HeidiSQ是开源免费的

 

HeidiSQL 是一个功能非常强大的 MySQL 客户端软件,采用 Delphi 开发,支持 Windows 操作系统

 

 

HeidiSQL官方:http://www.heidisql.com/

 

HeidiSQL下载:http://www.heidisql.com/download.php