cnx7 发布的文章
图片 压缩/上传 被旋转的问题解决方案
手机拍照上传的文件有时候方向会变,文件EXIF信息引起的,有的浏览器不支持解析EXIF就会出现问题,包括一些图片压缩软件/插件/中间件,比如Nginx的image_filter组件以及ImageOptim之类的软件。
解决方案:上传图片检测图片是否存在EXIF信息的旋转标记,清空标记并生成新的图片。
建议跳过GIF图片的处理
/**
* 图片处理/压缩
* @param $path string 原图片路径
* @param string $new_path string 新的图片路径,为空则覆盖原图
* @param int $cr 压缩率,为空则是70%
* @return bool
*/
function imgDeal($path, $new_path = '', $cr = 70) {
$new_path = $new_path ? $new_path : $path;
$exif = exif_read_data($path, 0, true);
$data = @getimagesize($path);
if (!$data) return false;
$w = $data[0];
$h = $data[1];
$xz = 0;
if ($exif && !empty($exif['IFD0'])) {
if (!empty($exif['IFD0']['Orientation'])) {
switch ($exif['IFD0']['Orientation']) {
case 3:
$xz = 180;
break;
case 6:
$xz = -90;
$w = $data[1];
$h = $data[0];
break;
case 8:
$xz = 90;
$w = $data[1];
$h = $data[0];
break;
default:
# code...
break;
}
}
}
//读取旧图片
$src_f = '';
switch ($data[2]) {
case 1:
$src_f = imagecreatefromgif($path);
break;
case 2:
$src_f = imagecreatefromjpeg($path);
break;
case 3:
$src_f = imagecreatefrompng($path);
break;
}
if ($src_f == "") return false;
$rotate = @imagerotate($src_f, $xz, 0);
$newim = imagecreatetruecolor($w,$h);
imagecopyresampled($newim, $rotate, 0, 0, 1, 1, $w, $h, $w - 3, $h - 3);
if (!imagejpeg($newim, $new_path, $cr)) return false;
@imagedestroy($rotate);
@imagedestroy($newim);
return true;
}
php 无法加载 mcrypt.so 的解决方案
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/local/opt/php56-mcrypt/mcrypt.so' - dlopen(/usr/local/opt/php56-mcrypt/mcrypt.so, 9): Library not loaded: /usr/local/opt/libtool/lib/libltdl.7.dylib
Referenced from: /usr/local/opt/php56-mcrypt/mcrypt.so
Reason: image not found in Unknown on line 0
解决方案
brew install libtool
RabbitMQ 工作队列简单 Demo
composer.json
{
"require": {
"php-amqplib/php-amqplib": "2.5.*"
}
}
task.php
<?php
/**
* task.php
*
* @author: R2A <zysafe@live.cn> 2017-03-13
*/
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
// 建立到RabbitMQ的连接
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// 声明持久化队列 第三个参数为true
$channel->queue_declare('test', false, true, false, false);
$data = implode(' ', array_slice($argv, 1));
if (empty($data)) $data = "Hello World!";
for ($i = 0; $i < 10; $i++) {
// 测试数据 每一个.代表1秒执行时间
$str = '';
for ($j = 0; $j < rand(0, 5); $j++) $str .= '.';
$data = $i . $str;
// 设置持久化消息 delivery_mode 为2
$msg = new AMQPMessage($data,
array('delivery_mode' => 2) # make message persistent
);
$channel->basic_publish($msg, '', 'test');
echo " [x] Sent ", $data, "\n";
}
$channel->close();
$connection->close();
worker.php
<?php
/**
* worker.php
*
* @author: R2A <zysafe@live.cn> 2017-03-13
*/
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// 持久化队列 第三个参数为true
$channel->queue_declare('test', false, true, false, false);
echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";
$callback = function ($msg) {
echo " [x] Received ", $msg->body, "\n";
sleep(substr_count($msg->body, '.'));
echo " [x] Done", "\n";
// 返回响应 通知已结束
$msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};
// basic_qos 的第二个参数设置为1 同时不发送超过1条消息到worker
$channel->basic_qos(null, 1, null);
$channel->basic_consume('test', '', false, false, false, false, $callback);
$i = 0;
while (count($channel->callbacks)) {
echo $i++;
$channel->wait();
}
$channel->close();
$connection->close();
可同时开启多个worker消费,中断退出无影响
golang 的并发处理示例
package main
import (
"fmt"
"sync"
"time"
)
func f(wg *sync.WaitGroup, val string) {
fmt.Println(val, "begin")
time.Sleep(2 * time.Second) // 这里处理需要3秒钟
fmt.Printf("Finished: %v - %v\n", val, time.Now())
wg.Done()
}
func main() {
t1 := time.Now()
var wg sync.WaitGroup
wg.Add(3) // 我们要做三个并发任务,这里添加3个协程
go f(&wg, "goroutine A") // 第一个任务:实行函数 f
// 第二个任务,匿名闭包函数
go func(wg *sync.WaitGroup, val string) {
fmt.Println(val, "begin")
time.Sleep(3 * time.Second) // 处理需要3秒钟
fmt.Printf("Finished: %v - %v\n", val, time.Now())
wg.Done()
}(&wg, "goroutine B") // 调用匿名函数
go f(&wg, "goroutine C") // 第三个任务,调用f 函数
wg.Wait() // 等待所有任务完成
fmt.Printf("Finished all goroutines: %v\n", time.Now())
t2 := time.Now()
fmt.Println("消耗时间:", t2.Sub(t1), "秒")
}