2020-10-12

安裝 laravel 8 和 jetstream

安裝 laravel 8 和 jetstream

安裝 laravel 8 之前先更新 laravel/installer,應該要是 4.0 版以上:

composer global require laravel/installer

接著就可以建立專案,同時使用 --jet 安裝 jetstream:

laravel new project-name --jet

安裝時要選擇使用 livewire 或 inertia,我個人選了 inertia。 另一個問題是要不要使用 teams,測試專案所以選了否。 接著做 migrate:

php artisan migrate

在這裡遇到 1071 Specified key was too long 的問題。 建議使用 MySQL 5.7 以上,我用的是 5.5。在 AppServiceProvider.php 內設定 defaultStringLength 為 191 可以修正此問題。

use Illuminate\Support\Facades\Schema; public function boot() { Schema::defaultStringLength(191); }

啟動測試 Server:

php artisan serve

使用 php artisan route:list 查看路由時,可以看到設定的內容,但在 /routes/web.php 卻看不到相關的設定,要變更路由會是一大問題。 在這篇 laravel-8-jetstream-login-route 有提到設定方式,在 /config/fortify.php 內加入 path 的設定:

'path' => 'admin',

如此可以將 /login 變更成 /admin/login。

2020-07-03

前端的兩個狀況

同學:「老蘇對 localStorage 熟嗎?」
老蘇:「localStorage 有什麼好熟的?」
...
結果問題果然不是在 localStorage

- - - - - - - - - 

localStorage 是個輔助功能,當快取用很方便,而且資料不會因為刷頁面而消失。
但 localStorage 並不能取代 cookie 或 session 的功能。
許多安全性相關的資料不應該放在 localStorage。
不要為了方便而失去安全。

- - - - - - - - - 

另一個狀況是用 fetch() 發 AJAX
在某個 react component 裡,那個 AJAX 總是 pending 的狀態,要不到資料,但也不噴錯。
後端 API 確定是正常的。
後來學員自己發現,發 AJAX 後有一段落入的無窮迴圈,以至於 AJAX 一直無法處理完成。

2020-05-17

Raspbian 安裝 MariaDB

Raspbian 安裝 MariaDB

查看 Raspbian 提供支援 MariaDB 的版本:

pi@raspberrypi:~ $ apt-cache policy mariadb-server mariadb-server: 已安裝:(無) 候選: 1:10.3.22-0+deb10u1 版本列表: 1:10.3.22-0+deb10u1 500 500 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages

安裝:

sudo apt install mariadb-server

安裝完成後,使用下式連線:

sudo mysql -u root

如果有需要,建立外連的用戶:

-- 建立本地端可以連線的用戶 CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'newuser_pw'; GRANT ALL PRIVILEGES ON * . * TO 'newuser'@'localhost'; FLUSH PRIVILEGES; -- 建立其他主機可以連線的用戶 CREATE USER 'newuser2'@'%' IDENTIFIED BY 'newuser_pw2'; GRANT ALL PRIVILEGES ON * . * TO 'newuser2'@'%'; FLUSH PRIVILEGES;

從 mac 用 adminer.php(Apache/PHP 環境)連到 R-Pi,結果得到 connection refused,查看網路狀況:

sudo netstat -ln

得到:

# sudo netstat -ln Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN

爬文得知要設定 bind-address=0.0.0.0,到 /etc/mysql/my.cnf 設定結果無效。 後來才找到在 /etc/mysql/mariadb.conf.d/50-server.cnf 有設定 bind-address=127.0.0.1 ,變更之後,重新啟動:

sudo service mysqld restart

就可以由外部連入:

# sudo netstat -ln Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN

2020-05-16

在 Raspbian 安裝 MongoDB 的慘痛經驗 (廢文)

在 Raspbian 安裝 MongoDB 的慘痛經驗 (廢文)

由於 Raspberry Pi 4 model B 的 CPU ARMv7l 為 32 bit,所以只能安裝舊版的 MongoDB。若是網路架構,可以將 MongoDB 裝在別的主機或雲端,使用較新版本的 MongoDB。

在 Raspbian 中查看提供的 MongoDB 版本就好,不要安裝:

pi@raspberrypi:~ $ apt-cache policy mongodb mongodb: 已安裝:(無) 候選: 1:2.4.14-4 版本列表: 1:2.4.14-4 500 500 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages

只提供 2.4 的版本真的太老舊了,官方 drivers 都不支援了,真的別裝!

