ter = array_value($config, 'filter'); $arr = array_value($filter, $type); $enable = array_value($arr, 'enable'); $wordarr = array_value($arr, 'keyword'); if (0 == $enable || empty($wordarr)) return FALSE; foreach ($wordarr as $_keyword) { if (!$_keyword) continue; $r = strpos(strtolower($keyword), strtolower($_keyword)); if (FALSE !== $r) { $error = $_keyword; return TRUE; } } return FALSE; } // return http://domain.com OR https://domain.com function url_prefix() { $http = ((isset($_SERVER['HTTPS']) && 'on' == $_SERVER['HTTPS']) || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://'; return $http . $_SERVER['HTTP_HOST']; } // 唯一身份ID function uniq_id() { return uniqid(substr(md5(microtime(true) . mt_rand(1000, 9999)), 8, 8)); } // 生成订单号 14位 function trade_no() { $trade_no = str_replace('.', '', microtime(1)); $strlen = mb_strlen($trade_no, 'UTF-8'); $strlen = 14 - $strlen; $str = ''; if ($strlen) { for ($i = 0; $i <= $strlen; $i++) { if ($i < $strlen) $str .= '0'; } } return $trade_no . $str; } // 生成订单号 16位 function trade_no_16() { $explode = explode(' ', microtime()); $trade_no = $explode[1] . mb_substr($explode[0], 2, 6, 'UTF-8'); return $trade_no; } // 当前年的天数 function date_year($time = NULL) { $time = intval($time) ? $time : time(); return date('L', $time) + 365; } // 当前年份中的第几天 function date_z($time = NULL) { $time = intval($time) ? $time : time(); return date('z', $time); } // 当前月份中的第几天,没有前导零 1 到 31 function date_j($time = NULL) { $time = intval($time) ? $time : time(); return date('j', $time); } // 当前月份中的第几天,有前导零的2位数字 01 到 31 function date_d($time = NULL) { $time = intval($time) ? $time : time(); return date('d', $time); } // 当前时间为星期中的第几天 数字表示 1表示星期一 到 7表示星期天 function date_w_n($time = NULL) { $time = intval($time) ? $time : time(); return date('N', $time); } // 当前日第几周 function date_d_w($time = NULL) { $time = intval($time) ? $time : time(); return date('W', $time); } // 当前几月 没有前导零1-12 function date_n($time = NULL) { $time = intval($time) ? $time : time(); return date('n', $time); } // 当前月的天数 function date_t($time = NULL) { $time = intval($time) ? $time : time(); return date('t', $time); } // 0 o'clock on the day function clock_zero() { return strtotime(date('Ymd')); } // 24 o'clock on the day function clock_twenty_four() { return strtotime(date('Ymd')) + 86400; } // 8点过期 / expired at 8 a.m. function eight_expired($time = NULL) { $time = intval($time) ? $time : time(); // 当前时间大于8点则改为第二天8点过期 $life = date('G') <= 8 ? (strtotime(date('Ymd')) + 28800 - $time) : clock_twenty_four() - $time + 28800; return $life; } // 24点过期 / expired at 24 a.m. function twenty_four_expired($time = NULL) { $time = intval($time) ? $time : time(); $twenty_four = clock_twenty_four(); $life = $twenty_four - $time; return $life; } /** * @param $url 提交地址 * @param string $post POST数组 / 空为GET获取数据 / $post='GET'获取连续跳转最终URL * @param string $cookie cookie * @param int $timeout 超时 * @param int $ms 设为1是毫秒 * @return mixed 返回数据 */ function https_request($url, $post = '', $cookie = '', $timeout = 30, $ms = 0) { if (empty($url)) return FALSE; if (version_compare(PHP_VERSION, '5.2.3', '<')) { $ms = 0; $timeout = 30; } is_array($post) and $post = http_build_query($post); // 没有安装curl 使用http的形式,支持post if (!extension_loaded('curl')) { //throw new Exception('server not install CURL'); if ($post) { return https_post($url, $post, $cookie, $timeout); } else { return http_get($url, $cookie, $timeout); } } is_array($cookie) and $cookie = http_build_query($cookie); $curl = curl_init(); // 返回执行结果,不输出 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); //php5.5跟php5.6中的CURLOPT_SAFE_UPLOAD的默认值不同 if (class_exists('\CURLFile')) { curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true); } else { defined('CURLOPT_SAFE_UPLOAD') and curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false); } // 设定请求的RUL curl_setopt($curl, CURLOPT_URL, $url); // 设定返回信息中包含响应信息头 if (ini_get('safe_mode') && ini_get('open_basedir')) { // $post参数必须为GET if ('GET' == $post) { // 安全模式时将头文件的信息作为数据流输出 curl_setopt($curl, CURLOPT_HEADER, true); // 安全模式采用连续抓取 curl_setopt($curl, CURLOPT_NOBODY, true); } } else { curl_setopt($curl, CURLOPT_HEADER, false); // 允许跳转10次 curl_setopt($curl, CURLOPT_MAXREDIRS, 10); // 使用自动跳转,返回最后的Location curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); } $ua1 = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'; $ua = empty($_SERVER["HTTP_USER_AGENT"]) ? $ua1 : $_SERVER["HTTP_USER_AGENT"]; curl_setopt($curl, CURLOPT_USERAGENT, $ua); // 兼容HTTPS if (FALSE !== stripos($url, 'https://')) { curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); //ssl版本控制 //curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_setopt($curl, CURLOPT_SSLVERSION, true); } $header = array('Content-type: application/x-www-form-urlencoded;charset=UTF-8', 'X-Requested-With: XMLHttpRequest'); $cookie and $header[] = "Cookie: $cookie"; curl_setopt($curl, CURLOPT_HTTPHEADER, $header); if ($post) { // POST curl_setopt($curl, CURLOPT_POST, true); // 自动设置Referer curl_setopt($curl, CURLOPT_AUTOREFERER, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $post); } if ($ms) { curl_setopt($curl, CURLOPT_NOSIGNAL, true); // 设置毫秒超时 curl_setopt($curl, CURLOPT_TIMEOUT_MS, intval($timeout)); // 超时毫秒 } else { curl_setopt($curl, CURLOPT_TIMEOUT, intval($timeout)); // 秒超时 } //优先解析 IPv6 超时后IPv4 //curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_setopt($curl, CURLOPT_ENCODING, 'gzip'); // 返回执行结果 $output = curl_exec($curl); // 有效URL,输出URL非URL页面内容 CURLOPT_RETURNTRANSFER 必须为false 'GET' == $post and $output = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL); curl_close($curl); return $output; } function save_image($img) { $ch = curl_init(); // 设定请求的RUL curl_setopt($ch, CURLOPT_URL, $img); // 设定返回信息中包含响应信息头 启用时会将头文件的信息作为数据流输出 //curl_setopt($ch, CURLOPT_HEADER, false); //curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER["HTTP_USER_AGENT"]); // true表示$html,false表示echo $html curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); //curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); $output = curl_exec($ch); curl_close($ch); return $output; } // 计算字串宽度:剧中对齐(字体大小/字串内容/字体链接/背景宽度/倍数) function calculate_str_width($size, $str, $font, $width, $multiple = 2) { $box = imagettfbbox($size, 0, $font, $str); return ($width - $box[4] - $box[6]) / $multiple; } // 搜索目录下的文件 比对文件后缀 function search_directory($path) { if (is_dir($path)) { $paths = scandir($path); foreach ($paths as $val) { $sub_path = $path . '/' . $val; if ('.' == $val || '..' == $val) { continue; } else if (is_dir($sub_path)) { //echo '目录名:' . $val . '
'; search_directory($sub_path); } else { //echo ' 最底层文件: ' . $path . '/' . $val . '
'; $ext = strtolower(file_ext($sub_path)); if (in_array($ext, array('php', 'asp', 'jsp', 'cgi', 'exe', 'dll'), TRUE)) { echo '异常文件:' . $sub_path . '
'; } } } } } // 一维数组转字符串 $sign待签名字符串 $url为urlencode转码GET参数字符串 function array_to_string($arr, &$sign = '', &$url = '') { if (count($arr) != count($arr, 1)) throw new Exception('Does not support multi-dimensional array to string'); // 注销签名 unset($arr['sign']); // 排序 ksort($arr); reset($arr); // 转字符串做签名 $url = ''; $sign = ''; foreach ($arr as $key => $val) { if (empty($val) || is_array($val)) continue; $url .= $key . '=' . urlencode($val) . '&'; $sign .= $key . '=' . $val . '&'; } $url = substr($url, 0, -1); $url = htmlspecialchars($url); $sign = substr($sign, 0, -1); } // 私钥生成签名 function rsa_create_sign($data, $key, $sign_type = 'RSA') { if (!function_exists('openssl_sign')) throw new Exception('OpenSSL extension is not enabled'); if (!defined('OPENSSL_ALGO_SHA256')) throw new Exception('Only versions above PHP 5.4.8 support SHA256'); $key = wordwrap($key, 64, "\n", true); if (FALSE === $key) throw new Exception('Private Key Error'); $key = "-----BEGIN RSA PRIVATE KEY-----\n$key\n-----END RSA PRIVATE KEY-----"; if ('RSA2' == $sign_type) { openssl_sign($data, $sign, $key, OPENSSL_ALGO_SHA256); } else { openssl_sign($data, $sign, $key, OPENSSL_ALGO_SHA1); } // 加密 return base64_encode($sign); } // 公钥验证签名 function rsa_verify_sign($data, $sign, $key, $sign_type = 'RSA') { $key = wordwrap($key, 64, "\n", true); if (FALSE === $key) throw new Exception('Public Key Error'); $key = "-----BEGIN PUBLIC KEY-----\n$key\n-----END PUBLIC KEY-----"; // 签名正确返回1 签名不正确返回0 错误-1 if ('RSA2' == $sign_type) { $result = openssl_verify($data, base64_decode($sign), $key, OPENSSL_ALGO_SHA256); } else { $result = openssl_verify($data, base64_decode($sign), $key, OPENSSL_ALGO_SHA1); } return $result === 1; } // Array to xml array('appid' => 'appid', 'code' => 'success') function array_to_xml($arr) { if (!is_array($arr) || empty($arr)) throw new Exception('Array Error'); $xml = ""; foreach ($arr as $key => $val) { if (is_numeric($val)) { $xml .= "<" . $key . ">" . $val . ""; } else { $xml .= "<" . $key . ">"; } } $xml .= ""; return $xml; } // Xml to array function xml_to_array($xml) { if (!$xml) throw new Exception('XML error'); $old = libxml_disable_entity_loader(true); // xml解析 $result = (array)simplexml_load_string($xml, null, LIBXML_NOCDATA | LIBXML_COMPACT); // 恢复旧值 if (FALSE === $old) libxml_disable_entity_loader(false); return $result; } // 逐行读取 function well_import($file) { if ($handle = fopen($file, 'r')) { while (!feof($handle)) { yield trim(fgets($handle)); } fclose($handle); } } // 计算总行数 function well_import_total($file, $key = 'well_import_total') { static $cache = array(); if (isset($cache[$key])) return $cache[$key]; $count = cache_get($key); if (NULL === $count) { $count = 0; $globs = well_import($file); while ($globs->valid()) { ++$count; $globs->next(); // 指向下一个 } $count and cache_set($key, $count, 300); } return $cache[$key] = $count; } $g_dir_file = FALSE; function well_search_dir($path) { global $g_dir_file; FALSE === $g_dir_file and $g_dir_file = array(); if (is_dir($path)) { $paths = scandir($path); foreach ($paths as $val) { $sub_path = $path . '/' . $val; if ('.' == $val || '..' == $val) { continue; } else if (is_dir($sub_path)) { well_search_dir($sub_path); } else { $g_dir_file[] = $sub_path; } } } return $g_dir_file; } ?>javascript - Firebase Cloud Function to resize image on firestore create - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Firebase Cloud Function to resize image on firestore create - Stack Overflow

