wordpress-twentyfifteen主题Google字体本地化配置

在我们的网络环境下,通常情况访问Google所有服务是十分吃力的,我们在使用Wordpress这么优秀的建站程序中,国外的主题一般都有用到Google提供的公共字体库,使用新的字体能让我们的网站变得漂亮美观,但是由于网络因素导致我们的网站打开异常缓慢,从而导致页面无法正常显示。如果你不想替换Google字体库的话,那么你可以在Wordpress插件里面搜索一款名叫“Disable Google Fonts”的插件,安装好后直接启用插件即可关闭Google字体加载。

下载字体包

这是Wordpress-twentyfifteen主题(只针对twentyfifteen主题哦)所用到的字体文件,我已经打包好了,有需要的朋友请下载它们吧。

http://cdn.markdream.com/google/fonts/wp-twentyfifteen-google-fonts.tar.gz

上传字体包

将它们上传到你的服务器上确保能够使用《你的地址》访问它们,修改解压出来的“font.css”文件,将文件里面的“https://api.markdream.com/xxx”的路径替换成你的地址(按照你的实际情况修改),在上传到你的服务器上去覆盖即可。

非同级域名下面的字体文件加载配置(Nginx)

如果你和我一样不再同一个域名下面调用字体的话,你还需要修改一下Webserver的配置文件,我这里就以Nginx为例子:

location / {
     add_header Access-Control-Allow-Origin https://www.markdream.com;
}

那么你会发现,请求这个路径下面的时候Nginx会返回一个头信息,当然像Google这样的公共字体库大家都能够引用它的文件资源,Google字体库的配置大概是这样的:

location / {
     add_header Access-Control-Allow-Origin *;
}

好的绕的有点远,让我们继续回到刚才这里,我们在这里假设上面都已经正确执行了,那么我们来修改一个主题的源代码了,修改别人的源码最简单的方法就是直接进行修改(当然这只是初级阶段,你也得注意要备份),为了简便起见的话,找到我们的twentyfifteen主题下面的functions.php文件,大约在152行,将twentyfifteen_fonts_url方法替换成下面这个方法即可,注意把下面的“fonts-url路径”修改你的,你的,你的路径(重要的事情说三遍):

function twentyfifteen_fonts_url() {
  $fonts_url = 'https://api.markdream.com/libs/google-fonts/wp-twentyfifteen-google-fonts/font.css';
  return $fonts_url;
}

保存好之后,那么你应该是可以去看看你的首页上面是否出现了上面的地址呢?打开的浏览器去试试吧。

更新后续:新增简单优化方案,支持HTTP(s)

这里似乎有一个更好的解决方案,使劲戳这里

了解Javascript模块化开发

小A是某个创业团队的前端工程师,负责编写项目的Javascript程序。

全局变量冲突

根据自己的经验,小A先把一些常用的功能抽出来,写成函数放到一个公用文件base.js中:

var _ = {
    $: function(id) { return document.getElementById(id); },
    getCookie: function(key) { ... },
    setCookie: function(key, value) { ... }
};

小A把这些函数都放在_对象内,以防过多的全局变量造成冲突。他告诉团队的其他成员,如果谁想使用这些函数,只要引入base.js就可以了。

小C是小A的同事,他向小A反映:自己的页面引入了一个叫做underscore.js的类库,而且,这个类库也会占用_这个全局变量,这样一来就会跟base.js中的_冲突了。小A心想,underscore.js是第三方类库,估计不好改,但是base.js已经在很多页面铺开,不可能改。最后小A只好无奈地把underscore.js占用的全局变量改了。

此时,小A发现,把函数都放在一个名字空间内,可以减少全局变量冲突的概率,却没有解决全局变量冲突这个问题。

依赖

随着业务的发展,小A又编写了一系列的函数库和UI组件,比方说标签切换组件tabs.js,此组件需调用base.js以及util.js中的函数。

有一天,新同事小D跟小A反映,自己已经在页面中引用了tabs.js,功能却不正常。小A一看就发现问题了,原来小D不知道tabs.js依赖于base.js以及util.js,他并没有添加这两个文件的引用。于是,他马上进行修改:

<script src="tabs.js"></script>

<script src="base.js"></script>

<script src="util.js"></script>

然而,功能还是不正常,此时小A教训小D说:“都说是依赖,那被依赖方肯定要放在依赖方之前啊”。原来小D把base.js和util.js放到tabs.js之后了。

小A心想,他是作者,自然知道组件的依赖情况,但是别人就难说了,特别是新人。

过了一段时间,小A给标签切换组件增加了功能,为了实现这个功能,tabs.js还需要调用ui.js中的函数。这时,小A发现了一个严重的问题,他需要在所有调用了tabs.js的页面上增加ui.js的引用!!!

