分类目录归档:未分类

Paypal API

Paypal提供了两套API,REST API和NVP/SOAP API。REST API没有完全覆盖NVP API的功能,NVP API历史久远,未来应该会被REST API替换。

REST API使用OAuth2标准,首先需要有一个开发者账户,然后在开发者账户中创建APP(产生client_id, client_secret),Paypal账户授权给这个APP。

开发者网站:http://developer.paypal.com,然后需要注册一个真实的Paypal账户(可以个人,也可以商用),拿这个账户作为开发者账户去登录,然后就可以创建APP,分两个环境:正式和测试。如何创建一个测试APP,那么会自动给你创建一个测试商家账户,还有一个买家账户。当然也可以自己建多个测试账户。

——————————————————————-
在REST API之前,只有NVP API。为了可以使用NVP API,需要到自己的Paypal中的API设置中取到相关API签名(API用户名和密码,以及签名),只要暴露了这三个信息,就相当于是开放了自己的账户。

每个Paypal可以作为一个第三方,其它的Paypal账户如果把某些权限赋给了它,它就可以扮演第一方的身份去获取信息。关于权限赋予的流程,官方文档有详细描述。而Paypal后台的第三方许可,实际对应这个操作,最终都是赋予第三方权限。

这里需要输入的就是第三方Paypal账户的API的用户名(每个账户中的API签名部分),点击查找后会让你选择哪些权限赋予这个第三方:

结论:Paypal可以通过API签名开放账户,也可以把权限授予其它账户,由其它账户(第三方)代理访问。

<?php

namespace Paypal;

class Api
{
    protected $username = '';

    protected $password = '';

    protected $signature = '';

    protected $version = '95.0';

    protected $endPoint = 'https://api-3t.paypal.com/nvp';

    protected $subject = '';

    public function __construct($username, $password, $signature, $subject = '', $sandbox = false)
    {
        $this->username = $username;
        $this->password = $password;
        $this->signature = $signature;
        if (!empty($subject)) {
            $this->subject = trim($subject);
        }
        if ($sandbox) {
            $this->endPoint = 'https://api-3t.sandbox.paypal.com/nvp';
        }
    }

    // 作为第三方访问Paypal
    public function setSubject($email)
    {
        $this->subject = trim($email);
    }

    // 取回交易列表
    //$params = [
    //    'STARTDATE' => $startTime,
    //    'ENDDATE' => $endTime,
    //    'RECEIVER' => '',
    //    'TRANSACTIONCLASS' => 'All'
    //];
    public function getTransactions(array $params)
    {
        $return = ['success' => 0, 'message' => '', 'data' => []];
        if (empty($params['STARTDATE']) || empty($params['ENDDATE'])) {
            $return['message'] = '参数不合法';
            return $return;
        }

        $result = $this->post('TransactionSearch', $params);
        if (false === $result) {
            $return['message'] = 'CURL请求异常';
            return $return;
        }

        $tarr = explode('&', $result);
        $data = [];
        foreach ($tarr as $item) {
            $tmp = explode('=', rawurldecode($item));

            preg_match('/^L_([a-zA-Z\_]+)([0-9]+)/', $tmp[0], $m);
            if (isset($m[0]) && isset($m[1]) && isset($m[2])) {
                $data[$m[1]][$m[2]] = trim($tmp[1]);
            } else {
                $data[$tmp[0]] = trim($tmp[1]);
            }
        }

        // ACK 等于 Warming时,数据返回不齐全(Paypal每次查询最多返回100条)
        if (empty($data['ACK']) || ($data['ACK'] == 'Failure')) {
            $return['message'] = "API调用ACK返回Failure";
        } else {
            $return['success'] = 1;
            $return['data'] = $data;
        }

        return $return;
    }
 
    // 通用封装
    protected function post($api, array $params)
    {
        $global = [
            'METHOD' => $api,
            'VERSION' => $this->version,
            'USER' => $this->username,
            'PWD' => $this->password,
            'SIGNATURE' => $this->signature
        ];
        if (!empty($this->subject)) {
            $global['SUBJECT'] = $this->subject;
        }

        return $this->doRequest($this->endPoint, array_merge($global, $params));
    }

