Google Drive File Picker and Download the file

This articles should how to use picker on google drive and then download the picked files(limit to photos) use the javascript

Setup on google drive.

Go to the google developers console:  https://console.developers.google.com/
Create a new project or select a exist project,

and enable two libraries:  “Google Picker API” and “Google Drive API”
there are no special setup on “Google Picker API”, but for “Drive API”, it need go setup “Drive UI Integration”:

Client ID should same as the “OAuth 2.0 client IDs” in this project.
Open URL should same as the url of your web site domain, or a specific URL where you try to download the files.

Go back to Crediential of Oauth,

the same domain setup on previous steps is also list on “Authorized JavaScript origins”,

the open url we input on previous steps is list on “Authorized redirect URIs. it best list all your related URL into redirect URI.

prepare the keys we need on code step:

 //Google Client Id
var googleClientID='954222223338828-f21pukla0g67531760s0ed1575qaivth.apps.googleusercontent.com'
//Google App Id
var googleAppId='954222223338828'
//google drive picker
var googleDrivePickerDevelopKey='AIzaBHzK0WWvRj5DF9jgV6sTJpGwxzSyDfGcj0s'

That’s all in Google Console.

Let’s start write code for it.

First of all, insert the google js file into the html

<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
<script type="text/javascript" src="https://apis.google.com/js/client.js"></script>

The second js code is google client libriry,  it’s quickly and easy to use, but on this article, I’ll not use this one.

build the picker, remember we have 3 variables get from google console before, we need use on the code files.

First of all, let’s build the Picker.

/**Google drive ***/
var pickerApiLoaded = false;
var oauthToken;
var fileId;
//Photos Scope can't get the data we wanted, the solution, is use Drive only scope,
//And view.setMimeTypes("image/png,image/jpeg,image/jpg"); to only view the images
//  var googleScope = ['https://www.googleapis.com/auth/photos'];
var googleScope='https://www.googleapis.com/auth/drive.readonly'
// Use the Google API Loader script to load the google.picker script.

function loadPicker() {
    gapi.load('auth', {'callback': onAuthApiLoad});
    gapi.load('picker', {'callback': onPickerApiLoad});
}

function onAuthApiLoad() {
    window.gapi.auth.authorize(
        {
            'client_id': googleClientID,
            scope: googleScope,
            'immediate': false
        },
        handleAuthResult);
}

function onPickerApiLoad() {
    pickerApiLoaded = true;
    createPicker();
}

function handleAuthResult(authResult) {
    if (authResult &amp;&amp; !authResult.error) {
        oauthToken = authResult.access_token;
        createPicker();
    }
}

// Create and render a Picker object for searching images.
function createPicker() {
    if (pickerApiLoaded &amp;&amp; oauthToken) {
        var view = new google.picker.View(google.picker.ViewId.DOCS);
        view.setMimeTypes("image/png,image/jpeg,image/jpg");
        var picker= new google.picker.PickerBuilder()
            .enableFeature(google.picker.Feature.NAV_HIDDEN)
            .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
            .setAppId(googleAppId)
            .setDeveloperKey(googleDrivePickerDevelopKey)
            .setOAuthToken(oauthToken)
            .addView(view)
            .setCallback(pickerCallback)
            .build()
            .setVisible(true);

    }
}
// A simple callback implementation.
function pickerCallback(data) {
}<

We need download image after Picker, the photo scope on Picker can’t get the right file ID,  to solute this,  Use  drive scope and limit the mimeTypes.

Handle the data from File Picker and download it

function pickerCallback(data) {
 if (data.action == google.picker.Action.PICKED) {
 fileId = data.docs[0].id;
 $http.get('https://www.googleapis.com/drive/v2/files/' +fileId+ '?alt=media',
 {
   headers: {'Authorization': 'Bearer '+oauthToken}
 }).success(function(file){
   //file is the image object
 })
 }
}

$http is from angularJs, you can replace this with the js framework you used, or use the google client js library.

?alt=media

which will return the image, otherwise it will return json code with image name, image downloadUrl(that Url still need oauth token) etc.

