본문으로 건너뛰기

Full Stack JavaScript Developer | Half-time Open Sourcerer.

View All Authors

Javascript로 로컬에 이미지 다운로드

· 약 4분

버튼을 눌러 이미지를 다운로드 받고 싶다면 어떻게 해야될까? Client Side 에서 할 수 있는 가장 쉬운 방법은 download attribute를 사용하는 것이다. 하지만 예상했듯이 이 속성은 IE 에서 지원하지 않는다.

For IE

base64

먼저 이미지를 base64 인코딩해야한다. FileReader 또는 Canvas 를 이용해 변환할 수 있는데 stackoverflow 의 명쾌한 답변을 참조하자. jQuery 환경이라면 Reading binary data using jquery ajax를 참조해도 된다.

base64encode 가 된 이미지 데이터가 뽑아지면 시작할 수 있다.

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2CAAAAADAeSUUAAADN0lEQVR42u3aQY7CMBAEQP7/afaKtEu2exwk4lROKITEZSQGT/vxiI/ny/H7zOv513ffXZl89viad6M6+cDGxsa+CDsZUP5uMqx3d8gntB3nH1ODjY2NvR373S/88TUtMuG1E5qMExsbGxv7eChJUTl+4nP5wMbGxsZu2UlbJy9RyQS1SxpsbGzsu7FXCkPeTkoihGTQeUPqhF4aNjY29tez81T0+19/JN/GxsbG/mL2rHEzi2OTxc968BwpsLGxsTdiz0Lc/I9+voBprzwhhMbGxsbeiN1S2xvNWkuzZtD6aLGxsbGvxW4f0BaqtpU/C4/bhRA2Njb2TuwkTF0ZVn4+/+zKJEb7lbCxsbG3YM9aRe0CJo8NkivzFhU2Njb2ruwW3/71r0vL6FnDXUvY2NjYl2XPAto8mm0LUrIImcUG2NjY2Luy1xv6eTCwMomzAlZPEzY2NvbF2ceDWIld82XJSjjRbsfExsbG3om9EgbkDak2GM5L6bApho2Njb0F+/imeclJWj/t61nwEBU2bGxs7I3Yn2vifKLN1MKKxQk2Njb2ZdlnFYzZ9bMG00rbCxsbG/sO7Lw13261zIvlMXVW5B7tDGFjY2NvwZ4lpDmpLYenXYmNjY29ETv5u5+XkDYYaFtL7ZKm2KmEjY2NfVl2u10mWYS009q2hNoC9scZbGxs7I3YM+SsjJ3V0lqZ3MfKd4uNjY39lexk6Hlkm4fHs40+7dacomhhY2Njb8TOi1MeCZw7oflER1t2sLGxsS/Onq1d2hC3XYq0japZCIGNjY29K7u9Xds8WmlU5SWwiH6xsbGxt2DnP/dthNBS12FFScPGxsbelN02aNrFRh4tzJ5SbO7BxsbGvgE7Aa8EACvlc6X9hI2Njb0T+1keySBmm3jy0Le92z9JCDY2NvbF2W0BOLfwHJ9vW0v1UgQbGxt7I3ZStFbKTLKMab+TZFH0T+SAjY2NvR07b7vP4ti2TK5MSvRcbGxs7Nuz2wfnT1nZalncBxsbG/vG7PWtlmdt5VlpimFjY2Pvx06aRHlBarfs5O3+9ut5u/rAxsbG3og9W1TkxWYWP7T3zBtV2NjY2BuxfwBOAYaS/PUQNQAAAABJRU5ErkJggg==

blob

이제 이미지 데이터를 Blob Object 로 변환해야한다.

// imageSrc는 위의 이미지 데이터이다.
// 실제 데이터는 iVBO...부터이므로 split한다.
const imgData = atob(imageSrc.split(",")[1]);
const len = imgData.length;
const buf = new ArrayBuffer(len); // 비트를 담을 버퍼를 만든다.
const view = new Uint8Array(buf); // 버퍼를 8bit Unsigned Int로 담는다.
let blob, i;