programmeradmin3浏览0评论

I am trying to achieve following. But, I have no idea as I am a beginner to firebase.

  1. User is trying to upload a post with image
  2. Image is selected from web browser
  3. When user clicks save button, I am uploading the selected image to firbase storage and getting the download URL.
  4. Inserting the post data with download url to firestore database.

Till this, I have pleted. Now, I need to resize the uploaded image.

For that, I am trying to use Cloud Functions, whenever a new entry is added to firestore database, I am calling a Cloud fountion, which can access the download URL of the image, using this download URL, I need to resize image. Please help.

Please let me know, if there are having any better approach to achieve this. (I know there should be :P )

Edit 1

Thank you Frank for your reply.

I have the below cloud function, which will be called for every post is inserted. I am getting the download URL of the image from the eventSnapshot. I need to resize the image in that location. Please help.

exports.resizeImage = functions.firestore
.document('posts/{postId}')
.onCreate(event => {
        var eventSnapshot = event.data.data();
        //In this eventSnapshot I am getting the document, and I can get the download URL from the document
});

I have analyzed the example to create thumbnail, but for that, I need the
storage object, and it will be called only when the storage object is changed. But, I need to do the thumbnail creation when the onWrite called in firestore.

 exports.generateThumbnail = functions.storage.object().onChange((event) => {
  // File and directory paths.
  const filePath = event.data.name;
});