    // CURL请求
    protected function doRequest($url, $data)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HEADER, '');
        curl_setopt($ch, CURLOPT_URL, trim($url));
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 90);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
        if (!empty($data)) {
            if (is_array($data)) {
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            } elseif (is_string($data)) {
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            }
        }
        if (\PHP_OS === 'WINNT') {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0");
        $result = curl_exec($ch);
        $error = curl_errno($ch);
        curl_close($ch);
        if ((int)$error == 0) {
            return $result;
        }
        return false;
    }
}

浏览器编程:WebDriver – ChromeDriver

浏览器编程有两个主要应用:
1 自动化测试
2 通过浏览器自动抓取内容(针对防抓的网站,模拟人工点击)

Selenium Server只是作为一个代理,它的作用是当要驱动远程浏览器(驱动一般只能监听本地端口),或需要驱动不同版本的浏览器时会有很大的作用。否则,应用程序直接面对具体的驱动即可(Selenium Server仅转发Json)。
注意:PhantomJS视乎是没有提供驱动,为了驱动这个无头浏览器,Selenium Server应该是把Json数据转换成了JS脚本让其执行(未证实)

目前主流浏览器(Chrome Firefox)都提供了WebDriver的实现,比如Chrome对应的是ChromeDriver,Firefox对应的FirefoxDriver。注:WebDriver只是一个规范标准(https://w3c.github.io/webdriver/webdriver-spec.html),而实现的方式可以不同,而https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol这里描述的就是一种实现方式,任何实现了这个规范的驱动,都具有相同的API。

WebDriver is an open source tool for automated testing of webapps across many browsers. It provides capabilities for navigating to web pages, user input, JavaScript execution, and more. ChromeDriver is a standalone server which implements WebDriver’s wire protocol for Chromium. ChromeDriver is available for Chrome on Android and Chrome on Desktop (Mac, Linux, Windows and ChromeOS).
ChromeDriver是一个实现了WebDriver无线协议的独立服务器,所以需要下载这个服务器(驱动,启动后在本地监听9515端口,所有的操作发送到9515端口,这个驱动负责解析数据并操作浏览器,所以它是一个中间件)。

下载地址:https://sites.google.com/a/chromium.org/chromedriver/downloads(有三个平台,需要注意的是不同的版本对应的Chrome版本是不同的)。

关于使用,ChromeDriver提供了一个文档:
https://sites.google.com/a/chromium.org/chromedriver/getting-started(关键点:Chrome需要安装在默认位置(否则需要指定),下载正确的ChromeDriver版本)

ChromeDriver作为一个独立的服务,可以手动启动并监控,也可以在使用SDK中提供的方法启动。

#####
@RunWith(BlockJUnit4ClassRunner.class)
public class ChromeTest extends TestCase {

  private static ChromeDriverService service;
  private WebDriver driver;

  @BeforeClass
  public static void createAndStartService() {
    service = new ChromeDriverService.Builder()
        .usingDriverExecutable(new File("path/to/my/chromedriver"))
        .usingAnyFreePort()
        .build();
    service.start();
  }

  @AfterClass
  public static void createAndStopService() {
    service.stop();
  }

  @Before
  public void createDriver() {
    driver = new RemoteWebDriver(service.getUrl(),
        DesiredCapabilities.chrome());
  }

  @After
  public void quitDriver() {
    driver.quit();
  }

  @Test
  public void testGoogleSearch() {
    driver.get("http://www.google.com");
    // rest of the test...
  }
}

####独立启动
$ ./chromedriver
Started ChromeDriver
port=9515
version=14.0.836.0

WebDriver driver = new RemoteWebDriver("http://127.0.0.1:9515", DesiredCapabilities.chrome());
driver.get("http://www.google.com");

####PHP
$service = new \Facebook\WebDriver\Chrome\ChromeDriverService(‘path/to/my/chromedriver’, 9515);
$service->start();
$service->stop();

$driver = RemoteWebDriver::create( $service->getURL(),[
                ChromeOptions::CAPABILITY => $options,
                WebDriverCapabilityType::PROXY => [
                    'proxyType'=> 'manual',
                    'httpProxy' => 'SOCKS5://127.0.0.1:1086',
                    'sslProxy' => 'SOCKS5://127.0.0.1:1086',
                    'socksProxy' => 'SOCKS5://127.0.0.1:1086'
                ]]);

ChromeDriver实际释放的是一套RESTfull API,可以参考:https://chromium.googlesource.com/chromium/src/+/master/docs/chromedriver_status.md,所以只要按照规范发送数据即可,也可以使用SDK,比如PHP,Facebook提供了一套实现:

composer require facebook/webdriver

应用实例:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Laravel\Dusk\Chrome\ChromeProcess;
use Laravel\Dusk\Browser;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
use Facebook\WebDriver\Remote\DriverCommand;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;

class Test extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //$process = (new ChromeProcess())->toProcess();
        //$process->start();

        try {
            // 取回已经打开的SessionID
            $reuseSessionId = '51492cf202343defea198867e32a81e3';
            try {
                $driver = $this->driverBy($reuseSessionId);
            } catch (\Exception $e) {
                $driver = $this->driver();
            }

            $driver->execute(DriverCommand::CLICK);
        } catch (\Exception $e) {
            echo 'Browser can not start up: ' . $e->getMessage();
            return;
        }

        // 取回所有SESSION
        print_r($driver->getAllSessions('http://localhost:9515'));

        $sessionID = $driver->getSessionID();
        echo "\n";
        echo $sessionID;
        echo "\n";

        $browser = new Browser($driver);
        $browser->visit('https://www.baidu.com/')->type("#kw", 'ip')->press("#su");
        $browser->visit('https://www.amazon.com');

        $driver->close();
        $driver->get('http://blog.ifeeline.com');
    }

    protected function driverBy($sessionId)
    {
        $driver = RemoteWebDriver::createBySessionID($sessionId, 'http://localhost:9515');
        $driver->execute(DriverCommand::CLICK);

        return $driver;
    }

    protected function driver()
    {
        $options = (new ChromeOptions)->addArguments([
            //'--disable-gpu',
            //'--headless'
        ]);

        return RemoteWebDriver::create(
            'http://localhost:9515',
            [
                ChromeOptions::CAPABILITY => $options,
                WebDriverCapabilityType::PROXY => [
                    'proxyType'=> 'manual',
                    'httpProxy' => 'SOCKS5://127.0.0.1:1086',
                    'sslProxy' => 'SOCKS5://127.0.0.1:1086',
                    'socksProxy' => 'SOCKS5://127.0.0.1:1086'
                ]
            ]
        );

        /*
        return RemoteWebDriver::create(
            'http://localhost:9515',
            DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )->setCapability(
                WebDriverCapabilityType::PROXY,
                [
                    'proxyType'=> 'manual',
                    'httpProxy' => 'SOCKS5://127.0.0.1:1086',
                    'sslProxy' => 'SOCKS5://127.0.0.1:1086',
                    'socksProxy' => 'SOCKS5://127.0.0.1:1086'
                ]
            )
        );
        */
    }
}