如果使用 MongoDB 3.2 以上是必要的那就請用 Ubuntu 20.04 LTS (64-bit),目前已經可以透過 Imager 安裝這個版本了。

以下是做個記錄,不要實作,在 Raspbian,MongoDB 3.2 和 3.0 32-bit 都無法執行,殘念。

支援 32-bit MongoDB 的最高版本 3.2.22,請參考這篇

可以透過瀏覽器到 MongoDB 官網下載中心 選取「Version 3.2.22」>「Linux 32-bit lagecy」>「TGZ」下載(拷備表單下的連結也可以)。

wget https://fastdl.mongodb.org/linux/mongodb-linux-i686-3.2.22.tgz # 下載 tar -zxvf mongodb-linux-i686-3.2.22.tgz # 解壓縮 sudo cp ./mongodb-linux-i686-3.2.22/bin/* /usr/bin/ # 複製檔案

設定啟動檔

wget https://raw.githubusercontent.com/mongodb/mongo/master/debian/init.d # 下載啟動檔 sudo mv init.d /etc/init.d/mongod # 移動檔案 sudo chmod 755 /etc/init.d/mongod # 變更屬性

建立設定檔 /etc/mongod.conf

storage: dbPath: /var/lib/mongo journal: enabled: true engine: mmapv1 systemLog: destination: file logAppend: true path: /var/log/mongodb/mongod.log processManagement: fork: true net: port: 27017 bindIp: 0.0.0.0

建立 mongodb 用戶

sudo useradd --home-dir /var/lib/mongo --shell /bin/false mongodb sudo passwd mongodb

建立存放資料的資料夾 /var/lib/mongo

# 存放資料庫資料 sudo mkdir /var/lib/mongo sudo chown -R mongodb /var/lib/mongo sudo chgrp -R mongodb /var/lib/mongo # 記錄檔 sudo mkdir /var/log/mongodb sudo chown -R mongodb /var/log/mongodb sudo chgrp -R mongodb /var/log/mongodb # pid sudo touch /var/run/mongod.pid sudo chown mongodb /var/run/mongod.pid sudo chgrp mongodb /var/run/mongod.pid

初始化服務:

sudo update-rc.d mongod defaults

最後重開機,然後還是不能執行。

Raspberry Pi 4 model B 安裝 Ubuntu 64-bit

Raspberry Pi 4 model B 安裝 Ubuntu 64-bit

Raspberry Pi 4 B 的 CPU 為 ARMv7l,是 32-bit 的 CPU,一般只會安裝 32-bit 的 OS。

但有些軟體已經不再支援 32-bit 的環境,此時使用 64-bit 變成一個基本需求。可喜的是 Ubuntu 官方已經提供 64-bit for Raspberry Pi 的 OS,不需要再到網路上找複雜的處理方式。

先到 Ubuntu 官網 下載 for Raspberry Pi 的 image 檔,現在可以選 Ubuntu 20.04 64-bit 的版本。雖然 R-Pi 官方的 Imager 裡已經有提供 Ubuntu 64-bit 的選項,但是還是建議先下載再使用 Imager,因為下載速度真的很慢。

接著再依照 How to install Ubuntu on your Raspberry Pi 安裝即可。

我個人是直接接實體網路線,所以 wifi 的設定都省了。

查看目前系統中可以安裝的 nodejs 和 mongodb 版本:

ubuntu@ubuntu:~$ apt-cache policy nodejs nodejs: Installed: (none) Candidate: 10.19.0~dfsg-3ubuntu1 Version table: 10.19.0~dfsg-3ubuntu1 500 500 http://ports.ubuntu.com/ubuntu-ports focal/universe arm64 Packages ubuntu@ubuntu:~$ apt-cache policy mongodb mongodb: Installed: (none) Candidate: 1:3.6.9+really3.6.8+90~g8e540c0b6d-0ubuntu5 Version table: 1:3.6.9+really3.6.8+90~g8e540c0b6d-0ubuntu5 500 500 http://ports.ubuntu.com/ubuntu-ports focal/universe arm64 Packages

如果沒有要太新的功能 nodejs 10 是可以接受的,安裝 nodejs 和 npm:

sudo apt install nodejs sudo apt install npm

也可以直接裝 MongoDB 3.6。若要安裝 MongoDB 4.2 可以參考這篇 Install Node.js and Npm on Raspberry Pi

2020-05-15

在 Raspbian 上安裝 VSCode

在 Raspbian 上安裝 VSCode

已經有人寫好 shell scripts 了 https://code.headmelted.com/