Please let me know, how to do the image resize operation, by detecting the onWrite in firestore and using downLoadURL.

I am trying to achieve following. But, I have no idea as I am a beginner to firebase.

  1. User is trying to upload a post with image
  2. Image is selected from web browser
  3. When user clicks save button, I am uploading the selected image to firbase storage and getting the download URL.
  4. Inserting the post data with download url to firestore database.

Till this, I have pleted. Now, I need to resize the uploaded image.

For that, I am trying to use Cloud Functions, whenever a new entry is added to firestore database, I am calling a Cloud fountion, which can access the download URL of the image, using this download URL, I need to resize image. Please help.

Please let me know, if there are having any better approach to achieve this. (I know there should be :P )

Edit 1

Thank you Frank for your reply.

I have the below cloud function, which will be called for every post is inserted. I am getting the download URL of the image from the eventSnapshot. I need to resize the image in that location. Please help.

exports.resizeImage = functions.firestore
.document('posts/{postId}')
.onCreate(event => {
        var eventSnapshot = event.data.data();
        //In this eventSnapshot I am getting the document, and I can get the download URL from the document
});

I have analyzed the example to create thumbnail, but for that, I need the
storage object, and it will be called only when the storage object is changed. But, I need to do the thumbnail creation when the onWrite called in firestore.

 exports.generateThumbnail = functions.storage.object().onChange((event) => {
  // File and directory paths.
  const filePath = event.data.name;
});

