关于pdf文件批量转换成其他格式的讨论

第三方插件和扩展:

1,PDFlib http://www.pdflib.com/

PDFlib是个商业软件,但有免费版,目前我用到的区别是免费版在读取PDF的时候最多只能读10页。

生成PDF用PDFlib,http://www.pdflib.com/download/pdflib-family/pdflib-8/

抽取PDF用TET,http://www.pdflib.com/download/tet/

通过TET可以抽取PDF文档中的纯文本以及字体、颜色等,但无法得到类似html的文本结果。

PDFlib可支持php、c、java等程序语言。

2,Haru Free PDF Library http://libharu.sourceforge.net/

只能写PDF,不能读PDF

HARU is a free, cross platform, open-sourced software library for generating PDF. It supports the following features.

Generating PDF files with lines, text, images.

Outline, text annotation, link annotation.

Compressing document with deflate-decode.

Embedding PNG, Jpeg images.

Embedding Type1 font and TrueType font.

Creating encrypted PDF files.

Using various character set (ISO8859-1~16, MSCP1250~8, KOI-8R).

Supporting CJK fonts and encodings.

3,FPDF http://www.fpdf.org/

FPDF is a PHP class which allows to generate PDF files with pure PHP, that is to say without using the PDFlib library. F from FPDF stands for Free: you may use it for any kind of usage and modify it to suit your needs.

FPDF has other advantages: high level functions. Here is a list of its main features:

Choice of measure unit, page format and margins

Page header and footer management

Automatic page break

Automatic line break and text justification

Image support (JPEG, PNG and GIF)

Colors

Links

TrueType, Type1 and encoding support

Page compression

http://www.fpdf.org/en/doc/index.php  这里是FPDF的函数列表

4,pdfbox http://pdfbox.apache.org/

Acrobat X 原生组件

AcrobatX本身也有接口可以直接给C和VB,但貌似只限于Windows平台。

Acrobat JavaScript Scripting Guide

JavaScript™ for Acrobat® API Reference

在AcrobatX安装到win系统上时候,也会注册一些组件,VC或者VB通过这些组件可以直接使用Acrobat丰富的功能,当然原生的要比第三方的质量更好。

CH16 – Accessing PDF.pdf

Programming Acrobat JavaScript Using Visual Basic

FPDF is a PHP class which allows to generate PDF files with pure PHP, that is to say without using the PDFlib library. F from FPDF stands for Free: you may use it for any kind of usage and modify it to suit your needs.
FPDF has other advantages: high level functions. Here is a list of its main features:
Choice of measure unit, page format and margins
Page header and footer management
Automatic page break
Automatic line break and text justification
Image support (JPEG, PNG and GIF)
Colors
Links
TrueType, Type1 and encoding support
Page compressio

自己写了个linux的打包备份程序

每天cron运行下面的脚本,备份多个web目录和mysql数据库,备份的文件按月分目录保存。

#!/bin/sh
todaystr=`date +%Y-%m-%d`
echo “today:${todaystr}”
month=`date +%Y-%m`
echo “month:${month}”

backuppath=”/opt/case/kbackup/${month}”

# mkdir
if [ ! -d "$backuppath" ]; then
mkdir ${backuppath}
fi
#exit 0

# web code
for var in web1 web4 web5 web6 web7 web8 ; do
echo “– $var”
mypath=”/opt/case/${var}/web”
myfile=”${backuppath}/${todaystr}_web_${var}.tar.gz”
echo $mypath
echo $myfile
tar zcvf $myfile $mypath
done

# mysql db
for var in db1 db2 db3 ; do
echo “– $var”
mypath=”/var/lib/mysql/${var}”
myfile=”${backuppath}/${todaystr}_mysqldb_${var}.tar.gz”
echo $mypath
echo $myfile
tar zcvf $myfile $mypath
done

换个思路——在多前端单一后端的架构中使用proxy

