PHP使用hash算法实现一个简单的数据库代码实例

咱们这次主要是使用PHP语言,结合hash算法,来实现一个简单的数据库实例,它主要有四个功能,连接数据库,查询操作,插入操作,删除操作,关闭数据库连接操作,其它的大家可以后期补充完善下,咱废话不多说,先来看代码:

<?php
header('Content-type:text/html;charset=utf-8');

define('DB_INSERT',1);
define('DB_REPLACE',2);
define('DB_STORE',3);
define('DB_BUCKET_SIZE',262114);
define('DB_KEY_SIZE',128);
define('DB_INDEX_SIZE',DB_KEY_SIZE+12);
define('DB_KEY_EXISTS',1);
define('DB_FAILURE',-1);
define('DB_SUCCESS',0);

class DB{
    private $idx_fp;
    private $dat_fp;
    private $closed;

    public function open($path_name)
    {
        $idx_path = $path_name.".idx";
        $dat_path = $path_name.".dat";

        if (!file_exists($idx_path)) {
            $init = true;
            $mode = 'w+b';
        }else{
            $init = false;
            $mode = 'r+b';
        }

        $this->idx_fp = fopen($idx_path,$mode);
        if($init){
            $elem = pack('L',0x00000000);
            for ($i=0;$i<DB_BUCKET_SIZE;$i++) {
                fwrite($this->idx_fp,$elem,4);
            }
        }

        $this->dat_fp = fopen($dat_path,$mode);
        if(!file_exists($dat_path)) {
            return DB_FAILURE;
        }
        if(!$this->dat_fp) {
            return DB_FAILURE;
        }
        return DB_SUCCESS;
    }

    private function _hash($str)
    {
        $str = substr(md5($str),0,8);
        $hash = 0;
        for ($i=0;$i<8;$i++) {
            $hash += 33*$hash+ord($str[$i]);
        }
        return $hash&0x7FFFFFFF;
    }

    public function fetch($key)
    {
        $offset = ($this->_hash($key)%DB_BUCKET_SIZE)*4;
        fseek($this->idx_fp,$offset,SEEK_SET);
        $pos = unpack('L',fread($this->idx_fp,4));
        $pos = $pos[1];
        $found = false;
        while ($pos) {
            fseek($this->idx_fp,$pos,SEEK_SET);
            $block = fread($this->idx_fp,DB_INDEX_SIZE);
            $cp_key = substr($block,4,DB_KEY_SIZE);
            if (!strncmp($key,$cp_key,strlen($key))) {
                $data_off = unpack('L',substr($block,DB_KEY_SIZE+4,4));
                $data_off = $data_off[1];
                $data_len = unpack('L',substr($block,DB_KEY_SIZE+8,4));
                $data_len = $data_len[1];
                $found = true;
                break;
            }

            $pos = unpack('L',substr($block,0,4));
            $pos = $pos[1];
        }

        if(!$found) {
            return null;
        }

        fseek($this->dat_fp,$data_off,SEEK_SET);
        $data = fread($this->dat_fp,$data_len);
        return $data;
    }