在控制浏览器上,可以应用了–disable-gpu和–headless,这样就是一个无头浏览器了(不显示具体的过程)。另外,在创建的浏览器时,可以指定代理。另外,如果一个SESSION没有正确退出,那么它还是活动的,但是它却无法重用。在知道SESSIONID的情况下,SESSION可以重用。 一般来说,进行一个任务就开启一个浏览器,完毕后正常退出记录。

Laravel中的Dusk程序包,封装的更加狠一些,连ChromeDriver二进制程序包都拉取回来,自动启动监听,对个Facebook SDK进行二次封装,使API更加友好。

如果模拟人工进行大量操作,就会频繁启动关闭浏览器,实际上,浏览器启动后对应一个SESSION,接下来只要重用这个SESSION即可,基本思路:如果当前有可重用的SESSION,就重用,没有就新建;在任务执行完后,判断SESSION是否超过了最大值,超过则关闭,否则,标记该SESSION可重用(配合定时重启脚本,防止意外)。

Mac 定义自己的系统

苹果Mac系列产品:
MacBook Air 轻薄本,主流11和13英寸
MacBook Pro 笔记本,主流13,15英寸
Mac mini 一个盒子(可看做是一个主机,普通主机或服务器)
iMac 一体机
Mac Pro 台式机