又过了一段时间,小A优化了tabs.js,这个组件已经不再依赖于util.js,所以他在所有用到tabs.js的页面中移除了util.js的引用,以提高性能。他这一修改,出大事了,测试组MM告诉他,有些页面不正常了。小A一看,恍然大悟,原来某些页面的其他功能用到了util.js中的函数,他把这个文件的引用去掉导致出错了。为了保证功能正常,他又把代码恢复了。

小A又想,有没有办法在修改依赖的同时不用逐一修改页面,也不影响其他功能呢?

模块化

小A逛互联网的时候,无意中发现了一种新奇的模块化编码方式,可以把它之前遇到的问题全部解决。

在模块化编程方式下,每个文件都是一个模块。每个模块都由一个名为define的函数创建。例如,把base.js改造成一个模块后,代码会变成这样:

define(function(require, exports, module) {
    exports.$ = function(id) { return document.getElementById(id); };
    exports.getCookie = function(key) { ... };
    exports.setCookie = function(key, value) { ... };
});

base.js向外提供的接口都被添加到exports这个对象。而exports是一个局部变量,整个模块的代码都没有占用半个全局变量。

那如何调用某个模块提供的接口呢?以tabs.js为例,它要依赖于base.js和util.js:

define(function(require, exports, module) {
    var _ = require('base.js'), util = require('util.js');
    var div_tabs = _.$('tabs');
    // .... 其他代码
});

一个模块可以通过局部函数require获取其他模块的接口。此时,变量_和util都是局部变量,并且,变量名完全是受开发者控制的,如果你不喜欢_,那也可以用base:

define(function(require, exports, module) {
    var base = require('base.js'), util = require('util.js');
    var div_tabs = base.$('tabs');
    // .... 其他代码
});

一旦要移除util.js、添加ui.js,那只要修改tabs.js就可以了:

define(function(require, exports, module) {
    var base = require('base.js'), ui = require('ui.js');
    var div_tabs = base.$('tabs');
    // .... 其他代码
});

加载器

由于缺乏浏览器的原生支持,如果我们要用模块化的方式编码,就必须借助于一个叫做加载器(loader)的东西。

目前加载器的实现有很多,比如require.js、seajs。而JRaiser类库也有自己的加载器。

 

本文摘自:http://heeroluo.net/article/detail/111

利用PHP调用BizMail OpenApi(腾讯企业邮箱)进行接口开发

以下引自《腾讯企业邮箱OpenApi协议v1.0

腾讯企业邮箱开放协议,包括面向第三方合作应用和面向企业邮用户两类。其中,面向
企业邮用户的开放协议, 将提供给企业邮用户丰富的应用接口, 用户可以根据这些接口定制
自己统一的企业解决方案。
通过协议接口,企业用户可以实现:
1) 单点登录
可以从公司 OA 系统、网站一键进入企业邮箱,免去登录过程。
2) 新邮件提醒
新邮件将即时在 OA 等办公系统提醒你。
3) 数据同步
数据同步可以帮助你同步部门成员信息, 你还可以创建、 删除、 修改帐号, 同步部门信息等。

我一直想用PHP来实现这些功能的调用,把腾讯官方提供的这份简单的文档研究了下,终于弄出来了。做个笔记,如下:
在使用OpenApi接口之前,要先准备好开通腾讯企业邮箱的管理员ID,接口Key(这个可以去企业邮箱管理后台获取)和需要调用信息的邮箱名,然后就可以进行相关调用了,PHP代码如下:

 

// 首先获取AccessToken
 
// 企业邮箱的管理员ID
$cTMailID = 'mymailid';
// 在管理后台获取的接口Key
$cTMailSecret = 'a1234567890b1234567890c123456789';
// 需要调用信息的邮箱名
$cTMailAlias = 'mailalias';
// 获取Token的地址
$cTMailGetAccessTokenURL = 'https://exmail.qq.com/cgi-bin/token';
$cTMailContentData = 'grant_type=client_credentials&client_id=' . $cTMailID . '&client_secret=' . $cTMailSecret;
 
// 获取access_token
// 不要问我为什么这么写,早就忘记了!-_-
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailGetAccessTokenURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
$cTMailAccessToken = $json_obj['access_token'];
 
// 打印获取的AccessToken
echo $cTMailAccessToken . '
';
 
 
 
// 获取auth_key
$cTMailGetAuthKeyURL = 'http://openapi.exmail.qq.com:12211/openapi/mail/authkey';
$cTMailContentData = 'access_token=' . $cTMailAccessToken . '&alias=' . $cTMailAlias;
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailGetAuthKeyURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
$cTMailAuthKey = $json_obj['auth_key'];
 
 
// 一键登录
$cURL = 'https://exmail.qq.com/cgi-bin/login?fun=bizopenssologin&method=bizauth&agent=' . $cTMailID . '&user=' . $cTMailAlias . '&ticket=' . $cTMailAuthKey;
echo '一键登录';
 
 
// 获取用户信息
$cTMailPostURL = 'http://openapi.exmail.qq.com:12211/openapi/user/get';
$cTMailContentData = 'access_token=' . $cTMailAccessToken . '&alias=' . $cTMailAlias;
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailPostURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, 75);
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
print_r($json_obj);
echo '
';
echo 'Email地址:' . $json_obj['Alias'] . '
';
echo '姓名:' . $json_obj['Name'] . '
';
echo '性别:' . $json_obj['Gender'] . '
';
echo '职位:' . $json_obj['Position'] . '
';
echo '电话:' . $json_obj['Tel'] . '
';
echo '手机号码:' . $json_obj['Mobile'] . '
';
echo '员工编号:' . $json_obj['ExtId'] . '
';
 
 
 