稍微改一下裡面的做法:

wget https://code.headmelted.com/installers/apt.sh # 下載 scripts chmod +x ./apt.sh # 加入「可執行」屬性 sudo ./apt.sh # 以管理者權限執行

裝好之後可以在圖形化介面的「啟動」>「Programming」>「Code-OSS (headmelted)」啟動 VSCode,也可以在 terminal 用 code-oss 去開啟一個文字檔。

2020-05-14

在 Raspbian 上安裝 Node.js

在 Raspbian 上安裝 Node.js

參考 Install Node.js and Npm on Raspberry Pi

先在 terminal 上查看 Raspberry Pi 的 CPU 型號:

uname -m

我的機器是 Pi 4 model B,CPU 是 ARMv7l。

Node.js 下載頁面 找到 Linux Binaries (ARM) 的版本,目前 LTS 12.16.3 版提供 ARMv7 和 ARMv8。若要找支援 ARMv6 就要找比較舊的版本。複製連結,並使用 wget 下載。

wget https://nodejs.org/dist/v12.16.3/node-v12.16.3-linux-armv7l.tar.xz

解壓縮檔案:

# tar -xvf 檔名.tar.xz tar -xvf ./node-v12.16.3-linux-armv7l.tar.xz

將檔案複製到 /usr/local/ 裡:

cd node-v12.16.3-linux-armv7l/ sudo cp -R * /usr/local/

最後查看版本,沒問題的話就完成安裝了:

node -v npm -v

這種安裝方式的缺點是,如果要移除 Node.js,由於沒有記錄複製的檔案,會無法移除所有檔案。

另一種安裝方式是使用 NodeSource Distributions,這個工具是由 NodeSource 這家公司所提供。

目前支援 Debian OS 的版本中,對 Raspberry Pi 支援的 CPU 只有 ARMv7 和 ARMv8,舊的 ARMv6 就不適合使用 NodeSource 的方案。以下是安裝的步驟:

先更新系統套件:

sudo apt-get update sudo apt-get dist-upgrade

NodeSource Distributions 查看支援 Debian 的版本,以下是安裝 12.x 的範例:

# Using Debian, as root curl -sL https://deb.nodesource.com/setup_12.x | bash - apt-get install -y nodejs

最後查看 Node 版本確認即可。

2020-05-13

透過 mac 安裝 Raspbian

透過 mac 安裝 Raspbian

首先到 Raspberry Pi 官網 下載 Raspberry Pi Imager for macOS,將 Raspberry Pi Imager.app 裝起來。

啟動 Imager 後,可以先格式化 SD 卡。

  1. Operating System 選 Erase
  2. SD Card 選讀卡設備
  3. 點選「Write」

安裝 Raspbian,也是同樣的步驟,不過下載檔案需要一些時間:

  1. Operating System 選「Raspbian」
  2. SD Card 選讀卡設備
  3. 點選「Write」

用我的老 mac mini 花了快一個小時... 後來發現是下載速度過慢的問題。 之後就可以裝 SD Card 試開機,一開始接比較舊的電視發現沒有畫面,換一般電腦螢幕就正常了。

一開始設定最重要的是開啟 SSH 和 VNC。有 SSH 才可以遠端登入 terminal,VNC 則是遠端桌面。 經常還是會發生設定上的問題,那可以用 ssh 登入:

ssh pi@192.168.1.108

輸入密碼後即可操作 Raspian 的 terminal。使用下式來設定:

sudo raspi-config

首頁畫面的 Interfacing Options 進入後可以啟動 SSH 和 VNC。 首頁畫面的 Advanced Options > Resolution,可以調整使用的解析度。有時 VNC 連線有狀況時,可以設定一個較小的模式,方便 VNC 呈現畫面。(CEA 模式比較接近電視,DMT 則是比較接近電腦螢幕)

2020-05-10

以 Flask / MongoDB 製作 通訊錄 CRUD

以 Flask / MongoDB 製作 通訊錄 CRUD

程式碼太多,請參考本文的專案 https://github.com/shinder/flask-practice,以下只列出部份程式碼:

主程式:

import modules.address_book app.add_url_rule('/address-book/list/', None, modules.address_book.ab_list) app.add_url_rule('/address-book/list/<int:page>', None, modules.address_book.ab_list) app.add_url_rule('/address-book/edit/<_id>', None, modules.address_book.ab_edit_get, methods=['GET']) app.add_url_rule('/address-book/edit', None, modules.address_book.ab_edit_post, methods=['POST']) app.add_url_rule('/address-book/add', None, modules.address_book.ab_add_get, methods=['GET']) app.add_url_rule('/address-book/add', None, modules.address_book.ab_add_post, methods=['POST']) app.add_url_rule('/address-book/delete/<_id>', None, modules.address_book.ab_delete)