    public function insert($key,$data)
    {
        $offset = ($this->_hash($key)%DB_BUCKET_SIZE)*4;
        $idx_off = fstat($this->idx_fp);
        $idx_off = intval($idx_off['size']);
        $dat_off = fstat($this->dat_fp);
        $dat_off = intval($dat_off['size']);
        $key_len = strlen($key);
        if($key_len > DB_KEY_SIZE) {
            return DB_FAILURE;
        }

        $block = pack('L',0x00000000);
        $block .= $key;
        $space = DB_KEY_SIZE-$key_len;
        for ($i=0;$i<$space;$i++) {
            $block .= pack('C',0x00);
        }
        $block .= pack('L',$dat_off);
        $block .= pack('L',strlen($data));

        fseek($this->idx_fp,$offset,SEEK_SET);
        $pos = unpack('L',fread($this->idx_fp,4));
        $pos = $pos[1];

        if ($pos == 0) {
            fseek($this->idx_fp,$offset,SEEK_SET);
            fwrite($this->idx_fp,pack('L',$idx_off),4);
            fseek($this->idx_fp,0,SEEK_END);
            fwrite($this->idx_fp,$block,DB_INDEX_SIZE);
            fseek($this->dat_fp,0,SEEK_END);
            fwrite($this->dat_fp,$data,strlen($data));
            return DB_SUCCESS;
        }

        $found = false;
        while ($pos) {
            fseek($this->idx_fp,$pos,SEEK_SET);
            $tmp_block = fread($this->idx_fp,DB_INDEX_SIZE);
            $cp_key = substr($tmp_block,4,DB_KEY_SIZE);
            if(!strncmp($key,$cp_key,strlen($key))) {
                $data_off = unpack('L',substr($tmp_block,DB_KEY_SIZE+4,4));
                $data_off = $data_off[1];
                $data_len = unpack('L',substr($tmp_block,DB_KEY_SIZE+8,4));
                $data_len = $data_len[1];
                $found = true;
                break;
            }

            $prev = $pos;
            $pos = unpack('L',substr($tmp_block,0,4));
            $pos = $pos[1];
        }

        if ($found) {
            return DB_KEY_EXISTS;
        }

        fseek($this->idx_fp,$prev,SEEK_SET);
        fwrite($this->idx_fp,pack('L',$idx_off),4);
        fseek($this->idx_fp,0,SEEK_END);
        fwrite($this->idx_fp,$block,DB_INDEX_SIZE);
        fseek($this->dat_fp,0,SEEK_END);
        fwrite($this->dat_fp,$data,strlen($data));
        return DB_SUCCESS;
    }

    public function delete($key)
    {
        $offset = ($this->_hash($key)%DB_BUCKET_SIZE)*4;
        fseek($this->idx_fp,$offset,SEEK_SET);
        $head = unpack('L',fread($this->idx_fp,4));
        $head = $head[1];
        $curr = $head;
        $prev = 0;

        while ($curr) {
            fseek($this->idx_fp,$curr,SEEK_SET);
            $block = fread($this->idx_fp,DB_INDEX_SIZE);
            $next = unpack('L',substr($block,0,4));
            $next = $next[1];
            $cp_key = substr($block,4,DB_KEY_SIZE);
            if(!strncmp($key,$cp_key,strlen($key))) {
                $found = true;
                break;
            }

            $prev = $curr;
            $curr = $next;
        }

        if(!$found){
            return DB_FAILURE;
        }

        if ($prev == 0) {
            fseek($this->idx_fp,$offset,SEEK_SET);
            fwrite($this->idx_fp,pack('L',$next),4);
        }else{
            fseek($this->idx_fp,$prev,SEEK_SET);
            fwrite($this->idx_fp,pack('L',$next),4);
        }

        return DB_SUCCESS;
    }

    public function close()
    {
        if (!$this->closed) {
            fclose($this->idx_fp);
            fclose($this->dat_fp);
            $this->closed = true;
        }
    }
}

上述代码首先是定义了一些咱们需要用到的常量,完事类里面的三个私有的成员变量是两个文件打开的句柄和记录数据库是否连接的句柄,idx的句柄是索引的句柄,另外一个文件句柄是保存数据文件的句柄,之后就是一个open的方法用来代开数据库连接也就是创建索引文件和数据文件,以及检测其是否存在,之后的_hash是一个计算字符串hash值的方法,利用的是timer33算法,之后是读取的方法,再来就是插入和删除的方法,里面具体函数的用处,大家可以在熟悉代码的过程中查百度,咱们这里就不做过多的赘述了。

接下来看下测试增删查的代码实例:

//增
<?php
header('Content-type:text/html;charset=utf-8');
include './db.php';
$db = new DB();
$res = $db->open('test');
$start_time = explode(' ',microtime());
$start_time = $start_time[0]+$start_time[1];
for ($i=0;$i<1000;$i++) {
    $db->insert('key'.$i,'value'.$i);
}
$end_time = explode(' ',microtime());
$end_time = $end_time[0]+$end_time[1];
$db->close();
echo 'process time in '.($end_time-$start_time).' seconds';
die;
//查
<?php
header('Content-type:text/html;charset=utf-8');
include './db.php';
$db = new DB();
$db->open('test');
$start_time = explode(' ',microtime());
$start_time = $start_time[0]+$start_time[1];
for ($i=0;$i<1000;$i++) {
    $data = $db->fetch('key'.$i);
//    echo $data."<br>";
}
$end_time = explode(' ',microtime());
$end_time = $end_time[0]+$end_time[1];
$db->close();
echo 'process time in '.($end_time-$start_time).' seconds';
die;
//删
<?php
header('Content-type:text/html;charset=utf-8');
include './db.php';
$db = new DB();
$db->open('test');
$start_time = explode(' ',microtime());
$start_time = $start_time[0]+$start_time[1];
$db->delete('key1');
for ($i=0;$i<1000;$i++) {
    $data = $db->fetch('key'.$i);
//    echo $data."<br>";
}
$end_time = explode(' ',microtime());
$end_time = $end_time[0]+$end_time[1];
$db->close();
echo 'process time in '.($end_time-$start_time).' seconds';
die;

插入和查询都已按着一千条来计算的,速度么,还算是可以的,都是毫秒级别的,大家有兴趣的可以多多测试和完善下,咱这里就算是抛砖引玉了,各位有什么问题和想法都可以给我评论和私信,只要看到了必回。