// 获取用户未读邮件数量
$cTMailPostURL = 'http://openapi.exmail.qq.com:12211/openapi/mail/newcount';
$cTMailContentData = 'access_token=' . $cTMailAccessToken . '&alias=' . $cTMailAlias;
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailPostURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, 75);
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
// 打印获取的信息
print_r($json_obj);
 
 
// 客户端维持长连接
$cTMailPostURL = 'http://openapi.exmail.qq.com:12211/openapi/listen';
$cTMailContentData = 'access_token=' . $cTMailAccessToken . '&alias=' . $cTMailAlias;
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailPostURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT, 75);
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
print_r($json_obj);
 
 
 
// 获取子部门列表
$cTMailPostURL = 'http://openapi.exmail.qq.com:12211/openapi/party/list';
$cTMailContentData = 'access_token=' . $cTMailAccessToken . '&partypath=';
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailPostURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
echo '
获取的子部门列表:';
print_r($json_obj);
 
 
 
// 获取部门下成员列表
$cTMailPostURL = 'http://openapi.exmail.qq.com:12211/openapi/partyuser/list';
$cTMailContentData = 'access_token=' . $cTMailAccessToken . '&partypath=XX公司/财务部';
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$cTMailPostURL);
curl_setopt($ch,CURLOPT_POSTFIELDS,$cTMailContentData);
curl_setopt($ch,CURLOPT_ENCODING,'UTF-8');
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1 );
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
echo '
获取的子部门成员列表:';
print_r($json_obj);

原文参考:http://www.barhe.org/archives/561
官方手册:http://cdn.markdream.com/ref/mat/%E8%85%BE%E8%AE%AF%E4%BC%81%E4%B8%9A%E9%82%AE%E7%AE%B1OpenApi%E5%8D%8F%E8%AE%AEv1.0.pdf

nginx使用XSendfile模块让php更快下载文件实战

引言

最近有点闲暇时间了,看了@风雪之隅的一篇的文章《让PHP更快的提供文件下载》后,利用实际项目中的业务场景觉得有必须要去优化附件下载功能了。鸟哥的文章里面主要介绍的基于apache来做XSendfile讲解的,我有点强迫症,我对我的生产环境《顶岗实习管理系统》进行升级改造,我的webserver是nginx,所以基于nginx官方网站的XSendfile说明特做此改造笔记。

我的webroot目录在/var/vhost/demo,demo目录中存在一个uploadfiles文件夹,这个文件夹是存放用户上传的文件。比如一个用户上传一个hello.docx文件,那么它对应的物理路径应该是/var/vhost/demo/xsendfile/uploadfiles/hello.docx,如果我们以直接路径“http://demo.markdream.com/xsendfile/uploadfiles/hello.docx”来访问的话,那么我想对这个文件进行下载统计或者隐藏实体路径的话就只能使用php readfile()方法来把文件装载到内存中,在转发给客户端,如果文件超大的话,你的服务器估计很悬。所以我们要改进php下载方式,就是引言所阐述的利用nginx的XSendfile方式来传送文件给客户端,nginx默认已经包含了senfile模块了,你如果安装完nginx你会在nginx.conf文件会看到“sendfile on;”,OK说明你可以直接使用了不像apache那么复杂还要重新加载组件编译等等。好了我贴下我的配置文件和代码。

我的nginx虚拟主机配置文件

server {
        listen 80;
        server_name demo.markdream.com;

        root /var/vhost/demo;
        index  index.php;

		# 这个是定义读取你的文件的目录的url开头  直接访问是不可以的 只能通过
        location /protected {
                internal;
                alias   /var/vhost/demo/uploadfiles;
        }

        location ~ \.php$ {
           fastcgi_pass   127.0.0.1:9000;
           fastcgi_index  index.php;
           fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
           include        fastcgi_params;
        }
}

一个简单的php下载文件脚本,downloads.php

<?php

//eg: http://demo.markdream.com/xsendfile/downloads.php?filename=hello.docx

// 获取文件名
$filename = $_GET["filename"];

// 你可以在这里写下你的查询数据库等你所想的功能 ……