for (i = 0; i < len; i++) {
view[i] = imgData.charCodeAt(i) & 0xff; // 비트 마스킹을 통해 msb를 보호한다.
}
// Blob 객체를 image/png 타입으로 생성한다. (application/octet-stream도 가능)
blob = new Blob([view], { type: "image/png" });

msSaveOrOpenBlob

IE10+ 에서 사용가능한 msSaveOrOpenBlob가 필요하다.

msSaveBlob 메서드는 저장 단추만 사용자에게 제공하는 반면 msSaveOrOpenBlob 메소드는 저장 및 열기 단추를 모두 제공한다는 것이 차이점이다.

// blob과 저장될 파일명을 받는다.
window.navigator.msSaveOrOpenBlob(blob, "new_file_name.png");

Not IE

IE 가 세상에 존재하지 않는다면 코드는 아주 예쁘게 짤 수 있다.

<a href="data:image/png;base64,iVBORw0KG..." download="new_file_name.png">
<img src="data:image/png;base64,iVBORw0KG..." />
</a>

a 태그가 보기 싫다면 아래 구문을 포함해 함수로 만든다.

const a = document.createElement("a");
a.style = "display: none";
a.href = img.src;
a.download = "new_file_name.png";

document.body.appendChild(a);
a.click();

setTimeout(function () {
// 다운로드가 안되는 경우 방지
document.body.removeChild(a);
}, 100);

Blob 재사용

IE 때문에 만들었던 Blob 객체를 URL 기능을 이용해 재사용해보자.

const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.style = "display: none";
a.href = url;
a.download = "new_file_name.png";

document.body.appendChild(a);
a.click();

setTimeout(function () {
document.body.removeChild(a);
URL.revokeObjectURL(url); // 메모리 해제
}, 100);

소스

/**
* [downloadImage]
* @param {[string]} img [base64encoded image data]
* @param {[string]} fileName [new file name]
* @return [image file]
*/
function downloadImage(img, fileName) {
let imgData = atob(img.src.split(",")[1]),
len = imgData.length,
buf = new ArrayBuffer(len),
view = new Uint8Array(buf),
blob,
i;

for (i = 0; i < len; i++) {
view[i] = imgData.charCodeAt(i) & 0xff; // masking
}

blob = new Blob([view], {
type: "application/octet-stream",
});

if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
//var url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.style = "display: none";
//a.href = url;
a.href = img.src;
a.download = fileName;
document.body.appendChild(a);
a.click();

setTimeout(function () {
document.body.removeChild(a);
//URL.revokeObjectURL(url);
}, 100);
}
}

여담

image from hexo

XML-RPC를 활용한 네이버 블로그 글쓰기 API

· 약 2분

OAuth 를 이용한 블로그 API 가 있는데, 네이버 블로그 글쓰기는 그보다 더 간단히 구현할 수 있다.

XML-RPC for PHP 다운로드

XML-RPC에서 다운받는다. image from hexo

압출을 푼 뒤 lib/xmlrpc.inc 파일을 로직을 만들 곳에 복사해 놓는다.

네이버 블로그 플러그인 설정

관리 > 글쓰기 API 설정 메뉴로 들어간다. image from hexo

사용하기로 설정을 바꾼 후 비밀번호를 기억하고, 어디에 등록할지 카테고리를 정한다. image from hexo

API 연동

<?php

include_once "xmlrpc.inc";

$title = $_POST['title'];
$content = $_POST['content'];
$result = newPost($title, $content);

echo json_encode($result);
// 블로그 API 함수
function newPost($title, $description) {
$g_blog_url = "https://api.blog.naver.com/xmlrpc";
$user_id = "아이디";
$blogid = "아이디";
$password = "발급받은 비밀번호";
$publish = true;
$client = new xmlrpc_client($g_blog_url);
$client->setSSLVerifyPeer(false);

$GLOBALS['xmlrpc_internalencoding'] = 'UTF-8';

$struct = [
'title' => new xmlrpcval($title, "string"),
'description' => new xmlrpcval($description, "string")
];

$f = new xmlrpcmsg("metaWeblog.newPost",
[
new xmlrpcval($blogid, "string"),
new xmlrpcval($user_id, "string"),
new xmlrpcval($password, "string"),
new xmlrpcval($struct , "struct"),
new xmlrpcval($publish, "boolean")
]
);

$f->request_charset_encoding = 'UTF-8';
return $response = $client->send($f);
}
?>