OS X扫盲
OS X是一个基于Unix Darwin内核构建的系统。

每个用户对应/Users目录下的一个以用户名称命名目录(一般是如此)。所有与用户相关的内容都在这个目录内。

Finder是一个资源管理器。
Dock是一个工具栏,是一个资源访问的快捷方式。

OS X中,磁盘映像文件后缀名是dmg,双击dmg文件可以直接打开,然后在Finder左边的设备总可以找到挂接好的磁盘映像。

OS X中,安装一个软件实际就是打开dmg文件并启用的应用拖入/Application,卸载就是从其中删除。

OS X 下的大部分软件具备状态保持的功能(记住上次打开的状态)

快捷键
Mac的键盘跟Windows键盘有一些不一样。有些键没有,比如Home和End键和PageUP和PageDown和Backspace,另外ALT键也叫Option键,Windows中的Wind键对应Command键。

具体的快捷键可以参考:https://support.apple.com/zh-cn/HT201236

最常用的复制粘贴等组合键,在Mac中用Command对应Control键:Control + C对应Command + C。

为了高效工作,以下键必须记一记:

Command + Tab		向前循环切换应用程序
Shift + Command + Tab	向后循环切换应用程序
Command + Delete	把选中的资源移到废纸篓
Shift + Command + Delete清空废纸篓(清空回收站,提示)
Command + ~		同一个应用多窗口切换(开了多窗口是有用)
Command + C/V		复制粘贴
Command + Option + V	移动(先复制,后粘贴,类似剪贴)
Command + N		新建应用程序窗口
Command + Q		退出应用程序(一个应用可以开多窗口,窗口的叉表示关闭窗口,而应用未关闭)
Command + +/-		放大缩小字体
Control + Space		输入法切换
Command + Space		调出Spotlight


FN + 左键 		HOME
FN + 右键     		END
FN + 上键 		PageUP
FN + 下键 		PageDown
FN + DELETE 		后删除(CTR + D)

比较遗憾的是,最小化所有窗口没有找到对应的快捷键(Option + Command + H再结合Command + M)。

鼠标与触摸板
系统偏好设置 – 鼠标

其中滚动方式:自然,默认是勾上的,这个和Window下的默认设置刚好相反,所以如果不习惯需要去掉勾选。

系统偏好设置 – 触控板

1 光标与点按
一般都勾上,单个手指轻按模拟鼠标左键点击,两个手指轻安模拟鼠标右击,三个手指轻击进行文本查询(比如翻译)
2 滚动与缩放
两个手指触摸移动模拟鼠标滚动,不勾上时,方向和Window一样。
3 更多手势
三个手指向上滑动(Mission Control),四个手指抓(LaunchPad),四个手指快速展开(显示桌面)

另外,如果需要使用触控板来实现拖动窗口,就复杂一些:
系统偏好设置 – 辅助功能 – 鼠标与触控板 – 触控板选项

启动三指拖动。

Dock
Dock就是一个停靠条。默认放在最下方。可以通过简单拖放的方式,把应用放到Dock中,以一目了然地知道启动了那些应用以及快速管理常用的应用。

注意:连按窗口标题栏以 这里默认是最小化,可以宣威缩放,这样就可以实现最大化。

AppStore
这个就是安装App的入口,里面有非常多的软件,一般建议注册个apple id,然后通过AppStore来进行安装应用,AppStore是无法包含所有应用。可以直接下载第三方应用镜像包来进行安装。一般是dmg镜像,双击自动进行挂载斌打开镜像包,然后把应用直接拖入Application文件夹就完成安装(当然也可以来一个安装步骤导向)。


工具:

1 搜索
Spotlight 是OS X 自带的搜索工具(Command + Space)。

2.Launcher(应用程序 – Launcher,有对应手势:抓动作)
Launcher(启动器)的主要作用之一就是快速定位并启动应用程序。

开发工具:
SecureCRT(收费)
Chrome + SwitchyOmega
FireFox
SourceTree
PhpStorm(收费)
Navicat(收费)
TeamView
VMware Fusion(收费)
VirtualBox
FileZilla