header ( "Content-type: application/octet-stream" );
// 处理中文文件名
$ua = $_SERVER ["HTTP_USER_AGENT"];
if (preg_match ( "/MSIE/", $ua )) {
 $encoded_filename = rawurlencode ( $filename );
 header ( 'Content-Disposition: attachment; filename="' . $encoded_filename . '"' );
} else if (preg_match ( "/Firefox/", $ua )) {
 header ( "Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"' );
} else {
 header ( 'Content-Disposition: attachment; filename="' . $filename . '"' );
}

// 就这么简单一句话搞定 注意“protected”是和nginx配置文件的 protected要一致
header("X-Accel-Redirect: /protected/" . $filename);

?>

愉悦的demo

http://demo.markdream.com/xsendfile/downloads.php?filename=hello.docx

参考

  1. http://wiki.nginx.org/XSendfile
  2. http://www.laruence.com/2012/05/02/2613.html
  3. http://kovyrin.net/2006/11/01/nginx-x-accel-redirect-php-rails/

让php获取图片的exif信息

生产环境中,我们有业务上的需求,比如搞什么摄影网站,或者相册图集功能。用户上传的图片我们不仅要满足用户上传图片的保存,还应该将一些专业的照片参数进行保存起来,这样在一些专业的图片网站上(比较摄影爱好者论坛)应该要分享这些相机型号、感光度、光圈、快门等等信息。

在默认的php版本中是没有对php_exif扩展的安装所以还需要我们针对服务器进行安装php-exif安装支持。
具体的检查你可以使用phpinfo()查看下是否存在exif组件项目,如果存在证明你的服务器已经安装了exif扩展,如果没有则安装之。

安装php_exif组件

要安装php_exif组件,首先我们还是要打开php源码安装文件夹中的ext/exif,命令如下(具体路径以你服务器实际地址为准)

cd /usr/local/src/php-5.4.8/ext/exif

/opt/php/bin/phpize

./configure --with-php-config=/opt/php/bin/php-config
 
make && make install

安装完毕之后,你需要将php_exif扩展添加到php.ini文件中

vi /opt/php/lib/php.ini

#找到extension列表中  添加一行  extension=exif.so

然后重启下php-fpm,再去phpinfo函数中查看下exif组件是否存在了。

使用exif获取照片信息

上个步骤就是在安装exif,下面我们来使用exif来获取照片信息,网络上面有一个很不错的类,我顺手把它们摘抄到这里了,已经做测试优化,直接使用是没有问题的。

<?php

error_reporting(0);

/**
* 获取图象信息的函数
*
* 一个全面获取图象信息的函数
*
* @access public
* @param string $img 图片路径
* @return array
*/
function GetImageInfoVal($ImageInfo,$val_arr) {
 $InfoVal = "未知";
 foreach($val_arr as $name=>$val) {
 if ($name==$ImageInfo) {
 $InfoVal = &$val;
 break;
 }
 }
 return $InfoVal;
}
function GetImageInfo($img) {
 $imgtype = array("", "GIF", "JPG", "PNG", "SWF", "PSD", "BMP", "TIFF(intel byte order)", "TIFF(motorola byte order)", "JPC", "JP2", "JPX", "JB2", "SWC", "IFF", "WBMP", "XBM");
 $Orientation = array("", "top left side", "top right side", "bottom right side", "bottom left side", "left side top", "right side top", "right side bottom", "left side bottom");
 $ResolutionUnit = array("", "", "英寸", "厘米");
 $YCbCrPositioning = array("", "the center of pixel array", "the datum point");
 $ExposureProgram = array("未定义", "手动", "标准程序", "光圈先决", "快门先决", "景深先决", "运动模式", "肖像模式", "风景模式");
 $MeteringMode_arr = array(
 "0" => "未知",
 "1" => "平均",
 "2" => "中央重点平均测光",
 "3" => "点测",
 "4" => "分区",
 "5" => "评估",
 "6" => "局部",
 "255" => "其他"
 );
 $Lightsource_arr = array(
 "0" => "未知",
 "1" => "日光",
 "2" => "荧光灯",
 "3" => "钨丝灯",
 "10" => "闪光灯",
 "17" => "标准灯光A",
 "18" => "标准灯光B",
 "19" => "标准灯光C",
 "20" => "D55",
 "21" => "D65",
 "22" => "D75",
 "255" => "其他"
 );
 $Flash_arr = array(
 "0" => "flash did not fire",
 "1" => "flash fired",
 "5" => "flash fired but strobe return light not detected",
 "7" => "flash fired and strobe return light detected",
 );
 
 $exif = exif_read_data ($img,"IFD0");
 if ($exif===false) {
 $new_img_info = array ("文件信息" => "没有图片EXIF信息");
 }else{
 $exif = exif_read_data ($img,0,true);
 $new_img_info = array (
 "文件信息" => "-----------------------------",
 "文件名" => $exif['FILE']['FileName'],
 "文件类型" => $imgtype[$exif['FILE']['FileType']],
 "文件格式" => $exif['FILE']['MimeType'],
 "文件大小" => $exif['FILE']['FileSize'],
 "时间戳" => date("Y-m-d H:i:s",$exif['FILE']['FileDateTime']),
 "图像信息" => "-----------------------------",
 "图片说明" => $exif['IFD0']['ImageDescription'],
 "制造商" => $exif['IFD0']['Make'],
 "型号" => $exif['IFD0']['Model'],
 "方向" => $Orientation[$exif['IFD0']['Orientation']],
 "水平分辨率" => $exif['IFD0']['XResolution'].$ResolutionUnit[$exif['IFD0']['ResolutionUnit']],
 "垂直分辨率" => $exif['IFD0']['YResolution'].$ResolutionUnit[$exif['IFD0']['ResolutionUnit']],
 "创建软件" => $exif['IFD0']['Software'],
 "修改时间" => $exif['IFD0']['DateTime'],
 "作者" => $exif['IFD0']['Artist'],
 "YCbCr位置控制" => $YCbCrPositioning[$exif['IFD0']['YCbCrPositioning']],
 "版权" => $exif['IFD0']['Copyright'],
 "摄影版权" => $exif['COMPUTED']['Copyright.Photographer'],
 "编辑版权" => $exif['COMPUTED']['Copyright.Editor'],
 "拍摄信息" => "-----------------------------",
 "Exif版本" => $exif['EXIF']['ExifVersion'],
 "FlashPix版本" => "Ver. ".number_format($exif['EXIF']['FlashPixVersion']/100,2),
 "拍摄时间" => $exif['EXIF']['DateTimeOriginal'],
 "数字化时间" => $exif['EXIF']['DateTimeDigitized'],
 "拍摄分辨率高" => $exif['COMPUTED']['Height'],
 "拍摄分辨率宽" => $exif['COMPUTED']['Width'],
 /*
 The actual aperture value of lens when the image was taken.
 Unit is APEX.
 To convert this value to ordinary F-number(F-stop),
 calculate this value's power of root 2 (=1.4142).
 For example, if the ApertureValue is '5', F-number is pow(1.41425,5) = F5.6.
 */
 "光圈" => $exif['EXIF']['ApertureValue'],
 "快门速度" => $exif['EXIF']['ShutterSpeedValue'],
 "快门光圈" => $exif['COMPUTED']['ApertureFNumber'],
 "最大光圈值" => "F".$exif['EXIF']['MaxApertureValue'],
 "曝光时间" => $exif['EXIF']['ExposureTime'],
 "F-Number" => $exif['EXIF']['FNumber'],
 "测光模式" => GetImageInfoVal($exif['EXIF']['MeteringMode'],$MeteringMode_arr),
 "光源" => GetImageInfoVal($exif['EXIF']['LightSource'], $Lightsource_arr),
 "闪光灯" => GetImageInfoVal($exif['EXIF']['Flash'], $Flash_arr),
 "曝光模式" => ($exif['EXIF']['ExposureMode']==1?"手动":"自动"),
 "白平衡" => ($exif['EXIF']['WhiteBalance']==1?"手动":"自动"),
 "曝光程序" => $ExposureProgram[$exif['EXIF']['ExposureProgram']],
 /*
 Brightness of taken subject, unit is APEX. To calculate Exposure(Ev) from BrigtnessValue(Bv), you must add SensitivityValue(Sv).
 Ev=Bv+Sv Sv=log((ISOSpeedRating/3.125),2)
 ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32. 
 */
 "曝光补偿" => $exif['EXIF']['ExposureBiasValue']."EV",
 "ISO感光度" => $exif['EXIF']['ISOSpeedRatings'],
 "分量配置" => (bin2hex($exif['EXIF']['ComponentsConfiguration'])=="01020300"?"YCbCr":"RGB"),//'0x04,0x05,0x06,0x00'="RGB" '0x01,0x02,0x03,0x00'="YCbCr"
 "图像压缩率" => $exif['EXIF']['CompressedBitsPerPixel']."Bits/Pixel",
 "对焦距离" => $exif['COMPUTED']['FocusDistance']."m",
 "焦距" => $exif['EXIF']['FocalLength']."mm",
 "等价35mm焦距" => $exif['EXIF']['FocalLengthIn35mmFilm']."mm",
 /*
 Stores user comment. This tag allows to use two-byte character code or unicode. First 8 bytes describe the character code. 'JIS' is a Japanese character code (known as Kanji).
 '0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
 '0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
 '0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
 '0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined
 */
 "用户注释编码" => $exif['COMPUTED']['UserCommentEncoding'],
 "用户注释" => $exif['COMPUTED']['UserComment'],
 "色彩空间" => ($exif['EXIF']['ColorSpace']==1?"sRGB":"Uncalibrated"),
 "Exif图像宽度" => $exif['EXIF']['ExifImageLength'],
 "Exif图像高度" => $exif['EXIF']['ExifImageWidth'],
 "文件来源" => (bin2hex($exif['EXIF']['FileSource'])==0x03?"digital still camera":"unknown"),
 "场景类型" => (bin2hex($exif['EXIF']['SceneType'])==0x01?"A directly photographed image":"unknown"),
 "缩略图文件格式" => $exif['COMPUTED']['Thumbnail.FileType'],
 "缩略图Mime格式" => $exif['COMPUTED']['Thumbnail.MimeType']
 );
 }
 return $new_img_info;
}
 
$innerhtml = "";
$exif = GetImageInfo($_GET['img']);

$innerhtml .= "<table>";
 
foreach($exif as $name=>$val) {
 $innerhtml .= "<tr><td>{$name}</td><td>{$val}</td></tr>";
}
 
$innerhtml .= "<tr><td colspan=\"2\">";

$innerhtml .= "</td></tr></table>";
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>markdream.com</title>
<style>body{font-size:12px;}table{margin: 30px auto;}</style>
</head>
<body>

<?php echo $innerhtml;?>
</body>
</html>

 

 演示demo

http://demo.markdream.com/exif/x.php?img=zz.JPG

MySQL字符串函数简单应用介绍

有一些特殊的业务需求,我们有时候可能会mysql的字符串函数,最好的解决方案还是拿出数据用程序来处理,不扯犊子了。这篇文章也是从

MySQL字符串函数:字符串截取转载过来的。

MySQL 字符串截取函数:left(), right(), substring(), substring_index()。还有 mid(), substr()。其中,mid(), substr() 等价于 substring() 函数,substring() 的功能非常强大和灵活。

1. 字符串截取:left(str, length)

mysql> select left('sqlstudy.com', 3);
+-------------------------+
| left('sqlstudy.com', 3) |
+-------------------------+
| sql                     |
+-------------------------+

2. 字符串截取:right(str, length)

mysql> select right('sqlstudy.com', 3);
+--------------------------+
| right('sqlstudy.com', 3) |
+--------------------------+
| com                      |
+--------------------------+

3. 字符串截取:substring(str, pos); substring(str, pos, len)

3.1 从字符串的第 4 个字符位置开始取,直到结束。

mysql> select substring('sqlstudy.com', 4);
+------------------------------+
| substring('sqlstudy.com', 4) |
+------------------------------+
| study.com                    |
+------------------------------+

3.2 从字符串的第 4 个字符位置开始取,只取 2 个字符。

mysql> select substring('sqlstudy.com', 4, 2);
+---------------------------------+
| substring('sqlstudy.com', 4, 2) |
+---------------------------------+
| st                              |
+---------------------------------+

3.3 从字符串的第 4 个字符位置(倒数)开始取,直到结束。

mysql> select substring('sqlstudy.com', -4);
+-------------------------------+
| substring('sqlstudy.com', -4) |
+-------------------------------+
| .com                          |
+-------------------------------+

3.4 从字符串的第 4 个字符位置(倒数)开始取,只取 2 个字符。

mysql> select substring('sqlstudy.com', -4, 2);
+----------------------------------+
| substring('sqlstudy.com', -4, 2) |
+----------------------------------+
| .c                               |
+----------------------------------+

我们注意到在函数 substring(str,pos, len)中, pos 可以是负值,但 len 不能取负值。

4. 字符串截取:substring_index(str,delim,count)

4.1 截取第二个 ‘.’ 之前的所有字符。

mysql> select substring_index('www.sqlstudy.com.cn', '.', 2);
+------------------------------------------------+
| substring_index('www.sqlstudy.com.cn', '.', 2) |
+------------------------------------------------+
| www.sqlstudy                                   |
+------------------------------------------------+

4.2 截取第二个 ‘.’ (倒数)之后的所有字符。

mysql> select substring_index('www.sqlstudy.com.cn', '.', -2);
+-------------------------------------------------+
| substring_index('www.sqlstudy.com.cn', '.', -2) |
+-------------------------------------------------+
| com.cn                                          |
+-------------------------------------------------+

4.3 如果在字符串中找不到 delim 参数指定的值,就返回整个字符串

mysql> select substring_index('www.sqlstudy.com.cn', '.coc', 1);
+---------------------------------------------------+
| substring_index('www.sqlstudy.com.cn', '.coc', 1) |
+---------------------------------------------------+
| www.sqlstudy.com.cn                               |
+---------------------------------------------------+

ASCII(str)

返回字符串str的最左面字符的ASCII代码值。如果str是空字符串,返回0。如果str是NULL,返回NULL。

如:select ASCII('2');select ASCII(2); 结果都为2的Ascii码值 50   
如:select ASCII('2');select ASCII(2); 结果都为2的Ascii码值 50

CHAR(N,…)

CHAR()将参数解释为整数并且返回由这些整数的ASCII代码字符组成的一个字符串。NULL值被跳过。

select CHAR(77,121,83,81,NULL);  结果为 MySQ ; 
select CHAR(77,121,83,81,NULL);  结果为 MySQ ;

CONCAT(str1,str2,…)

返回来自于参数连结的字符串。如果任何参数是NULL,返回NULL。可以有超过2个的参数。一个数字参数被变换为等价的字符串形式。

select CONCAT('My', 'S', 'QL');  //MySQL  
select CONCAT(12.3); //'12.3' 
select CONCAT('My', 'S', 'QL');  //MySQL
select CONCAT(12.3); //'12.3'

LENGTH(str)

计算字符串长度 :select length(‘text’) ; //4

LOCATE(substr,str)  
POSITION(substr IN str)

返回子串substr在字符串str第一个出现的位置,如果substr不是在str里面,返回0.

mysql> select LOCATE('bar', 'foobarbar');  
      -> 4 
mysql> select LOCATE('xbar', 'foobar');  
       -> 0 
mysql> select LOCATE('bar', 'foobarbar');
        -> 4
mysql> select LOCATE('xbar', 'foobar');
        -> 0该函数是多字节可靠的

LOCATE(substr,str,pos)

返回子串substr在字符串str第一个出现的位置,从位置pos开始。如果substr不是在str里面,返回0。

mysql> select LOCATE('bar', 'foobarbar',5);  
    -> 7 
mysql> select LOCATE('bar', 'foobarbar',5);
    -> 7

INSTR(str,substr)

返回子串substr在字符串str中的第一个出现的位置。这与有2个参数形式的LOCATE()相同,除了参数被颠倒。

mysql> select INSTR('foobarbar', 'bar');  
    -> 4 
mysql> select INSTR('xbar', 'foobar');  
    -> 0 
mysql> select INSTR('foobarbar', 'bar');
    -> 4
mysql> select INSTR('xbar', 'foobar');
    -> 0这函数是多字节可靠的。

LPAD(str,len,padstr)

返回字符串str,左面用字符串padstr填补直到str是len个字符长。

mysql> select LPAD('hi',4,'??');  
    -> '??hi'

RPAD(str,len,padstr)

返回字符串str,右面用字符串padstr填补直到str是len个字符长。

mysql> select LPAD('hi',4,'??');
    -> '??hi'

RPAD(str,len,padstr)

返回字符串str,右面用字符串padstr填补直到str是len个字符长。

  
mysql> select RPAD('hi',5,'?');
    -> 'hi???'

LEFT(str,len)

返回字符串str的最左面len个字符。

mysql> select LEFT('foobarbar', 5);  
    -> 'fooba'该函数是多字节可靠的。 
mysql> select LEFT('foobarbar', 5);
    -> 'fooba'该函数是多字节可靠的。

RIGHT(str,len)

返回字符串str的最右面len个字符。

mysql> select RIGHT('foobarbar', 4);  
    -> 'rbar'

该函数是多字节可靠的。

SUBSTRING(str,pos)

从字符串str的起始位置pos返回一个子串。

mysql> select SUBSTRING('Quadratically',5);
        -> 'ratically'
mysql> select SUBSTRING('foobarbar' FROM 4);
        -> 'barbar'

该函数是多字节可靠的。

SUBSTRING_INDEX(str,delim,count)

返回从字符串str的第count个出现的分隔符delim之后的子串。如果count是正数,返回最后的分隔符到左边(从左边数) 的所有字符。如果count是负数,返回最后的分隔符到右边的所有字符(从右边数)。

mysql> select SUBSTRING_INDEX('www.mysql.com', '.', 2);
        -> 'www.mysql'
mysql> select SUBSTRING_INDEX('www.mysql.com', '.', -2);
        -> 'mysql.com'

该函数对多字节是可靠的。

LTRIM(str)

返回删除了其前置空格字符的字符串str。

mysql> select LTRIM('  barbar');
        -> 'barbar'

RTRIM(str)

返回删除了其拖后空格字符的字符串str。

mysql> select RTRIM('barbar   ');
        -> 'barbar'

该函数对多字节是可靠的。

TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)