Please let me know, how to do the image resize operation, by detecting the onWrite in firestore and using downLoadURL.

Share Improve this question edited Mar 30, 2018 at 15:26 Frank van Puffelen 600k85 gold badges890 silver badges860 bronze badges asked Mar 30, 2018 at 13:14 JohnJohn 3021 gold badge5 silver badges18 bronze badges 4
  • 1 It sounds like you're well on your way to building an app, but are having problems with a specific step (resizing of an image). In that case, it's best to focus your question to only that specific problem, show what you've tried. The best way to do this is by creating a minimal, plete, verifiable example, that reproduces the problem without us having to know the rest of your app. If you're struggling on how to get started with resizing the image, have a look at this sample: github./firebase/functions-samples/tree/master/… – Frank van Puffelen Commented Mar 30, 2018 at 14:16
  • 1 @FrankvanPuffelen Thank you very much for your ment, I have edited the question. Please help. Thank you in advance. – John Commented Mar 30, 2018 at 15:20
  • @FrankvanPuffelen Your suggestion please.... – John Commented Mar 31, 2018 at 11:14
  • Did you ever find a solution that works? I'm using FirebaseDatabase instead of Firestore, but encountering the same issue. I have successfully generated a thumbnail, but getting the download URL stored inside my user data has proved to be a head scratcher. – Eric Duffett Commented May 21, 2019 at 15:00
Add a ment  | 

4 Answers 4

Reset to default 3

I, too, have created a document in firestore that I'm using as the backend to a website. I, too, would like to resize the image (to fit on a card) and write the URL back to firestore. I found a solution that uses a different pattern from the standard examples that are triggered by uploading the image to storage.

Basically, I upload the image to storage and then write the URL into Firestore within my app page. I then trigger the function with Firestore's onCreate() trigger.

The function grabs 'image_name' from firestore and uses that to get the file reference in storage. Next, it follows the patterns of the generate-thumbnail firebase example.

The trick was then grabbing the signedUrl and writing it back to firestore in img_src.

In case anyone else finds this useful:

const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')({keyFilename: 'service-key.json'});
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

exports.createCard = functions.firestore
  .document('work_cards/{cardID}')
  .onCreate((snap, context) => {
    const newCardData = snap.data()
    const bucket = gcs.bucket('your-project-id.appspot.')
    const file = bucket.file(newCardData.image_name)
    const tempFilePath = path.join(os.tmpdir(), file.name);
    const thumbFileName = `thumb_${file.name}`;
    const thumbFilePath = bucket.file(thumbFileName)
    const contentType = file.contentType;
    const metadata = {
      contentType: contentType
    };

    return bucket.file(file.name).download({
        destination: tempFilePath,
      })
      .then(() => {
        return spawn('convert', [tempFilePath, '-thumbnail', '250x250', tempFilePath]);
      })
      .then(() => {
        return bucket.upload(tempFilePath, {
          destination: thumbFilePath,
          metadata: metadata,
        })
      })
      .then(() => {
        return thumbFilePath.getSignedUrl({
        action: 'read',
        expires: '03-09-2491'
        })
      })
      .then(signedUrls => {
        const img_src = signedUrls[0]
        return snap.ref.set({img_src}, {merge: true});
      })
      .then(() => {
        bucket.file(file.name).delete()
        fs.unlinkSync(tempFilePath)
        return
      })
    });

Rather than take the URL from Cloud Firestore, you can have Cloud Storage trigger the Cloud Function to resize the image. There is a great example of how to do this, on GitHub.