好啦,本次记录就到这里了,如果感觉不错的话,请多多点赞支持哦。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
国密算法是中国自主开发的密码算法,包括SM1、SM2、SM3和SM4等。其中,SM2是非对称加密算法,SM3是哈希算法,SM4是对称加密算法。这里我们以SM2为例,使用Java代码实现SM2算法。 首先,需要使用Bouncy Castle库来实现SM2算法。可以在Maven中添加以下依赖: ``` <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.68</version> </dependency> ``` 然后就可以使用以下代码实现SM2算法: ```java import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.signers.SM2Signer; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECPrivateKeySpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; import java.security.Security; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; public class SM2Utils { private static final String SM2_CURVE_NAME = "sm2p256v1"; // SM2的椭圆曲线参数 private static final int SM2_DIGEST_SIZE = 32; // SM3哈希函数输出长度为32字节 static { Security.addProvider(new BouncyCastleProvider()); } /** * 生成SM2密钥对 * @return SM2密钥对 * @throws Exception 异常 */ public static KeyPair generateKeyPair() throws Exception { ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(SM2_CURVE_NAME); ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator(); ecKeyPairGenerator.init(new ECKeyGenerationParameters(new ECDomainParameters(ecGenParameterSpec.getCurve(), ecGenParameterSpec.getG(), ecGenParameterSpec.getN()), null)); AsymmetricCipherKeyPair keyPair = ecKeyPairGenerator.generateKeyPair(); ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate(); ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic(); KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC"); ECParameterSpec ecParameterSpec = new ECParameterSpec(ecGenParameterSpec.getCurve(), ecGenParameterSpec.getG(), ecGenParameterSpec.getN()); ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(privateKey.getD(), ecParameterSpec); ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(publicKey.getQ().getAffineXCoord().toBigInteger(), publicKey.getQ().getAffineYCoord().toBigInteger()), ecParameterSpec); return new KeyPair(keyFactory.generatePublic(publicKeySpec), keyFactory.generatePrivate(privateKeySpec)); } /** * SM2签名 * @param data 待签名数据 * @param privateKey 私钥 * @return 签名结果 * @throws Exception 异常 */ public static byte[] sign(byte[] data, BigInteger privateKey) throws Exception { ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(SM2_CURVE_NAME); SM2Signer signer = new SM2Signer(); signer.init(true, new ECPrivateKeyParameters(privateKey, new ECDomainParameters(ecGenParameterSpec.getCurve(), ecGenParameterSpec.getG(), ecGenParameterSpec.getN()))); signer.update(data, 0, data.length); return signer.generateSignature(); } /** * SM2验签 * @param data 待验签数据 * @param publicKey 公钥 * @param signature 签名结果 * @return 验签结果 * @throws Exception 异常 */ public static boolean verify(byte[] data, byte[] publicKey, byte[] signature) throws Exception { ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(SM2_CURVE_NAME); SM2Signer signer = new SM2Signer(); signer.init(false, new ECPublicKeyParameters(new ECPoint(new BigInteger(1, publicKey), new BigInteger(1, publicKey, 32)), new ECDomainParameters(ecGenParameterSpec.getCurve(), ecGenParameterSpec.getG(), ecGenParameterSpec.getN()))); signer.update(data, 0, data.length); return signer.verifySignature(signature); } /** * SM3哈希 * @param data 待哈希数据 * @return 哈希结果 * @throws Exception 异常 */ public static byte[] hash(byte[] data) throws Exception { SM3Digest digest = new SM3Digest(); digest.update(data, 0, data.length); byte[] hash = new byte[SM2_DIGEST_SIZE]; digest.doFinal(hash, 0); return hash; } /** * SM2加密 * @param data 待加密数据 * @param publicKey 公钥 * @return 加密结果 * @throws Exception 异常 */ public static byte[] encrypt(byte[] data, byte[] publicKey) throws Exception { ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(SM2_CURVE_NAME); SM2Engine engine = new SM2Engine(); engine.init(true, new ECPublicKeyParameters(new ECPoint(new BigInteger(1, publicKey), new BigInteger(1, publicKey, 32)), new ECDomainParameters(ecGenParameterSpec.getCurve(), ecGenParameterSpec.getG(), ecGenParameterSpec.getN()))); return engine.processBlock(data, 0, data.length); } /** * SM2解密 * @param data 待解密数据 * @param privateKey 私钥 * @return 解密结果 * @throws Exception 异常 */ public static byte[] decrypt(byte[] data, BigInteger privateKey) throws Exception { ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(SM2_CURVE_NAME); SM2Engine engine = new SM2Engine(); engine.init(false, new ECPrivateKeyParameters(privateKey, new ECDomainParameters(ecGenParameterSpec.getCurve(), ecGenParameterSpec.getG(), ecGenParameterSpec.getN()))); return engine.processBlock(data, 0, data.length); } } ``` 使用示例: ```java KeyPair keyPair = SM2Utils.generateKeyPair(); byte[] publicKey = ((ECPublicKey) keyPair.getPublic()).getEncoded(); byte[] privateKey = ((ECPrivateKey) keyPair.getPrivate()).getEncoded(); byte[] data = "hello world".getBytes(); // 签名 byte[] signature = SM2Utils.sign(SM2Utils.hash(data), new BigInteger(1, privateKey)); System.out.println("signature: " + Hex.encodeHexString(signature)); // 验签 boolean verifyResult = SM2Utils.verify(SM2Utils.hash(data), publicKey, signature); System.out.println("verifyResult: " + verifyResult); // 加密 byte[] encryptedData = SM2Utils.encrypt(data, publicKey); System.out.println("encryptedData: " + Hex.encodeHexString(encryptedData)); // 解密 byte[] decryptedData = SM2Utils.decrypt(encryptedData, new BigInteger(1, privateKey)); System.out.println("decryptedData: " + new String(decryptedData)); ``` 需要注意的是,SM2算法使用的椭圆曲线参数为sm2p256v1,哈希函数为SM3,输出长度为32字节。在使用时需要注意参数的设置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luyaran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值