返回字符串str,其所有remstr前缀或后缀被删除了。如果没有修饰符BOTH、LEADING或TRAILING给出,BOTH被假定。如果remstr没被指定,空格被删除。

mysql> select TRIM('  bar   ');
        -> 'bar'
mysql> select TRIM(LEADING 'x' FROM 'xxxbarxxx');
        -> 'barxxx'
mysql> select TRIM(BOTH 'x' FROM 'xxxbarxxx');
        -> 'bar'
mysql> select TRIM(TRAILING 'xyz' FROM 'barxxyz');
        -> 'barx'

该函数对多字节是可靠的。

SOUNDEX(str)

返回str的一个同音字符串。听起来“大致相同”的2个字符串应该有相同的同音字符串。一个“标准”的同音字符串长是4个字符,但是SOUNDEX()函数返回一个任意长的字符串。你可以在结果上使用SUBSTRING()得到一个“标准”的 同音串。所有非数字字母字符在给定的字符串中被忽略。所有在A-Z之外的字符国际字母被当作元音。

mysql> select SOUNDEX('Hello');
        -> 'H400'
mysql> select SOUNDEX('Quadratically');
        -> 'Q36324'

SPACE(N)

返回由N个空格字符组成的一个字符串。

mysql> select SPACE(6);
        -> '      '