Firebase SDK for Cloud Functions Quickstart - Cloud Storage trigger

I needed to achieve this too, but for me, using the Cloud Storage trigger wasn't a suitable solution as I didn't want to resize everything.

My scenario was that a user would upload a number of images, but they picked one as the thumbnail. I modified Birch's code as a callable function, where the file reference data was passed to it

exports.generateThumbnail = functions.https.onCall((data, context) => {
  const file = bucket.file(`/designs/${context.auth.uid}/${data.design}/${data.image}`)
  const tempFilePath = path.join(os.tmpdir(), `${data.image}`);
  const thumbFileName = `thumb_${data.image}`;
  const thumbFilePath = bucket.file(`/designs/${context.auth.uid}/${data.design}/${thumbFileName}`);

  return bucket.file(file.name).download({
       destination: tempFilePath,
     })
     .then(() => {
       return spawn('convert', [tempFilePath, '-trim','-resize', '190', tempFilePath]);
     })
     .then(() => {
       return bucket.upload(tempFilePath, {
         destination: thumbFilePath,
       })
     })
     .then(() => {
       fs.unlinkSync(tempFilePath)
       return
     })
})

I made it by generating and setting thumbnail when our user create or update firestore object.

resizeImage.ts

import * as admin from "firebase-admin";
const mkdirp = require("mkdirp-promise");
import { spawn } from "child-process-promise";
import * as path from "path";
import * as os from "os";
import * as fs from "fs";

export default async function resizeImage(
    filePath: string,
    size: string
): Promise<string> {
    // File and directory paths.
    const fileDir = path.dirname(filePath);
    const fileName = path.basename(filePath);
    const thumbFilePath = path.normalize(
        path.join(fileDir, `thumb_${size}_${fileName}`)
    );
    const tempLocalFile = path.join(os.tmpdir(), filePath);
    const tempLocalDir = path.dirname(tempLocalFile);
    const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);

    // Cloud Storage files.
    const bucket = admin.storage().bucket();
    const file = bucket.file(filePath);
    const thumbFile = bucket.file(thumbFilePath);
    const metadata = {
        contentType: null
        // To enable Client-side caching you can set the Cache-Control headers here. Unment below.
        // 'Cache-Control': 'public,max-age=3600',
    };
    await file.getMetadata().then(data => {
        if (data && data[0] && data[0]["contentType"]) {
            metadata["contentType"] = data[0]["contentType"];
        }
    });

    // Create the temp directory where the storage file will be downloaded.
    await mkdirp(tempLocalDir);
    // Download file from bucket.
    await file.download({ destination: tempLocalFile });
    console.log("The file has been downloaded to", tempLocalFile);
    // Generate a thumbnail using ImageMagick.
    await spawn(
        "convert",
        [
            tempLocalFile,
            "-auto-orient",
            "-thumbnail",
            `${size}>`,
            tempLocalThumbFile
        ],
        { capture: ["stdout", "stderr"] }
    );
    console.log("Thumbnail created at", tempLocalThumbFile);
    // Uploading the Thumbnail.
    await bucket.upload(tempLocalThumbFile, {
        destination: thumbFilePath,
        metadata: metadata
    });
    console.log("Thumbnail uploaded to Storage at", thumbFilePath);
    // Once the image has been uploaded delete the local files to free up disk space.
    fs.unlinkSync(tempLocalFile);
    fs.unlinkSync(tempLocalThumbFile);
    return thumbFile
        .getSignedUrl({
            action: "read",
            expires: "03-01-2500"
        })
        .then((urls: string[]) => urls[0]);
}

resizeAvatar.ts

const functions = require("firebase-functions");
import { Change } from "firebase-functions";
import resizeImage from "./resizeImage";

async function resizeAvatar(snapshot: FirebaseFirestore.DocumentSnapshot) {
    const data = snapshot.data();
    const filePath = data && data.avatarPath;
    if (!data || !filePath || data.avatarUrlSmall) {
        return; // No avatar or already resized
    }
    const url = await resizeImage(filePath, "200x200");
    await snapshot.ref.set({ avatarUrlSmall: url }, { merge: true });
}

exports.resizeAvatarOnCreate = functions.firestore
    .document("users/{userID}")
    .onCreate(async (snapshot: FirebaseFirestore.DocumentSnapshot) => {
        await resizeAvatar(snapshot);
    });

exports.resizeAvatarOnUpdate = functions.firestore
    .document("users/{userID}")
    .onUpdate(async (change: Change<FirebaseFirestore.DocumentSnapshot>) => {
        await resizeAvatar(change.after);
    });
发布评论

评论列表(0)

  1. 暂无评论