headers: {'Authorization': 'Bearer '+oauthToken}

We need setup Authorization token on the hear, otherwise we can’t visit the file.

It’s simple, we can handle the image in the js code now,  but it’s not end for me, I need directly download the files on remote server, not download on the js code to user browser.

Let’s change the code to download the file on remote server

function pickerCallback(data) {
 if (data.action == google.picker.Action.PICKED) { 
   $http({
     method: 'POST',
     url: 'theUrlWhichDownloadImage.php',
     dataType: 'json',
     crossDomain: true,
     data: {
       oAuthToken:oauthToken,
       fileId: data.docs[0].id,
       name: data.docs[0].name,
       mimeType:data.docs[0].mimeType
     },
     headers: {'Content-Type': 'application/x-www-form-urlencoded'}
   })
   .success(function (data2) {

   })
   .error(function (data2) {

   });
 }
}

replace with get the files from google drive api, we send the file id, the oauth token to remote server, which used to download the file.

and on the remote server, a php file was created and recevied the data, try to download the file from google drive.

 

$request_body = file_get_contents('php://input');
$param = (array)json_decode($request_body);
$oAuthToken = $param['oAuthToken'];
$fileId = $param['fileId'];
$getUrl = 'https://www.googleapis.com/drive/v2/files/' . $fileId . '?alt=media'; //
$authHeader = 'Authorization: Bearer ' . $oAuthToken;
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, $getUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, array($authHeader));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$data = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);

The image was on $data. save it and return the path to js code on fronend.

$path='examplepath/';
file_put_contents($path.$param['name'], $data)
//return the file URL to js code.

Compare to OneDrive, DropBox,  Google Drive File Picker and download files is much more complex. hope this Article can help you.

Symfony2 创建项目与模板设置

环境准备与概览

习惯于在windows使用netbean编辑器并使用virtualbox虚拟centos系统, 预将nginx+php-fpm+mysql,  当然apache也是不错的选择,   使用http://symfony在windows与centos上作为开发域名。

1.下载与环境设置

1. 如何于centos上面建立开发环境不再详述, 当然也可以在windows上面建立开发环境。

2. 关于使用 symfony代替127.0.0.1 在liunx系统中修改/etc/hosts文件, win7系统中修改 C:\Windows\System32\drivers\etc\host 文件(需要用管理员权限打开)

加入类似于IP 别名1 别名2的内容即可, 如:

# /etc/hosts 127.0.0.1 symblog dev symfony

3.手动下载symfony2, 也可以参照这个页面用Composer 进行安装。http://symfony.com/doc/current/book/installation.html

唯一需要注意的是: app/cache 和app/logs目录需要设置成777权限。windows的开发环境应该不存在这个问题。

4. 修改apache 或者nginx配置文件symfony域名指向下载的symfony文件的web目录。

此时应该可以通过 http://symfony/app_dev.php 访问到symfony的默认页面, 有几个demo可以参照学习。

app_dev.php 默认加载了一个开发工具条在下面, 显示了当前页面的一些信息, 极大地方便了程序的调试, 只有当环境变量为dev时才会显示。

5. 使用composer安装时, 会提示输出mysql等相关信息, 需要修改这些信息, 或者是直接下载的文件, 可以进入页面的“Configure” 进行相关设置。

Bundles(也许可以称之为包, 束, 程序集,或者项目, 还是用英文吧)是symfony的基础东东, 一个个分享出来可重复利用的代码封装, 甚至于symfony本身是作为一个bundles运行的。  包括控制器、模块、模板, 甚至于图像与js, css样式表等资源。   很杂乱的东西, 区别不同的bundles使用了php5.3以后的命名空间, 大部分cpenal, da虚拟主机好像只有php5.2版本吧, 无法运行symfony2了。

2.创建一个Bundle

在下面的例子中将创建一个博客,  Symfony 提供了大量工具来快速地创建项目。 比如我们可以用它来快速创建一个博客的基础bundle.

php app/console generate:bundle --namespace=Blogger/BlogBundle --format=yml

运行后直接采用所有的默认设置即可。 可以方便地创建我们所需要的基本控制器, 模块与模板等。 包含了下面的行为:

注册Bundles

在symfony中所有使用的bundles都要求先被注册, 有些bundles只会使用于开发测试环境(dev or test), 如前文提及的开发工具条. 下面这断代码显示了bundles创建命令如何注册BloggerBlogBundle这个bundle.

// app/AppKernel.php
class AppKernel extends Kernel {

public function registerBundles() {
$bundles = array(
// ..
new Blogger\BlogBundle\BloggerBlogBundle(),
);
// .. return $bundles; } // ..
}
}

路由

作为一个框架, 路由功能被bundler创建器创建于app/config/routing.yml, symfony是用yml格式来保存配置信息。

# app/config/routing.yml
BloggerBlogBundle:
    resource: "@BloggerBlogBundle/Resources/config/routing.yml"
    prefix:   /

prefix前缀选项允许我们可以将其放置于如blog、news等子目录下。
文件
除了以上配置文件外, 其它大部分文件生成为src目录下, 如同大部分mvc框架。 在src下生成Blogger目录, 并有BlogBundle子目录存放着各种相关东东。不同的是类似于blogger的目录对应着php命名空间。

默认控制器

Bundle生成器在src下面生成了默认了控制器。 通过访问: http://symfony/app_dev.php/hello/world 可以看到简单的问候。 关于这个页面是如何生成:

路由

还是路由, 不同的是前面的路由是在整个程序里面注册使用, 这里的路由是控制具体页面使用, src/Blogger/BlogBundle/Resources/config/routing.yml 控制了BloggerBlogBundle, 包含以下程序片断:

# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_homepage:
    pattern:  /hello/{name}
    defaults: { _controller: BloggerBlogBundle:Default:index }

参数: 进行url检测, 符合/hello/{name}结构的任意值将被赋予给{name},
方式: 没有对形式进行限制, 理论可以put, get, post, delete所有的操作都可以进行。
后续: 如果符合以上两条, 那么{name}将会传导至特定文件, 以上为src/Blogger/BlogBundle/Controller/DefaultController.php文件中的default控制器的index行为将被使用。

控制器

在默认生产的bundler中, 控制器行为相当简单, {name}参数被传入并被传出到模板文件:

<pre>// src/Blogger/BlogBundle/Controller/DefaultController.php

namespace Blogger\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction($name)
    {
        return $this->render('BloggerBlogBundle:Default:index.html.twig', array('name' => $name));
    }
}

BloggerBlogBundle:Default:index.html.twig 会使用 BloggerBlogBundle views文件夹中 Default文件夹下面index.html.twig模板文件.

模板文件

打开上述模板文件, 非常简单的一句代码:

{# src/Blogger/BlogBundle/Resources/views/Default/index.html.twig #}
Hello {{ name }}!

以上就是symfony的整个mvc流程, 这么多文件的作用只是输出一个 “hello world”. 理论上不用bundler创建器, 只是手动创建上述文件也可以实现相同效果。花费的时间就多了去了。

回到正题, 我们是创建博客系统, 所以不需要 hello world,
1.移除控制器 src/Blogger/BlogBundle/Controller/DefaultController.php
2.移除模板 src/Blogger/BlogBundle/Resources/views/Default/
3.最后移除路由 src/Blogger/BlogBundle/Resources/config/routing.yml
整个世界清静了。

3. 让我们开始创建博客的主页

Twig的优点

在symfony中我们可以使用 Twig和php(这不是废话嘛)作为模板。使用Twig的以下优点:

1. 快: 是编绎过的php类, 可以占用更少的资源

2. 简洁:想想看要打<?php ?>, Twig输入的内容要少很多。

3. 可继承: 非常cool的一个功能

4. 安全: 转义功能默认开启, 甚至还可以为重要代码提供沙盒功能。

5. 可扩展: 需要额外的定制功能, 可以随时扩展

更多内容, 请移步:http://twig.sensiolabs.org/

可继承是一个非常好的优点, 我们将使用三级继承结构来定制这个模板, 这将允许我们在三个不同层级修改模板, 方便自由定制。

主模板–level 1

<!-- app/Resources/views/base.html.twig -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html"; charset=utf-8" />
<title>{% block title %}symfony{% endblock %} - blog</title>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
{% block stylesheets %}
<link href='http://fonts.googleapis.com/css?family=Irish+Grover' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=La+Belle+Aurore' rel='stylesheet' type='text/css'>
<link href="{{ asset('css/screen.css') }}" type="text/css" rel="stylesheet" />
{% endblock %}
<link rel="shortcut icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>

<section id="wrapper">
<header id="header">
<div>
{% block navigation %}
<nav>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
{% endblock %}
</div>

<hgroup>
<h2>{% block blog_title %}<a href="#">symfony</a>{% endblock %}</h2>
<h3>{% block blog_tagline %}<a href="#">creating a blog in Symfony2</a>{% endblock %}</h3>
</hgroup>
</header>

<section>
{% block body %}{% endblock %}
</section>
<aside>
{% block sidebar %}{% endblock %}
</aside>

<div id="footer">
{% block footer %}
<a href="http://blog.dengruo.com/201309/1409">Symfony2 博客教程</a>
{% endblock %}
</div>
</section>

{% block javascripts %}{% endblock %}
</body>
</html>

上面代码在引入了一个js文件, 在ie9版本前的浏览器中实现html, 以及两个css文件导入google fronts.
这构成了网页的主要内容结构, 相当于drupal的html.tpl.php+page.tpl.php.
让我们看一下头部文件

<title>{% block title %}blog{% endblock %} - symfony</title>

{% 标签中即不是html, 也不是php, 他是3个Twig标签中的一个, 用于执行某些动作。 这里可以找到完整的Twig控制动作用于这个标签。 回到当前代码, 是用于查找title的block并输出他, 如果没有则输出默认的symblo这个词。
Twig的可续承特性可以用于修改title, 我们可以在其它模板文件中重写它:

{% extends '::base.html.twig' %}

{% block title %}The blog title goes here{% endblock %}

上面代码首先继承了第一次定义这个block的文件, 然后修改它。 网站标题部分会输出 ‘The blog title goes here – symfony’。
一般而言, 我们引用模板文件时会采用bundle:controller:template, 但是以上代码并没有bundle 和controller, 不包含这两个字段会直接引用app/Resources/views/ 文件夹下面的文件。

在css样式表中, 我们可以发现另一个Twig标签{{, 这是一个输出(说些什么)标签。

<link href="{{ asset('css/screen.css') }}" type="text/css" rel="stylesheet" />

这个标签用于输出变量或者表达式, 上面例子输出了asset函数的返回值, 这个函数提供可移植的方式来返回css,js, 图片的地址。

这个标签可以以特定格式输出我们想要内容, 比如时间:

{{ blog.created|date("d-m-Y") }}

全部过滤列表在 Twig 文档可以查到。

最后一个标签并没有在上述代码中出现, 它是{#, 只是一个注释标签

{# 注释内容可以输出在这里 #}

接下来我们将创建css样式表web/css/screen.css , 加入以下内容.

<pre>html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}

body { line-height: 1;font-family: Arial, Helvetica, sans-serif;font-size: 12px; width: 100%; height: 100%; color: #000; font-size: 14px; }
.clear { clear: both; }

#wrapper { margin: 10px auto; width: 1000px; }
#wrapper a { text-decoration: none; color: #F48A00; }
#wrapper span.highlight { color: #F48A00; }

#header { border-bottom: 1px solid #ccc; margin-bottom: 20px; }
#header .top { border-bottom: 1px solid #ccc; margin-bottom: 10px; }
#header ul.navigation { list-style: none; text-align: right; }
#header .navigation li { display: inline }
#header .navigation li a { display: inline-block; padding: 10px 15px; border-left: 1px solid #ccc; }
#header h2 { font-family: 'Irish Grover', cursive; font-size: 92px; text-align: center; line-height: 110px; }
#header h2 a { color: #000; }
#header h3 { text-align: center; font-family: 'La Belle Aurore', cursive; font-size: 24px; margin-bottom: 20px; font-weight: normal; }

.main-col { width: 700px; display: inline-block; float: left; border-right: 1px solid #ccc; padding: 20px; margin-bottom: 20px; }
.sidebar { width: 239px; padding: 10px; display: inline-block; }

.main-col a { color: #F48A00; }
.main-col h1,
.main-col h2
    { line-height: 1.2em; font-size: 32px; margin-bottom: 10px; font-weight: normal; color: #F48A00; }
.main-col p { line-height: 1.5em; margin-bottom: 20px; }

#footer { border-top: 1px solid #ccc; clear: both; text-align: center; padding: 10px; color: #aaa; }

Bundler模板–level 2

现在我们为blog bundler 创建模板, 创建src/Blogger/BlogBundle/Resources/views/layout.html.twig 并加入:

{# src/Blogger/BlogBundle/Resources/views/layout.html.twig #}
{% extends '::base.html.twig' %}

{% block sidebar %}
    Sidebar content
{% endblock %}

非常简单的代码,1. 继承了一级模板, 并且为博客内容特别定制了侧边栏, 很显然我们并不想博客的布局与其它页面一样。 类似drupal7中page–content-type.tpl.php模板, 定制了某一特殊类型内容的布局。

具体页面布局–level 3

这个阶段已经涉及到创建具体页面, 所以需要先创建控制器src/Blogger/BlogBundle/Controller/PageController.php

<pre>// src/Blogger/BlogBundle/Controller/PageController.php

namespace Blogger\BlogBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class PageController extends Controller
{
    public function indexAction()
    {
        return $this->render('BloggerBlogBundle:Page:index.html.twig');
    }
}

然后创建相应的Twig文件: src/Blogger/BlogBundle/Resources/views/Page/index.html.twig

{# src/Blogger/BlogBundle/Resources/views/Page/index.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}

{% block body %}
Blog homepage
{% endblock %}

创建路由将首页引导到我们刚创建的页面:src/Blogger/BlogBundle/Resources/config/routing.yml

# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_homepage:
    pattern:  /
    defaults: { _controller: BloggerBlogBundle:Page:index }
    requirements:
        _method:  GET

再次访问 http://symfony/app_dev.php可以看见简单的首页。

4.再创建一个about页面

路由:在src/Blogger/BlogBundle/Resources/config/routing.yml中加入

# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_about:
pattern:  /about
defaults: { _controller: BloggerBlogBundle:Page:about }
requirements:
_method:  GET

 

当以get方式访问about页时执行位于BloggerBlogBundle命名空间的page控制器about动作。

控制器: 在src/Blogger/BlogBundle/Controller/PageController.php 于page控制器中加入about动作

// src/Blogger/BlogBundle/Controller/PageController.php
// ..
public function aboutAction()
{
    return $this->render('BloggerBlogBundle:Page:about.html.twig');
}
// ..

模板: 创建src/Blogger/BlogBundle/Resources/views/Page/about.html.twig 并加入相关页面文件

{# src/Blogger/BlogBundle/Resources/views/Page/about.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}

{% block body %}
about page
{% endblock %}

简单的三个流程增加了关于页面:http://symfony/app_dev.php/about
 

参考:http://tutorial.symblog.co.uk/docs/configuration-and-templating.html

防火防盗防度娘

国内互联网公司恶名昭著,下面只不过是多了一个例子而已。

在签百度竞价时,在所谓的顾问授权书上面, 我否定了所有的权限, 理论上面所谓的百度客服是没有任何权力对我的帐号做改动。

然而, 对于度娘而言,一切皆有可能, 在每周一次的例行骚扰,直白地叫我:你是不是考虑增加消费数额后。 这贱人终于忍不住,亲自操刀上阵。 直接给我加了垃圾关键词。

防火防盗防度娘,  千日防贼的日子真累。

 

一堆的邮件提醒:

 

这N个无效关键词被添加, 还是广泛匹配, 操他妈的度娘。 老子只是暂停,老子不删掉,看他的怎么解释。

 

php移除&nbsp

在php文本处理中, 用trim()可以方便去掉首尾空格, 但是对于&nbsp; 这个恶心的东西却无能为力。

尝试几种方法,最终有用的是:

str_replace(chr(0xC2).chr(0xA0),”,$entry->nodeValue)

直接用asc码, 哪个垃圾再用&nbsp;就是傻X, 用css用排版会死吗?

nginx fast-cgi cache有效期

收到linode关于I/O abuse的警告,

mysql所在的服务器也被暂停。 nginx设置了fast-cgi cache的, 并且时间为10d, 但是却直接出现无效状态。

service 区块内

fastcgi_cache_valid   200 302  10d;
astcgi_cache_valid   301      10d;

nginx.conf内

fastcgi_cache_path /home/cache  levels=1:2  keys_zone=cache:500m inactive=1m max_size=10g;

好吧,测试下来, nginx cache的有效时间只有可怜的1m,  听信网上流言害死人啊。

与恶魔共舞

只有永恒的利益。

百度是一只恶魔,在不答应在推广的情况不间断地K站, 而同行的几个百度帐号却都存在着恶意点击等现象。 它所做的一切只会让人对这个国家最开放的领域,网络感到厚重的暮气。

但是,这就是一个劣币驱逐良市的市场, 反抗与呐喊都是无用的,只有被强奸并且享受着。

不能和钱过不去, 那么就与这只恶魔共舞吧。

近6K大洋能否给我带来回报并不知道,但是他却真能减少我受到的骚扰, 记得那孩子走之前说:你还有什么号码需要一起加入屏蔽的,一起写一下吧,我们以后不会打你了。

深圳的网络公司并不发达,百度的电话可以占到其中的1/3强,能够花钱买个安静也是值得的。

另一方面,研究一下SEM了,定向投放,即时性都是seo所不能比的。下载下来的一堆资料也可以通宵研究一下了。

 

PS:还是感觉我很帅:发邮件给业务员叫他下午来签了合同, 他同事过来后核对了一下信息,刷卡赶他出去,前后没和这孩子说了超过十五句话。

只是我有个孩子在百度 当了三年业务员了, 没必要从他的十句话里面分析出哪一句话是真话吧。还是那句话–朋友多了好办事。各位认识的不认识的,捧个场, 以后互相扶持哈。

百度,你够狠

在最后一次拒绝做百度竞价排名后。

百度自然收录量(百度统计后台数据)直接减少了2/3。

难道,真的只能被逼上贼船了–做付费了。

见过甩流氓的,没见过这么无赖的。

除了此次因为竞价的原因被大量减少收录外,前一次的大量因为加了百度统计, 结果第二天也是如同这次的情况。  google analytics 从来没有人怀疑它,而百度统计网上到处是不敢使用的站长。 谣言之所以为谣言,是因为其有存在的依据。 我用我的两次经历见证了这句话。

宁得罪君子,勿得罪小人–切记。

nginx 502和504错误

nginx php-fpm环境下, 数据库备份因为utf8文件bom原因无法用命令行导入, 直接准备上bigdump.

无奈因为数据库的巨大, 502和504的出现。 一步步地增加nginx和php-fpm的,对这两个恶心的错误也有了更直观的认为。

简单地说两个的区别502出现调整php-fpm参数, 504则是调整nginx参数(汗, 好像nginx的文档里面就说502只是传递后面过来的错误信息的)。

主要是几个时间限制的nginx.conf里:
fastcgi_connect_timeout 3000s;
fastcgi_send_timeout 3000s;
fastcgi_read_timeout 3000s;

而php-fpm则是  request_terminate_timeout

当然, 以上只是在恢复数据, 实现生产环境还得考虑进程数等等。

 

drupal 多站点同步解决构想

用drupal 7 构建的多个站点, 分布于不同服务器上面, 力求在A站发布了某篇文章或某个产品同步到B站和C站。

解决方案:

1:http://drupal.org/project/content_distribution 模块可以实现, 但是其并没有D7的版本

2:直接服务器同步数据库,–不会操作

3:利用services模块生成服务器, 再利用feeds模块去解析。 测试OK, 追求完美的情况只需要再根据两个模块提供的Hooks各写两个新模块即可。

记录 备忘。