REPLACE(str,from_str,to_str)

返回字符串str,其字符串from_str的所有出现由字符串to_str代替。

mysql> select REPLACE('www.mysql.com', 'w', 'Ww');
        -> 'WwWwWw.mysql.com'

该函数对多字节是可靠的。

REPEAT(str,count)

返回由重复countTimes次的字符串str组成的一个字符串。如果count <= 0,返回一个空字符串。如果str或count是NULL,返回NULL。

mysql> select REPEAT('MySQL', 3);
        -> 'MySQLMySQLMySQL'

REVERSE(str)

返回颠倒字符顺序的字符串str。

mysql> select REVERSE('abc');
        -> 'cba'

该函数对多字节可靠的。

INSERT(str,pos,len,newstr)

返回字符串str,在位置pos起始的子串且len个字符长得子串由字符串newstr代替。

mysql> select INSERT('Quadratic', 3, 4, 'What');
        -> 'QuWhattic'

该函数对多字节是可靠的。

ELT(N,str1,str2,str3,…)

如果N= 1,返回str1,如果N= 2,返回str2,等等。如果N小于1或大于参数个数,返回NULL。ELT()是FIELD()反运算。

mysql> select ELT(1, 'ej', 'Heja', 'hej', 'foo');
        -> 'ej'