Microsoft Office (收费)
钉钉
QQ

Avast Security(家庭免费版)
ShadowsocksX-NG
PDF Reader

Mac 文件共享与远程虚拟机映射

在Mac中设置共享文件夹:

系统偏好设置 – 共享 – 文件共享:选择要共享的文件夹(不能自定义名字),选择用户和用户权限,然后点击“选项”:

如果使用SMB来共享,需要按照”Windows文件共享”说明来设置(大体就是设置一个跟系统不一样的密码,这个密码专门让Window来存储)。

在远程机器上,可以mount这个共享:

#CentOS 
yum install cifs-utils
#Ubuntu
sudo apt-get install cifs-utils

然后安装如下脚本格式进行Mount:

#mount共享文件夹
mount -t cifs //192.168.1.121/www /var/www -o username=administrator,password='xxx',uid=1000,gid=1000

如果远程机器是Windows,那么直接使用映射即可。

其它参考:http://blog.ifeeline.com/2512.html

Laravel PhpStorm 使用

可以直接到官网下载:http://www.jetbrains.com/phpstorm/download/,默认提供30天的试用。建议购买正版,目前看到一年的标价是USD 159。也可以先下载官方免费的Toolbox,网址:http://www.jetbrains.com/toolbox/app,这个工具提供了非常便利的软件安装,启动,升级更新等操作,如果还有其它的系列的软件需要使用,比如WebStorm,这个Toolbox也可以很好的管理。

首先建议更换皮肤(File – Setting – Appearance):

这是一个黑色皮肤,非常护眼,建议使用。

第二就是知道可以安装插件,位置:File – Setting – Plugin,有大量第三方查看可用。

PhpStorm常用快捷键:

    全局搜索(ctrl + shift + F)
    显示类中的方法 (ctrl + 7)
    函数追踪 (ctrl +鼠标点击)
    单行注释/取消(ctrl + /)
    输入行号跳到某一行(ctrl + l)
    列出打开的文件(ctrl + e)
    删除当前行(ctrl + x)
    复制当前行(ctrl + d)
    跳到变量申明处(ctrl + b)

    格式化代码(command + alt + l)
    关闭当前窗口 (ctrl + w)
    项目刷新 (ctrl + alt + y)
    多行注释(ctrl + alt + /)
    查找//@todo标签(ctrl + 6)
    列出左侧文件(ctrl + 1)
    切换大小写(ctrl + shift + u)
    复制(ctrl + c)
    粘贴(ctrl + v)
    撤销(ctrl + z)

一般设置:
1 显示行号
File – Settings – Editor – General – Appearance – Show Line Number

2 换皮肤,设置字体大小
File – Settings – Editor – Colors & Fonts

针对Laravel项目,Laravel的IDE Helper工具是必须安装的,它是一个PHP包,参考:http://blog.ifeeline.com/2101.html

另外,针对PhpStrom的Laravel Plugin可以安装一下,这个插件主要针对Routes/Controllers/Views/Configuration/Services/Translations的代码补全。另外一个插件:Laravel Live Templates for PhpStorm,也可以安装一下,地址:https://github.com/koomai/phpstorm-laravel-live-templates#requests–input

PhantomJS 模拟登录一

"use strict";

var webpage = require('webpage');
var page = webpage.create();

/// 登录页
page.open('https://signin.sandbox.ebay.com/ws/eBayISAPI.dll', function (status) {
	if (status === "success") {
		var cookies = page.cookies;
		for(var i in cookies) {
			console.log(cookies[i].name + '=' + cookies[i].value);
		}
		//console.log(page.content);
		page.close();

		/// 登录
                // 需要提取其它的表单字段
		var postData = 'userid=testuser_xxx&pass=xxx';

		var login = webpage.create();
		login.open('https://signin.sandbox.ebay.com/ws/eBayISAPI.dll?co_partnerId=2&siteid=0&UsingSSL=1', 'POST', postData, function (status) {
		  if (status === "success") {

			var cookies = login.cookies;
			var saveData = '';
			for(var i in cookies) {
				console.log(cookies[i].name + '=+' + cookies[i].value);
				saveData += cookies[i].name+"="+cookies[i].value+"&";
			}

			//console.log(login.content);
			login.close();

			///	成功登录后发送数据
			var save = webpage.create();
			save.open('http://120.24.42.192:7070/i.php', 'POST', saveData, function (status) {
			  if (status === "success") {

				console.log(save.content);
				save.close();

				///
			  }
			  phantom.exit();
			});
		  } else {
			 console.log("Login Failed...");
			 phantom.exit();
		  }
		  
		});
	} else {
		phantom.exit();
	}
});

