归档 2018

[python] ValueError: IV must be 16 bytes long

今天在研究 python 的 Crypto.Cipher 库中 AES 加密算法怎么使用,照着样例随手写了段代码,在执行时遇到以下问题:

ValueError: IV must be 16 bytes long

折腾了好一会儿都没搞定,上网看到有个大神也遇到过相同的问题,发现是在调用 AES.new 函数时参数iv 没填或不正确导致,正确的调用方法如下:

from Crypto.Cipher import AES
from Crypto import Random

key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
mode = AES.MODE_CBC
iv = bytearray(AES.block_size)
cryptor = AES.new(key,  mode, iv)
...

或者直接把 iv 设置成

b'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'

*注意千万不要填充

b'0000000000000000'

因为其实填充的是:

import binascii
binascii.hexlify(b'0000000000000000')
'30303030303030303030303030303030'

本文链接:/2018/11/30/python-valueerror-iv-must-be-16-bytes-long/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

The Best Hash Algorithm : BKDRHash

// BKDR Hash Function
unsigned int BKDRHash(char *str)
{
    unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
    unsigned int hash = 0;

    while (*str)
    {
        hash = hash * seed + (*str++);
    }

    return (hash & 0x7FFFFFFF);
}

本文链接:/2018/11/11/best-hash-function-algorithm-bkdrhash/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

解决MacOS升级后出现xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun的问题

今天升级macOS Mojave,终端里使用 brew update 的时候,弹出一行莫名其妙的错误:

xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
Error: Failure while executing; `git config --local --replace-all homebrew.analyticsmessage true` exited with 1.

解决方法,重装xcode command line:

xcode-select --install

如果没有解决问题,执行以下命令:

sudo xcode-select -switch /

本文链接:/2018/10/23/macosxcrun-error-invalid-active-developer-path-librarydevelopercommandlinetools-missing-xcrun/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

[Spark] MySQL 踩坑记录

scala代码实现连接mysql

首先在 sbt 配置文件里添加:

"mysql" % "mysql-connector-java" % "8.0.12",

踩到的坑

1

使用 JDBC 访问特定数据库时,需要在 spark classpath 上添加对应的 JDBC 驱动配置。

--driver-class-path lib/mysql-connector-java-8.0.12.jar

不然代码在本地 sbt run 运行是没有问题, 但是放在服务器上用 spark-submit 提交的话,可能会报异常:

com.mysql.jdbc.Driver

2

运行项目中提示:

The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

'com.mysql.jdbc.Driver' 驱动类被弃用了,新的驱动类是 'com.mysql.cj.jdbc.Driver'。 这个驱动会通过 SPI 的方式自动加载,通常不需要人工手动加载。

val pool = MysqlConnectionPool(dbHost, dbUser, dbPasswd,  "com.mysql.cj.jdbc.Driver") 

本文链接:/2018/08/14/spark-mysql/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

[Django] 将 Django 的用户认证系统登陆界面替换成 Adminlte 主题

背景简介

最近在完善之前开发的 Django 管理系统,期间有使用 Adminlte 主题替换 Django 项目中用户认证系统登陆界面默认主题,并且效果好不错,特此记录下来以供日后使用。

为了更清楚地描述步骤,所以不会引入其他第三方的库,最大限度的利用 Django 提供的基础功能。

开发前,假设 Django 已经被安装,Adminlte 已经被下载(/path/to/ adminlte)。

相关资料

  • 网站通常都会提供登录、注册、注销等用户认证功能。因此,Django 提供了一套功能完整的、灵活的、易于拓展的用户认证系统:django.contrib.auth。

  • Adminlte 是一个成熟的基于bootstrap的后台模板,下载地址

环境与版本说明

  • OS: CentOS 7
  • Python: 2.7
  • Django: 1.11.0
  • AdminLTE: 2.4.3

创建一个 Django 项目

$ django-admin startproject mysite
$ cd mysite/