mysql> select ELT(4, 'ej', 'Heja', 'hej', 'foo');
        -> 'foo'

FIELD(str,str1,str2,str3,…)

返回str在str1, str2, str3, …清单的索引。如果str没找到,返回0。FIELD()是ELT()反运算。

mysql> select FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');
        -> 2
mysql> select FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo');
        -> 0

FIND_IN_SET(str,strlist)

如果字符串str在由N子串组成的表strlist之中,返回一个1到N的值。一个字符串表是被“,”分隔的子串组成的一个字符串。如果第一个参数是一个常数字符串并且第二个参数是一种类型为SET的列,FIND_IN_SET()函数被优化而使用位运算!如果str不是在strlist里面或如果strlist是空字符串,返回0。如果任何一个参数是NULL,返回NULL。如果第一个参数包含一个“,”,该函数将工作不正常。

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
        -> 2

MAKE_SET(bits,str1,str2,…)

返回一个集合 (包含由“,”字符分隔的子串组成的一个字符串),由相应的位在bits集合中的的字符串组成。str1对应于位0,str2对应位1,等等。在str1, str2, …中的NULL串不添加到结果中。

mysql> SELECT MAKE_SET(1,'a','b','c');
        -> 'a'
mysql> SELECT MAKE_SET(1 | 4,'hello','nice','world');
        -> 'hello,world'