네이버 블로그는 html 태그가 먹으므로 escape 처리를 할 필요는 없다.

RESTful을 위한 PHP HTTP Method 처리

· 약 1분

메소드를 분기해서 새로운 배열에 담아주면 된다.

소스

contentType을 application/json으로 보냈을 경우

<?
$method = strtolower($_SERVER['REQUEST_METHOD']);
switch ($method) {
case 'get':
$input = json_decode(json_encode($_GET), true);
break;
case 'post':
$input = json_decode(file_get_contents('php://input'), true);
break;
case 'put':
$input = json_decode(file_get_contents('php://input'), true);
break;
case 'delete':
$input = json_decode(file_get_contents('php://input'), true);
break;
}
?>

contentType을 그냥 전송한다면 **file_get_contents('php://input')**으로 받으면 된다.

여담

GET을 제외한 method는 params를 JSON.stringify한 뒤에 file_get_contents로 읽어오면 되는데, GET으로는 file전송을 할 수 없기 때문에 위처럼 받으면 된다.

레이 커즈와일이 예측하는 기술발전 시나리오

· 약 4분

급진적 미래학자인 레이 커즈와일이 How to create your mind에서 쓴 내용을 정리해봤다.

2010 년대

  • 망막에 이미지를 직접 조사하는 안경 형태의 디스플레이가 상용화
  • 인간의 뇌 용량과 거의 비슷한 10TB 의 컴퓨터가 100 만원대에 출시

2020 년대

  • 혈관 속에 투여하여 24 시간 인간의 몸 속 변화를 감시하는 나노봇이 상용화
  • 튜링테스트를 통과하는 컴퓨터의 등장
  • 자동차는 모두 자율주행차로 바뀜, 고속도로는 자율주행차의 통행만 가능

2030 년대

  • 가상현실 구현 기술이 발전해 실제와 구분할 수 없음
  • 마음과 의식을 컴퓨터에 백업할 수 있음

2040 년대

  • 인공지능이 인간의 지능보다 10 억배 뛰어난 성능을 발휘
  • 분자 단위로 물질을 조립할 수 있는 기술이 개발되어, 어떠한 물질이든 창조가능
  • 인간의 뇌와 클라우드 인공지능을 무선으로 연결하게되며, 인간의 지능은 10 억배 증가

인간

2030 년대부터 뇌의 알고리즘이 컴퓨터로 구현이 완료된다면, 인간에 대한 정의가 달라질 수 있다.

의식은 뇌에 있다. 뇌의 모든 알고리즘을 옮겨 기계 뇌를 만들었다.

  • 기계는 의식이 있는 것인가?
  • 기계는 살아 있는 것인가?
  • 기계는 인간인가?
  • 의식은 뇌에서 나오니 의식이 있다고 할 수 있다.
  • 의식은 살아 있는 것에서부터 나오니 살아있다고 할 수 있다.
  • ???

복제

의 뇌를 스캔해서 의식이 복제된 기계인 나 2가 있다. 나 2는 마치 나처럼 내 삶에 대해 이야기하고 심지어 "새로운 몸이 참 마음에 드는군"이라며 너스레를 떤다.

나 2라고 할 수 있을까?

나 2는 겉보기엔 와 똑같지만 는 여기 존재하니 아니다.

는 뇌를 부분부분 기계로 바꾸는 수술을 진행하고 있다. 수술은 성공적이여서 수술을 할수록 의 신체 기능은 진화하고 있다. 수술이 계속되어 완전한 기계뇌를 가진 내가 되었다.

는 위의 나 2와 똑같은 기계가 된 것이다.

결국 나 2는 또다른 이다. 내가 둘이 된 것이다.