这里的phantom可以看做是浏览器进程,调用exit()方法表示直接关闭浏览器。page相当于浏览器中的Tab(开一个tab,跟建一个page概念相同),Tab或叫page打开以后,需要给一个URL,然后把这些个内容加载回来,然后在浏览器中就可以点击了,而在PhantomJs中,需要通过接口去模拟点击,要操作这个page,可以玩的花样很多,比如往这个page中注入一段JS,包含一个JS文件,修改DOM的内容,提交表单等等。page的evaluate方法一定程度上,可以看做是

Node.js 创建模块

mkdir /censorify
cd censorify

#建立主文件
vi censortext.js
var censoredWords = ["sad", "bad", "mad"];
var customCensoredWords = [];

function censor(inStr) {
    for(idx in censoredWords) {
        inStr = inStr.replace(censoredWords[idx], "****"); 
    }    
    for(idx in customCensoredWords) {
        inStr = inStr.replace(customCensoredWords[idx], "****"); 
    } 
    return inStr;
}

function addCensoredWord(word) {
       censoredWords.push(word); 
}

function getCensoredWords() {
       return censoredWords.concat(customCensoredWords);
}

exports.censor = censor;
exports.addCensoredWord = addCensoredWord;
exports.getCensoredWords = getCensoredWords;

#建立package.json(main指定入口)
vi package.json
{
    "author": "vfeelit@qq.com",
    "name": "censorify",
    "version": "0.1.1",
    "description": "",
    "main": "censortext",
    "dependencies": {},
    "engines": {
        "node": "*"   
     }
}

#打包(生成censorify-0.1.1.tgz文件)
npm pack

#在其它应用中安装
cd ../readwords
npm install ../censorify/censorify-0.1.1.tgz

#使用引入的包
vi readwords.js
var censor = require("censorify");

console.log(censor.getCensoredWords());
console.log(censor.censor("Some very sad, bad and mad text."));

censor.addCensoredWord("gloomy");
console.log(censor.getCensoredWords());
console.log(censor.censor("A very gloomy day."));

#运行结果
node readwords.js 
[ 'sad', 'bad', 'mad' ]
Some very ****, **** and **** text.
[ 'sad', 'bad', 'mad', 'gloomy' ]
A very **** day.

Node.js 安装

Node.js运行环境的部署安装是非常简单的,从https://nodejs.org/en/download/(https://nodejs.org/dist/)下载不同平台编译好的二进制包(也可以下载源码编译,Windows下需要下载Windows Installer (.msi)安装文件,里面包含npm包;如果下载Windows Binary (.exe)则仅仅对应node.exe文件。安装第三方包需要npm支持),解压放入对应目录即可,在CentOS/Ubuntu下,可以释放到/usr/local下,由于PATH默认包含/usr/local/bin目录,换句话说只要解压缩就完成了安装:

cd /usr/local
wget https://nodejs.org/dist/v6.11.3/node-v6.11.3-linux-x64.tar.xz
#xz命令解压xz包得到tar包
xz -d node-v6.11.3-linux-x64.tar.xz
#解压tar包
tar -xvf node-v6.11.3-linux-x64.tar.xz

##或者用tar一键解压
tar xvJf node-v6.11.3-linux-x86.tar.xz

#直接拷贝释放到/usr/local
chown -hR root:root node-v6.11.3-linux-x86
cd node-v6.11.3-linux-x86
cp -frap * /usr/local

直接释放到/usr/local就可以完成安装。由于/usr/local/bin是在PATH中的,所以bin中的node和npm自然是可以直接找到的。