mysql> SELECT MAKE_SET(0,'a','b','c');
        -> ''

EXPORT_SET(bits,on,off,[separator,[number_of_bits]])

返回一个字符串,在这里对于在“bits”中设定每一位,你得到一个“on”字符串,并且对于每个复位(reset)的位,你得到一个“off”字符串。每个字符串用“separator”分隔(缺省“,”),并且只有“bits”的“number_of_bits” (缺省64)位被使用。

mysql> select EXPORT_SET(5,'Y','N',',',4)
        -> Y,N,Y,N

LCASE(str)

LOWER(str) 返回字符串str,根据当前字符集映射(缺省是ISO-8859-1 Latin1)把所有的字符改变成小写。该函数对多字节是可靠的。

mysql> select LCASE('QUADRATICALLY');
        -> 'quadratically'

UCASE(str)

返回字符串str,根据当前字符集映射(缺省是ISO-8859-1 Latin1)把所有的字符改变成大写。该函数对多字节是可靠的。

mysql> select UCASE('Hej');
        -> 'HEJ'

该函数对多字节是可靠的。

LOAD_FILE(file_name)

读入文件并且作为一个字符串返回文件内容。文件必须在服务器上,你必须指定到文件的完整路径名,而且你必须有file权限。文件必须所有内容都是可读的并且小于max_allowed_packet。如果文件不存在或由于上面原因之一不能被读出,函数返回NULL。

mysql> UPDATE table_name
           SET blob_column=LOAD_FILE("/tmp/picture")
           WHERE id=1;

MySQL必要时自动变换数字为字符串,并且反过来也如此:

mysql> SELECT 1+"1";
        -> 2
mysql> SELECT CONCAT(2,' test');
        -> '2 test'

如果你想要明确地变换一个数字到一个字符串,把它作为参数传递到CONCAT()。

如果字符串函数提供一个二进制字符串作为参数,结果字符串也是一个二进制字符串。被变换到一个字符串的数字被当作是一个二进制字符串。这仅影响比较。