550 : smtp auth address is not same to envfrom address (#5.5.0)

· 약 1분

550 : smtp auth address is not same to envfrom address

stmp 로 메일 발송시 아래와 같은 오류가 발생하는 경우가 있다.

550 : smtp auth address is not same to envfrom address (#5.5.0)
The following From address failed: [email protected] : MAIL FROM command failed, smtp auth address is not same to envfrom address (#5.5.0)

해결

smtp 인증 username 과 보내는 메일주소가 같지 않아서 발생한다. username 과 from email 을 일치시켜주면 해결된다.

로컬 웹서버 돌리기 - 5. CURL 설정

· 약 1분

4. OpenSSL 설정에서 이어집니다.

리눅스에서는 Curl 모듈을 확장만 하면 사용이 가능하지만 윈도우 로컬 서버에서는 사용이 되지 않는다. 해결해보자.

모듈 확장

php.ini에서 php_curl 모듈의 주석을 해제한다. image from hexo

dll 복사

총 4 개의 dll 파일을 C:\Windows\system32 폴더로 복사해야한다.

  • php7\ libeay32.dll
  • php7\ libssh2.dll
  • php7\ ssleay32.dll
  • php7\ext\ php_curl.dll

image from hexo

이제 php curl command 를 사용할 수 있다.

로컬 웹서버 돌리기 - 4. HTTPS OpenSSL 설정

· 약 3분

3. Virtual Host 설정에서 이어집니다. 로컬에서 HTTPS 통신으로 프로젝트에 접근하시고 싶지 않으시다면 3 장으로 웹서버 구동은 완료됩니다.

Apache SSL 사용 설정

모듈 활성화

Apache24\conf\httpd.conf에서 ssl_module 과 socache_shmcb_module 의 주석을 해제한다. image from hexo

설정 활성화

Include conf/extra/httpd-ssl.conf의 주석을 해제한다. image from hexo

SSL 설정 변경

디렉토리 생성

Apache24\conf 경로에서 ssl폴더를 만든 뒤 conf/openssl.cnf 파일을 ssl 폴더로 복사한다.

키 생성

ssl 폴더로 들어와 cmd 창을 연 뒤 키를 생성한다.

openssl genrsa -out domain.key 1024
openssl req -new -config openssl.cnf -days 365 -key domain.key -out domain.csr

위 명령어를 입력하면 입력 폼 형식이 나오는데, 주제에 맞게 입력하면 된다. (KR, Seoul 등)

생성된 domain.key, domain.csr 파일을 확인한 뒤 아래 명령어를 입력한다.

openssl x509 -in domain.csr -out domain.crt -req -signkey domain.key -days 365

완성된 파일 구조의 형태는 다음과 같아야한다. image from hexo

SSL 연동

httpd-ssl.conf를 열어 키 파일을 연동해준다. image from hexo 그 밖에 다른 경로로 연결된 설정이 있다면 바로 잡아주면 된다.

HTTPS 접속

Apache restart 후 접속해보자. image from hexo

여담

오류 발생시

오류가 발생할 경우 Apache24\logs\error.log 파일을 확인해가며 진행하면 된다.

Virtual Host 설정

Virtual Host 에 직접 key 파일을 지정할 수도 있다.

<VirtualHost *:443>
SSLEngine on
SSLCertificateFile "d:/Apache24/conf/ssl/domain.crt"
SSLCertificateKeyFile "d:/Apache24/conf/ssl/domain.key"

DocumentRoot "D:/workspace/test"
ServerName local.test.com
</VirtualHost>

👏👏👏 이로서 로컬 HTTPS 서버를 가지게 되었습니다. 다음 장에서는 서버 통신을 위해 CURL 설정을 해보겠습니다.

Windows10에서 hosts 파일 저장이 안될 때

· 약 2분

실컷 hosts 파일을 변경했는데 다시 들어가보니 원래대로거나, 권한이 없다고 아예 저장이 안 되는 경우가 있다.

해결

백신

백신에 따라 hosts 파일을 보호하기 때문에 수정을 제한될 수 있다. 잠시 백신을 사용안함 상태로 변경하자.

Windows10

Windows10 은 기본적으로 hosts 파일의 수정이 제한되어있다.

바탕화면 우클릭 > 새로만들기 > 바로가기를 실행한다. image from hexo

항목 위치 입력에 host 파일 경로를 입력해 바로가기를 만든다.

## 아래 내용을 항목 위치 입력에 넣어 바로가기 생성
C:\Windows\System32\notepad.exe C:\windows\system32\drivers\etc\hosts

image from hexo

관리자 권한으로 실행한다. image from hexo

이제 hosts 파일을 수정하면 된다.

로컬 웹서버 돌리기 - 3. Virtual Host 설정

· 약 2분

2. PHP 설치에서 이어집니다.

Apache와 PHP의 연동은 끝났지만 사용하고 싶은 프로젝트를 연동하는 작업을 해주어야 원하는 폴더를 웹으로 볼 수 있을 것이다.

Virtual Host 사용

httpd.conf를 열어 맨 아래쪽으로 내리면 있는 httpd-vhost.conf의 주석을 해제한다. image from hexo

디렉토리 접근 권한 변경

httpd.conf에서 모든 디렉토리 접근권한은 기본적으로 차단되어있기에 변경해야한다.

<Directory />
Options FollowSymLinks
AllowOverride none
Order allow,deny
Allow from all
</Directory>

image from hexo

Virtual Host 설정

./conf/extra/httpd-vhosts.conf 파일을 연다. 임시로 있는 VirtualHost를 지워주고 아래처럼 내가 사용할 프로젝트를 입력한다. image from hexo DocumentRoot에는 프로젝트 경로, ServerName은 URL로 접근할 경로를 적는다.

Host 파일 수정

C:\Windows\system32\drivers\etc\hosts 파일을 관리자 권한으로 열고 주소를 추가한다.

127.0.0.1 local.test.com

저장 불가일시

잠시 hosts 파일을 수정가능하게 손을 보고 다시 오자.

연동 확인

Apache restart 후에 확인한다. image from hexo

👏👏👏 이로서 기본 웹서버 설치는 마무리 됬습니다. 다음 장에서는 HTTPS 환경을 위해 OpenSSL 설정을 해보겠습니다.

로컬 웹서버 돌리기 - 2. PHP 설치

· 약 3분

1. Apache 설치에서 이어집니다.

PHP 다운로드

여기서 Apache 의 VC 버전에 맞는 Thread Safe 타입의 PHP 를 다운받으면 된다. image from hexo

압축을 풀고 Apache 와 같은 폴더에 php7 로 변경해 저장한다. (D:\php7) 폴더 안의 php.ini-developmentphp.ini로 변경한다.

모듈 활성화

사용할 모듈의 세미콜론을 지워주면 된다. image from hexo curl, mysqli, gettext, mbstring, openssl, pdomysql는 기본으로 지워주고, 나머진 나중에 지워도 된다.

설정 변경

php.ini 파일의 설정을 변경한다.

시간대 설정

date.timezone 을 추가한다. image from hexo

short_open_tag 설정

<?php<? 로도 사용할 수 있게 해주는 short_open_tag 옵션을 켠다. image from hexo

에러 리포팅 설정

에러 발생시 서버에 오류가 노출되기에 에러 노출 단계를 낮춰주자. image from hexo

error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_USER_DEPRECATED

모든오류 & not runtime notice & not deprecated & not user deprecated 의 상태이면 오류를 출력한다.

확장 모듈 경로 설정

C:\php에 php 설치를 하지 않았을 경우 확장 모듈 경로를 변경해줘야한다.

extension_dir = "D:\php7\ext"

Apache에 PHP 연동

httpd.conf 파일을 열고 아래 구문을 모두 추가한다.

## 인덱스 파일 설정
DirectoryIndex index.php index.html index.htm
## 모듈 연동 (php 설치 경로를 적는다)
LoadModule php7_module "D:/php7/php7apache2_4.dll"
## 핸들러 및 타입 연동
AddHandler application/x-httpd-php .php
AddType application/x-httpd-php .php .html
## PHP INI 경로 설정
PHPIniDir "D:/php7"

image from hexo

연동 확인

D:\Apache24\htdocs 경로의 index.html 파일을 index.php 로 변경 후 저장한다.

index.php
<?
phpinfo();
?>

image from hexo

여담

php5에서 php7로 오는 중 큰 변경점이 몇 가지 있다.

  1. 속도가 php5보다 2배 향상
  2. mysql 함수 사용 불가 (Mysqli로 대체)
  3. 기본값 연산자 사용 가능 (A ?? B ?? C 로 사용가능)

👏👏👏 다음 장에서는 실제 프로젝트를 웹서버에 돌리기 위한 Virtual Host 설정을 해보겠습니다.