一般来说,apache的proxy有几个用途:

  • 负载均衡:一台server撑不住,通过proxy把业务处理分流到其他server,让网站更强壮;
  • 安全:前台用porxy或者squide挡一下,受到攻击或者黑客的时候让前端的proxy当靶子;
  • 应用整合:让某些目录proxy到其他webserver的其他端口,不同的server整合到同一个域名下。

在最近的一个项目中,同一个网站应用要推送到不同的前端ip和域名上,而且将会分布在几十台物理服务器上,但流量并不高。惯性思维想到的方案是——发布,再发布,不管数据库还是代码,有更新就从新发布到各个服务器上。虽说我们做了很多自动化的脚本,但是这种方式还是会出现一些问题:

  • 繁琐:每次更新完了beta还需要一个冗长的脚本执行过程,而且为了稳妥更新后的效果还需要去每个server上去人工查看;
  • 数据库无法统一,一些应用不好实现:为了让服务更快,不得不在每台server都放上数据库,但是这样,一来,因为mysql遇到直接dump导入就不能用mysql的主从方式,推送大各个server同步时间较长,不稳定;二来,一些用户信息不方便在各个server之间做同步。
  • 配置一台新的服务器需要时间。

在反复的纠结和测试之后,我采用apache的proxy实现了多前端单一后端的架构:

有应用A,B,C

有服务器:

P ->192.168.1.100
Q->192.168.1.101
R->192.168.1.102
S->192.168.1.103
T->192.168.1.104

给应用A分配的域名:

www.a1.com ->192.168.1.101 (Q)
www.a2.com ->192.168.1.101 (Q)
www.a3.com ->192.168.1.102 (R)
www.a4.com ->192.168.1.102 (R)
……

给应用B分配的域名:

www.b1.com ->192.168.1.101 (Q)
www.b2.com ->192.168.1.101 (Q)
www.b3.com ->192.168.1.102 (R)
www.b4.com ->192.168.1.102 (R)
……

以server P(192.168.1.100)为后端:

把A的后端放在P的81端口
把B的后端放在P的82端口
把C的后端放在P的83端口。

给Q,R,S,T的80配置好proxy和rewrite(具体的配置这里不复述,请百度上自己google一下)。

那么针对Q的80端口对应的目录下的.htaccess做如下配置:

RewriteEngine on

# A ——————–
# server  Q (2 sites)
RewriteCond %{HTTP_HOST} ^www.a1.com* [OR]
RewriteCond %{HTTP_HOST} ^www.a2.com*
RewriteRule ^(.*)$ http://192.168.1.100:81/$1 [P,L]
# END A ——————–

# B ——————–
# server  Q (2 sites)
RewriteCond %{HTTP_HOST} ^www.b1.com* [OR]
RewriteCond %{HTTP_HOST} ^www.b2.com*
RewriteRule ^(.*)$ http://192.168.1.100:82/$1 [P,L]
# END A ——————–

这样一来指向到serverQ的:

域名 www.a1.com www.a2.com 的所有请求通过反向代理转发到了 serverP的81端口
域名 www.b1.com www.b2.com 的所有请求通过反向代理转发到了 serverP的82端口

以此类推,不管前端有多少台服务器,我们只要搭建好了apache(proxy&rewrite),只需要通过ftp来维护.htaccess就能灵活设置多前端单一后端的proxy了。

PS:一般来说通过ftp软件是无法看到.htaccess文件的,每个ftp软件都有自己一套设置支持浏览这类文件,这里推荐一下filezilla这个免费ftp工具,只需把菜单中“服务器”->“强制显示隐藏文件”开启就可以正常显示隐藏文件了。

php实现简单的“分享”功能

看到人人和facebook都有一个分享的功能。

就是输入一个url,然后返回对方的title名称和很多该页面上的图片,操作者选择之后就提交到后端:

如我在renren上分享链接 http://www.dyee.org/bbs/thread-182935-1-2.html

会跳转到这样的页面:

cc

其中,红色区域是获得的网页title,而点击绿色部分就可以切换所要使用的图片。