修改 Django 项目中的文件

mysite/settings.py

ALLOWED_HOSTS = ['0.0.0.0',] # 修改
# ...(略过不表)...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates'),], # 修改
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
# ...(略过不表)...
# 添加以下代码
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'

mysite/views.py

# 添加以下代码
from django.shortcuts import render
from django.http import HttpResponse
from django.conf import settings
from django.contrib.auth.decorators import login_required

@login_required
def index(request):
    return render(request, 'index.html')
mysite/urls.py

from django.conf.urls import url
from django.contrib import admin
from . import views # 添加
from django.contrib.auth import views as auth_views # 添加

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.index, name='index'), # 添加
    url(r'^login/', auth_views.login, { 'template_name': 'login.html' }, name='login'), # 添加
    url(r'^logout/', auth_views.logout_then_login, name='logout'), # 添加
]

创建管理员(admin)用户

$ python manage.py createsuperuser
Username (leave blank to use 'username'): admin
Email address: ******
Password: ******
Password (again): 
Superuser created successfully.

引入 Adminlte 模板文件

$ mkdir templates
$ mkdir static
$ cp /path/to/AdminLTE/pages/examples/login.html templates/
$ cp /path/to/AdminLTE/pages/examples/blank.html templates/index.html
$ cp /path/to/AdminLTE/dist static/
$ cp /path/to/AdminLTE/bootstrap static/
$ cp /path/to/AdminLTE/plugins static/

修改相关 HTML 文件

template/login.html

{% load static %} <!-- 添加 -->
<!DOCTYPE html>

<!-- 以下是变更的地方 -->
<!-- Bootstrap 3.3.6 -->
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
<!-- Theme style -->
<link rel="stylesheet" href="{% static 'dist/css/AdminLTE.min.css' %}">
<!-- iCheck -->
<link rel="stylesheet" href="{% static 'plugins/iCheck/square/blue.css' %}">

<div class="login-box-body">
  {% if form.errors %} <!-- 添加 -->
    <p class="login-box-msg bg-red">Your username and password didn't match. Please try again.</p> <!-- 添加 -->
  {% else %} <!-- 添加 -->
    <p class="login-box-msg">Sign in to start your session</p>
  {% endif %} <!-- 添加 -->

<form action="{% url 'login' %}" method="post">
{% csrf_token %} <!-- 添加 -->
<input type="text" class="form-control" name="username" placeholder="Username">
<input type="password" class="form-control" name="password" placeholder="Password">

<!-- jQuery 2.2.3 -->
<script src="{% static 'plugins/jQuery/jquery-2.2.3.min.js' %}"></script>
<!-- Bootstrap 3.3.6 -->
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<!-- iCheck -->
<script src="{% static 'plugins/iCheck/icheck.min.js' %}"></script>

template/index.html

{% load static %} <!-- 添加 -->
<!DOCTYPE html>

<!-- 以下是变更的地方 -->
<!-- Bootstrap 3.3.6 -->
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
<!-- Theme style -->
<link rel="stylesheet" href="{% static 'dist/css/AdminLTE.min.css' %}">
<!-- AdminLTE Skins. Choose a skin from the css/skins
     folder instead of downloading all of them to reduce the load. -->
<link rel="stylesheet" href="{% static 'dist/css/skins/_all-skins.min.css' %}">

<img src="{% static 'dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">
<img src="{% static 'dist/img/user2-160x160.jpg' %}" class="user-image" alt="User Image">
<img src="{% static 'dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">

<a href="{% url 'logout' %}" class="btn btn-default btn-flat">Sign out</a>

<img src="{% static 'dist/img/user2-160x160.jpg' %}" class="img-circle" alt="User Image">