app/modules/address_book.py 的內容:

from flask import Flask, request, render_template, session, jsonify, redirect from bson.objectid import ObjectId import json import math import re import modules.mongo_connection email_pattern = r"^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$" def ab_list(page=1): (db, connection) = modules.mongo_connection.getDB('test') output = { 'page_name': 'ab-list', 'page_title': '列表 - 通訊錄', 'totalRows': 0, # 總筆數 'perPage': 3, # 每一頁最多幾筆 'totalPages': 0, # 總頁數 'page': page, # 用戶要查看的頁數 'rows': [], # 當頁的資料 } output['totalRows'] = db.address_book.count_documents({}) output['totalPages'] = math.ceil(output['totalRows']/output['perPage']) output['page'] = 1 if page < 1 else page if output['page'] > output['totalPages']: output['page'] = output['totalPages'] if output['totalRows']==0: output['rows'] = [] else: cursor = db.address_book.find({}, sort=[('_id', -1)], skip=(output['page']-1) * output['perPage'], limit=output['perPage'] ) for doc in cursor: doc['_id'] = str(doc['_id']) output['rows'].append(doc) return render_template('address-book/list.html', **output) def ab_edit_get(_id): (db, connection) = modules.mongo_connection.getDB('test') try: oid = ObjectId(_id) except: return redirect("/address-book/list/1", code=302) row = db.address_book.find_one({'_id': oid}) row['_id'] = _id # 使用字串 if not row: return redirect("/address-book/list/1", code=302) else: row['page_name'] = 'ab_edit' row['page_title'] = '修改 - 通訊錄' return render_template('address-book/edit.html', **row) def ab_edit_post(): output = { 'success': False, 'error': '', } if len(request.form.get('name')) < 2: output['error'] = '姓名字元長度太短' return output email_match = re.search(email_pattern, request.form.get('email'), re.I) if not email_match: output['error'] = 'Email 格式錯誤' return output (db, connection) = modules.mongo_connection.getDB('test') doc = request.form.to_dict() _id = doc['_id'] del doc['_id'] rr = db.address_book.replace_one({'_id': ObjectId(_id)}, doc) # print(rr) # pymongo.results.UpdateResult if rr.modified_count==1: output['success'] = True else: output['error'] = '資料沒有變更'; return output def ab_add_get(): output = { 'page_name': 'ab_add', 'page_title': '新增 - 通訊錄', } return render_template('address-book/add.html', **output) def ab_add_post(): output = { 'success': False, 'error': '', } if len(request.form.get('name')) < 2: output['error'] = '姓名字元長度太短' return output email_match = re.search(email_pattern, request.form.get('email'), re.I) if not email_match: output['error'] = 'Email 格式錯誤' return output (db, connection) = modules.mongo_connection.getDB('test') doc = request.form.to_dict() rr = db.address_book.insert_one(doc) # print(dir(rr)) # InsertOneResult if rr.inserted_id: output['success'] = True else: output['error'] = '資料沒有新增'; return output def ab_delete(_id): (db, connection) = modules.mongo_connection.getDB('test') try: oid = ObjectId(_id) except: return redirect("/address-book/list/1", code=302) rr = db.address_book.delete_one({'_id': oid}) # print(dir(rr)) # DeleteResult referer = request.headers.get('referer') if not referer: return redirect("/address-book/list/1", code=302) else: return redirect(referer, code=302)

2020-05-09

Flask 連線 MongoDB

Flask 連線 MongoDB

本文的參考專案 https://github.com/shinder/flask-practice

這裡直接用最基本的 PyMongo 連線方式,官方文件

建立連線模組,app/modules/mongo_connection.py:

from pymongo import MongoClient url = 'mongodb://localhost:27017' client = None def getDB(db_name): global client if not client: client = MongoClient(url) return (client[db_name], client)

這個 MongoDB 連線模組的想法和 mysql_connection.py 的想法相同,有使用才會連線。測試的 route 部份:

import modules.mongo_connection @app.route('/try-mongo') def try_mongo(): (db, c) = modules.mongo_connection.getDB('test') one = db.inventory.find_one() one['_id'] = str(one['_id']) # 將 ObjectId 轉換為字串顯示 return one

FB 留言