我写的后端代码如下:

<?php
set_time_limit(0);
$url = trim($_REQUEST['url']);
if($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//curl_exec($ch);
$output = curl_exec($ch);
//$c_info = curl_getinfo($ch);
//print_r($c_info);
curl_close($ch);
preg_match(”/charset=([^\"]+)\”/i”,$output, $matches);
//print_r($matches);
$code = $matches[1];
echo ‘<p>编码:’.$code.’</p>’;
preg_match(”/<title>([^<]+)</i”,$output, $matches);
//print_r($matches);
$title = mb_convert_encoding($matches[1],’utf-8′,$code);
echo ‘<p>标题:’.$title.’</p>’;
//$output=str_replace(”\”",”\n”,$output);
//$output=str_replace(”\’”,”\n”,$output);
//preg_match_all(”/src=[\"|']{0,1}(.*\.(gif|jpg|jpeg|png))/i”,$output, $imgs);
//preg_match_all(”/src=[\"|']{0,1}(([^\.]+)\.(gif|jpg|jpeg|png))/i”,$output, $imgs);
//preg_match_all(’/<img.*?(?: |\\t|\\r|\\n)?src=[\'"]?(.+?)[\'"]?(?:(?: |\\t|\\r|\\n)+.*?)/sim’, $output, $imgs, PREG_PATTERN_ORDER);
//preg_match_all(”/<img.*src\s*=\s*[\"|\']?\s*([^>\"\'\s]*)/i”,$output,$imgs);
//preg_match_all(’/<img.+src=\”?(.+\.(jpg|gif|bmp|bnp|png))\”?.+>/i’,$output,$imgs);
preg_match_all(’/src=[\"\']?([%+\*\w\/:\._-]+(?:jpg|gif|bmp|jpeg|png))/ism’, $output,$imgs);
if(is_array($imgs)){
$tmp = explode(’/',$url);
$http = $tmp[0].’//’.$tmp[2];
$tpath = $tmp[0].’//’;
for($i=2;$i<count($tmp)-1;$i++){
$tpath.=$tmp[$i].’/';
}
foreach ($imgs[1] as $i){
echo ‘<img src=”‘.parseImg($i,$url,$http,$tpath).’”/>’;
//echo ”.parseImg($i,$url,$http,$tpath).’<br/>’.”\n”;
}
}
}
function parseImg($img,$page,$http,$tpath){
#直接有http
if(preg_match (’/^http/i’, $img) ){
return $img;
}
#根路径
if(preg_match (’/^\//i’, $img)){
return $http.$img;
}
#本路径
if(preg_match (’/^[^\/]/i’, $img)){
if(preg_match(’/\/$/i’,$page)){
return $page.$img;
}
if($http.’/'==$page || $http==$page){
return $http.’/’.$img;
}else{
return $tpath.$img;
}
}
}

<?php

set_time_limit(0);

$url = trim($_REQUEST['url']);

if($url){

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_HEADER, 0);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$output = curl_exec($ch);

curl_close($ch);

preg_match(”/charset=([^\"]+)\”/i”,$output, $matches);

$code = $matches[1];

echo ‘<p>编码:’.$code.’</p>’;

preg_match(”/<title>([^<]+)</i”,$output, $matches);

$title = mb_convert_encoding($matches[1],’utf-8′,$code);

echo ‘<p>标题:’.$title.’</p>’;

preg_match_all(’/src=[\"\']?([%+\*\w\/:\._-]+(?:jpg|gif|bmp|jpeg|png))/ism’, $output,$imgs);

if(is_array($imgs)){

$tmp = explode(’/',$url);

$http = $tmp[0].’//’.$tmp[2];

$tpath = $tmp[0].’//’;

for($i=2;$i<count($tmp)-1;$i++){

$tpath.=$tmp[$i].’/';

}

foreach ($imgs[1] as $i){

echo ‘<img src=”‘.parseImg($i,$url,$http,$tpath).’”/>’;

}

}

}

function parseImg($img,$page,$http,$tpath){

#直接有http

if(preg_match (’/^http/i’, $img) ){

return $img;

}

#根路径

if(preg_match (’/^\//i’, $img)){

return $http.$img;

}

#本路径

if(preg_match (’/^[^\/]/i’, $img)){

if(preg_match(’/\/$/i’,$page)){

return $page.$img;

}

if($http.’/'==$page || $http==$page){

return $http.’/’.$img;

}else{

return $tpath.$img;

}

}

}

稍加改动就可以使用了。

《了凡四训》电影版

A面:

B面:

也谈facebook的bigPipe

最近在做技术研究的时候,遇到了bigPipe。

关于bigPipe的官方文章在这里 http://www.facebook.com/note.php?note_id=389414033919 (天朝得翻墙)。

有位叫 limu的仁兄发表了 http://limu.javaeye.com/blog/765173 这篇文章。 我表示一般赞成的。

但是,可能是这仁兄facebook用的少吧~那并不是bigPipe的全部。

limu仁兄说到,先点菜,然后各个大厨一起做菜,然后给用户端上来,举个反证:

http://www.facebook.com/pages/ka-ti-nuo-wang-guo-CK101lun-tan/107749042613155 (AD一下CK的粉丝页)

用户每次点菜(打开新页面)时,先载入框架,再ajax调用内容填充上去。但是,针对这一次载入,反而给服务器多填了几个请求不是么?

不理解?我们分析看看,比方说一个页面有8个框框要填东西,如果用传统的方式,这8个框框本来可以随着主框架一次载入进来,如果某个框框需要更新,那么我们就ajax再载入和更新对应的位置。这样一来,第一次的成本就只有1次服务器开销。而facebook也同样可以实现高速的载入,肯定不会像limu仁兄说的,超过500ms。

不管数据来自哪里,服务端怎么缓冲,这8个框框的内容肯定都会被用户载入到浏览器的。

那么每次多8个请求,有何意义呢?

让我们来正确的分析一下吧:

http://www.facebook.com/pages/ka-ti-nuo-wang-guo-CK101lun-tan/107749042613155

一个该页面的请求,如果浏览器支持js,那么html部分只有框架,其后跟着大量的js的json对象,跟limu兄说的一样。

这时候,左侧喜欢他的网友框里面显示:

aa

以上图片的红框“芮世軒”这个网友,链接为 http://www.facebook.com/profile.php?id=100000868569268

ok,当我们在页面上点击该链接,不出意外,浏览器的地址栏会是这个链接地址吧?

但是…当你点击该链接并且载入该网友信息后,链接地址却是:

http://www.facebook.com/pages/ka-ti-nuo-wang-guo-CK101lun-tan/107749042613155#!/profile.php?id=100000868569268

哦?一个锚链!!而页面上的东西已经全变成这个网友的个人主页了~

bigpipe拦截了我的a标签的click动作,又通过ajax方式调用了该网友的信息,在当前这个ck粉丝页上,能用的动态框框就复用,不能用的就隐藏,没有的就添加,制造了一个网友的个人首页出来。

而他又给该粉丝页增加了一个锚链,既可以个goback创造空间,又让网友可以通过这个加了锚链的地址直接访问这个网友的页面。

事实上,ck的粉丝页,并不含有一个#!/profile.php?id=100000868569268锚链,而这个锚链是告诉服务器,该页的实际位置的。

那么至此,大家应该明白,第一次还要分8块载入的原因了吧?就算请求某个实际页面,最终呈现成什么样子或者分成几块,也不取决于框架。

这样一来:

如果访问http://www.facebook.com/pages/ka-ti-nuo-wang-guo-CK101lun-tan/107749042613155#!/profile.php?id=100000868569268

跟ck的粉丝页,基本上没有关系了,出来的结果是那个网友的个人主页。

另外,还有一些弹出窗口也设计成这样:

比方说“分享”按钮,其实href是http://www.facebook.com/ajax/share_dialog.php?s=99&appid=2309869772&p[]=1149318559&p[]=129942140395896&action_link=share

但实际上,页面不动,而facebook截取了click时间把它转换成了弹出窗口。

apache的常用module配置

用来做gzip压缩的deflate模块:

DeflateCompressionLevel  压缩等级,取值范围1–9,越高cpu的load越重。

大致的配置(得先SetOutputFilter再AddOutputFilter):

<IfModule mod_deflate.c>
DeflateCompressionLevel 3
SetOutputFilter DEFLATE
#AddOutputFilterByType DEFLATE php
AddOutputFilter DEFLATE php html htm js css xml
</IfModule>

用apxs灵活编译更多的apache模块

在apache安装的时候,可以选择–enable-so这一项,那么就可以通过apxs这个文件来扩展更多的apache 模块了。

不懂安装的请看我的“apache在linux上的编译安装”一文。

查看当前的apache是否支持so:

#/path/to/apache/bin/apachectl -l |grep mod_so

如果列表中有mod_so.c这一项,说明你目前的apache是支持,另外,你的/path/to/apache/bin/下面有没有apxs这个文件。

apxs的部分参数说明:
http://www.linux.gov.cn/netweb/mat/ApacheMenu_zh_CN/dso.html

-n modname
它明确设置了-i(install)和-g (template generation)选项的模块名称。 对-g选项,它是必须的; 对-i选项,apxs工具会按文件名判断至少是推测出这个模块名称。
-q
查询某种apxs设置的信息。 query参数可以是下列一个或多个字串:CC, CFLAGS, CFLAGS_SHLIB, INCLUDEDIR, LD_SHLIB, LDFLAGS_SHLIB, LIBEXECDIR, LIBS_SHLIB, SBINDIR, SYSCONFDIR, TARGET.这个参数用于手动查询某些设置。比如,要手动处理Apache的C头文件,可以在Makefile中使用
-g
此选项生成一个名为name的子目录(见选项-n)和其中的两个文件: 一个是名为mod_name.c的样板模块源程序, 可以用作建立你自己的模块的模板,或是学习使用apxs机制的良好开端; 另一个则是对应的Makefile,用于编译和安装此模块。
-c
此选项表示需要执行编译操作。 它首先会编译C源程序(.c)files为对应的目标代码文件(.o), 然后,连接这些目标代码和files中其余的目标代码文件(.o and .a), 以生成动态共享对象dsofile。如果没有指定-o选项, 则此输出文件名由files中的第一个文件名推测得到, 所以,缺省时,它一般会是mod_name.so
-i
此选项表示需要执行安装操作, 以安装一个或多个动态共享对象到服务器的modules目录中。
-a
此选项自动在httpd.conf文件中增加一个LoadModule行,以激活此模块,或者,如果此行已经存在,则启用之。
-A
与-a选项类似,但是它增加的LoadModule指令由一个井号前缀(#), 即,此模块已经准备就绪,但尚处于禁用状态。
-e
此选项表示需要执行编辑操作,它可以与-a和-A选项配合使用, 与-i操作类似,修改Apache的httpd.conf配置文件,但是并不安装此模块。

apxs的运作原理

一般来说,每个module都对应一个.c文件,放在你apache的源文件目录里面,让apache的这个apxs程序去编译对应的module.c的源文件,会在apache安装目录的modules/文件夹中生成对应的.so文件,再在httpd.conf里面添加LoadModule 指令,那么,每次启动apache 就会把对应的这个module载进来。

这写module的源文件有些有相互依存关系,安装的时候需要注意一下顺序和前后摆放。

通过apxs采用DSO方式安装mod_headers和mod_deflate两个模块:

# cd /path/to/apache/bin/

# ./apxs -i -a -c /path/to/source/modules/filters/mod_deflate.c
# ./apxs –i –a –c /path/to/source/modules/filters/mod_headers.c

去httpd.conf里面看看,两个LoadModule 都放在那里了。

apache在linux上的编译安装

http://www.linux.gov.cn/netweb/mat/ApacheMenu_zh_CN/programs/configure.html

apache拥有4层结构,从核心到外层的module。而外层的module可以用通过静态和动态两种方式与apache共同工作。这也就引入下文的“动态”和“静态”两种编译安装方式:

静态编译:

编译的时候,所有的模块自己编译进httpd 这个文件中 ,启动apache的时候这些模块就已经加载进来了,可以直接来使用,而不用再httpd.conf中在LoadModule来加载,只要在 <ifmodule></ifmodule> 中来配置就可以了。

动态编译:

编译的时候,使用enable-module=shared 或者enable-modules-shared=module来动态编译。 动态显然就不编译到httpd里面去了,启动的时候根本不会加载这个模块, 而是给你一个module.so 文件。你想用,就在httpd.conf中使用 loadmodule 这个语法来加载,这个模块才有效。

区别是:

静态的模块通常在http.conf中用<ifmodule></ifmodule> 来配置,动态的要先loadmoule来加载,然后再<ifmodule></ifmodule>配置。
官方说静态的比动态的在性能方面多5%左右。

相对来说,静态的效率高些,而动态方式配置方面灵活。想想如果编译进去的C这个module你想升级或者去掉,静态方式的就只能重新编译apache了。

下面这句在apache源文件夹下运行,可以查看默认情况下apache都给你装了那些module进去:

./configure –help | grep disable

让apache日后可以动态编译和加载模块:

如果想让apache日后可以支持动态编译(DSO)更多的module,需要在初次安装时把so这个模编译到核心。

如果编译中包含任何DSO模块,则mod_so会被自动包含进核心。如果希望核心能够装载DSO,但不实际编译任何DSO模块,则需明确指定:

针对apache1.x:    –enable-module=so

针对apache2.x: –enable-so=static

apache模块的类型:

基本(B)模块默认包含,必须明确禁用;

扩展(E)/实验(X)模块默认不包含,必须明确启用。

那么,针对以上这些类型的模块,有以下几种操作方式:

–disable-MODULE
禁用MODULE模块(仅用于基本模块)
–enable-MODULE=shared
将MODULE编译为DSO(可用于所有模块)
–enable-MODULE=static
将MODULE静态连接进核心(仅用于扩展和实验模块)
–enable-mods-shared=MODULE-LIST
将MODULE-LIST中的所有模块都编译成DSO(可用于所有模块)
–enable-modules=MODULE-LIST
将MODULE-LIST静态连接进核心(可用于所有模块)

针对–enable-modules和–enable-module-shared有两个懒办法就是 most参数和all参数,分别表示“很多的”和“所有”。

例如:

mod_alias是个基本模块,不想安装的话就: –disable-alias

mod_rewrite是个扩展模块,想动态加载它:–enable-rewrite=shared,想静态加载就是:–enable-rewrite=static

想静态编译mod_alias和mod_rewrite:–enable-modules=’alias rewrite’

想动态编译mod_alias和mod_rewrite:–enable-modules-shared=’alias rewrite’

针对apache2.2.x的一些例子:

最大化静态安装apache:

./configure –prefix=/path/to/local –enable-modules=all

最大化动态安装apache:

./configure –prefix=/path/to/local –enable-mod-shared=all

静态安装rewrite、动态安装deflate以及headers

./configure –prefix=/path/to/local –enable-rewrite=static –enable-deflate=shared –enable-headers=shared

不安装基本的alais,保留以后的扩展DSO能力:

./configure –prefix=/path/to/local –enable-so=static –disable-alias

linux分区点滴

1,必要分开的几个区

/swap     交换分区,大小是物理内存的2倍而不大于4G

/boot     引导区,100-200M够了

/      根分区

2,针对服务器的不同用途

针对服务器的不同用途,来划分其他分区,比如把应用和数据分开多个区放。

未完待续..

杭州拓展训练