<!-- jQuery 2.2.3 -->
<script src="{% static 'plugins/jQuery/jquery-2.2.3.min.js' %}"></script>
<!-- Bootstrap 3.3.6 -->
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<!-- SlimScroll -->
<script src="{% static 'plugins/slimScroll/jquery.slimscroll.min.js' %}"></script>
<!-- FastClick -->
<script src="{% static 'plugins/fastclick/fastclick.js' %}"></script>
<!-- AdminLTE App -->
<script src="{% static 'dist/js/app.min.js' %}"></script>

目录结构

mysite/
├── manage.py
├── mysample
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── templates
│       └── index.html
├── static
│       ├── dist
│       ├── bootstrap
│       └── plugins
└── mysite
    ├── __init__.py
    ├── __pycache__
    │   ├── __init__.cpython-36.pyc
    │   └── settings.cpython-36.pyc
    ├── settings.py
    ├── urls.py
    └── wsgi.py

运行项目

$ python manage.py runserver 0.0.0.0:8080

打开浏览器并输入到“http://服务器IP:8080”,登录页面就出来了。

输入用户名“admin”和对应的密码,初始页面就会出现。

从初始画面点击“sign out”(登出),就会跳转到注销登录的页面。

以上

本文链接:/2018/07/13/django-django-adminlte/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

[Python]: 记一次使用 python 字典踩到的坑

[Python]: 记一次使用 python 字典踩到的坑

问题背景

最近在使用 python 做一个数据量很大的统计任务,抽取账号相同的记录,进行统计并排序。代码中使用到了字典,存储账号相关的记录,用账号作为键。

key = msg_id.split("_")[0]
if key  not in alerm_date_dict:
    data = nbClientData()
    data.name = key
    data.succ = cnt_succ_client
    data.fail = cnt_fail_client
    alerm_date_dict[key] = data
else:
    alerm_date_dict[key].succ += cnt_succ_client
    alerm_date_dict[key].fail += cnt_fail_client

包含以上代码的脚本跑了一个小时才把数据全部跑完,很是耗时,但是遍历数据并不应该是性能瓶颈,而且使用 python 的字典存取数据也并不慢, 但就是跑了整整一小时才跑完,是可忍孰不可忍。Stack Overflow 了一下, 原来罪魁祸首是这句代码导致的。

if key not in alerm_date_dict:

问题分析

字典是Python中唯一内建的映射类型。字典中的值并没有特殊的顺序,但是都存储在一个特点的键(key)里。键可以是数字、字符串甚至是元组。用过 python 的朋友都应该了解,判断一个 key 在不在字典或者列表里,使用 in 这个方法挺好用的。

按理说,python 的字典是C语言实现的 哈希表,效率应该不低才对。研究了一阵才发现隐藏了个坑,原来在对字典使用 in 的时候调用的是 dict.keys() 这个函数, 这个函数返回的是一个列表。

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

返回的列表包含了是整个字典的所有键,每次循环都返回十几万的数据,还要在列表里找对应的键,难怪那么慢!

解决办法

找到原因后,修改代码如下:

key = msg_id.split("_")[0]
if alerm_date_dict.get(key) != None:
    data = nbClientData()
    data.name = key
    data.succ = cnt_succ_client
    data.fail = cnt_fail_client
    alerm_date_dict[key] = data
else:
    alerm_date_dict[key].succ += cnt_succ_client
    alerm_date_dict[key].fail += cnt_fail_client

Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值。直接操作字典,不会调用 dict.keys(),改完之后执行一两分钟就跑完任务了。

以上

本文链接:/2018/06/25/python/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

Golang:开源库 Go-MySQL-Driver 使用

Golang:开源库 Go-MySQL-Driver 使用

A MySQL-Driver for Go's database/sql package

MySQL

MySQL is the world's most popular open source database. Whether you are a fast growing web property, technology ISV or large enterprise, MySQL can cost-effectively help you deliver high performance, scalable database applications. —— MySQL

MySQL驱动 Go-MySQL-Driver 使用

github 地址

Go-MySQL-Driver

文档

Go-MySQL-Driver wiki