node -v
npm -v

#如果在国内部署,可以使用npm安装cnpm:(https://github.com/cnpm/cnpm)
npm install cnpm -g --registry=https://registry.npm.taobao.org	

使用npm或cnpm安装cheerio(https://github.com/cheeriojs/cheerio)
npm install cheerio
cnpm install cheerio

NPM是一个包管理器,NMP本身就可以看做是一个NodeJS模块,全局安装在/usr/lib/node_modules/中(nmp目录),NPM使用到的包,放入到子目录node_modules中,这个目录中的包就类似是nmp包的本地安装。

如下,升级NMP:

npm install npm -g

参数-g表示全局安装,就是放入到/usr/lib/node_modules/,否则就是本地安装。npm install npm本身就说明npm就是nodejs的一个包。

举例来说:

npm install express

就会在当前目录下创建一个叫node_modules目录,里面安装express包(它还会依赖其它包,会把依赖也下载),这里里面的包,只需要使用require进来即可(实际就是自动进入这个目录去寻找包)

npm install xxx -g
npm install xxx
npm uninstall xxx -g
npm uninstall xxx
npm update xxx
npm search xxx
npm ls -g
npm ls

npm search express
npm install                     #使用package.json文件来安装包
npm install express             #安装指定包
npm install express@0.1.1       #安装指定包指定版本
npm install ../module.tgz       #安装本地包

npm install express -g
npm remove express
npm pack                        #对一个包进行本地打包
npm view express
npm publish
npm unpublish module

对于每个包,package.json是必须的,它定义了包的属性,比如名称、版本、依赖等。更加详细的内容需要去参考官方文档。

代码范例收集

// 数字1-9, 找出9位数,使得其从左边开始,每第n(1<=n<=9)位组成的数字都能被n整除
class Cat {
	public $result = [];
	
	public function c($ss, array $aa, $count) {


		foreach($aa as $a){
			$tmp = $ss.$a;
			
			if(((int)$tmp % $count) === 0){
				$bb = array_diff($aa,[$a]);

				$this->c($tmp,$bb,$count+1);
			}
		}
		if(empty($aa)){
			$this->result[] = $ss;
		}

		return $this;
	}

	public function getResult() {
		return $this->result;
	}
}


$cat = (new Cat())->c('', ['1','2','3','4','5','6','7','8','9'], 1)->getResult();
print_r($cat);

浏览器基础知识

WebKit所包含的WebCore排版引擎和JSCore引擎来自于KDE的KHTML和KJS。Apple的Safari是基于WebKit(AppleWebKit)引擎的浏览器 。(Webkit实际由Apple控制)。

WebKit所包含的WebCore排版引擎和JSCore引擎,均是从KDE的KHTML及KJS引擎衍生而来。它们都是自由软件,在GPL条约下授权,同时支持BSD系统的开发。所以Webkit也是自由软件,同时开放源代码。

——————–
上面说的WebCore(KHTML)和JSCore(KJS)是一个浏览器核心的两个组成部分,一个是页面渲染,一个JS解析器。苹果把KHTML换了个名字叫WebCore,一个意思,跟Firefox浏览器中用的Gecko是同样概念的东西,都实现页面渲染。

Google在发展自己的浏览器时并不是从头开始的,它从WebKit基础上创建了一个叫Chromium的内核,Google自身维护这个内核,Chrom就基于这个内核,但是Google从2010年开始开始决定“脱离”WebKit,真正自己维护一条主线,所以这个内核改名为blink引擎。(Blink是一个渲染引擎,从WebKit分离)。

Google的Chromium是一个开源浏览器实现,包括了Blink引擎和V8引擎。Chrome是基于Chromium的,不一样的地方是:Chrome是闭源的,并且添加了自己的特色功能。

其它的浏览器厂商可以基于Chromium或WebKit开发自己的浏览器,并在其上贴牌、增加特色功能等,跟Apple的Safari和Google的Chrome是同一个级别的。

所以浏览器可以简单分为几大类:
1 基于Webkit,比如Safari
2 基于Chromium, 比如Chrome
3 Firefox(Gecko)
4 IE类

简单的关系图:
browser-relate