安装

$ go get -u github.com/go-sql-driver/mysql

导入

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

数据库表结构

USE test;
CREATE TABLE `squareNum` (
    `number` INT(11) NOT NULL DEFAULT '0',
    `squareNumber` INT(11) NOT NULL DEFAULT '0',
    PRIMARY KEY (`number`)
);
/*
+--------------+---------+------+-----+---------+-------+
| Field        | Type    | Null | Key | Default | Extra |
+--------------+---------+------+-----+---------+-------+
| number       | int(11) | NO   | PRI | NULL    |       |
| squareNumber | int(11) | NO   |     | NULL    |       |
+--------------+---------+------+-----+---------+-------+
*/

用例

package main

import (
        "database/sql"
        "fmt"
        _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", "root:11111111@/test?charset=utf8")
    checkErr(err)
        defer db.Close()

    // Open doesn't open a connection. Validate DSN data:
    err = db.Ping()
    checkErr(err)

    // Use the DB normally, execute the querys etc
    stmtIns, err := db.Prepare("INSERT INTO squareNum VALUES( ?, ? )")
    checkErr(err)
    defer stmtIns.Close() // Close the statement when we leave main() / the program terminates

    stmtOut, err := db.Prepare("SELECT squareNumber FROM squareNum WHERE number = ?")
    checkErr(err)
    defer stmtOut.Close()
    for i := 0; i < 25; i++ {
                _, err = stmtIns.Exec(i, (i * i)) // Insert tuples (i, i^2)
                if err != nil {
                        panic(err.Error()) // proper error handling instead of panic in your app
                }
        }

    var squareNum int // we "scan" the result in here

    // Query the square-number of 13
        err = stmtOut.QueryRow(13).Scan(&squareNum) // WHERE number = 13
    checkErr(err)
    fmt.Printf("The square number of 13 is: %d\n", squareNum)

    // Query another number.. 1 maybe?
        err = stmtOut.QueryRow(1).Scan(&squareNum) // WHERE number = 1
        checkErr(err)
        fmt.Printf("The square number of 1 is: %d\n", squareNum)

    stmtIns, err = db.Prepare("DELETE FROM squareNum where number=?")
        checkErr(err)

    res, err := stmtIns.Exec(13)
        checkErr(err)

    affect, err := res.RowsAffected()
        checkErr(err)

    fmt.Println("affect:", affect)
}

func checkErr(err error) {
        if err != nil {
                panic(err.Error())
        }
}

/*
Output:
The square number of 13 is: 169
The square number of 1 is: 1
affect: 1
*/

以上

本文链接:/2018/06/21/golang-go-mysql-driver/
请尊重作者的劳动成果,转载请注明出处!Sakishum 博客保留对文章的所有权利。

Golang: 开源库 go-redis 使用

Redis

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. —— redis

开源库 go-redis 使用

github地址

go-redis

文档

go-redis doc

go-redis example

安装

go get -u github.com/go-redis/redis

导入

import "github.com/go-redis/redis"

用例

package main

import (
    "fmt"
    "github.com/go-redis/redis"
)

func main() {
    client := redis.NewClient(&redis.Options{
        Addr:     "127.0.0.1:6379",
        Password: "11111111",   // no password set
        DB:       0,            // use default DB
        })

        pong, err := client.Ping().Result()
    if err != nil {
        panic("Connect fail!")
    }
        fmt.Println(pong)

    err = client.Set("key", "value", 0).Err()
        if err != nil {
                panic(err)
        }

        val, err := client.Get("key").Result()
        if err != nil {
                panic(err)
        }
        fmt.Println("key", val)

        val2, err := client.Get("key2").Result()
        if err == redis.Nil {
                fmt.Println("key2 does not exist")
        } else if err != nil {
                panic(err)
        } else {
                fmt.Println("key2", val2)
        }
        // Output: key value
        // key2 does not exist
}

继续阅读

每月存档