PHP SM4 加密
PHP SM4 加密
sm4基类
class Sm4
{private $ck = [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279];private $Sbox = [0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48];private $fk = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];private $rk = [];private $b = '';private $len = 16;/*** Sm4 constructor.* @param string $key 秘钥长度16位* @param string $b 不是16的倍数 需要的补码* @throws \Exception*/public function __construct($key, $b = ' '){$this->ck16($key);$this->crk($key);}private function dd(&$data){$n = strlen($data) % $this->len;$data = $data . str_repeat($this->b, $n);}private function ck16($str){if (strlen($str) !== $this->len) {throw new \Exception('秘钥长度为16位');}}private function add($v){$arr = unpack('N*', $v);$max = 0xffffffff;$j = 1;for ($i = 4; $i > 0; $i--) {if ($arr[$i] > $max - $j) {$j = 1;$arr[$i] = 0;} else {$arr[$i] += $j;break;}}return pack('N*', ...$arr);}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function deDataCtr($str, $iv){return $this->enDataCtr($str, $iv);}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function enDataCtr($str, $iv){$this->ck16($iv);$r = '';$this->dd($str);$l = strlen($str) / $this->len;for ($i = 0; $i < $l; $i++) {$s = substr($str, $i * $this->len, $this->len);$tr = [];$this->encode(array_values(unpack('N*', $iv)), $tr);$s1 = pack('N*', ...$tr);$s1 = $s1 ^ $s;$iv = $this->add($iv);$r .= $s1;}return $r;}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function enDataOfb($str, $iv){$this->ck16($iv);$r = '';$this->dd($str);$l = strlen($str) / $this->len;for ($i = 0; $i < $l; $i++) {$s = substr($str, $i * $this->len, $this->len);$tr = [];$this->encode(array_values(unpack('N*', $iv)), $tr);$iv = pack('N*', ...$tr);$s1 = $s ^ $iv;$r .= $s1;}return $r;}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function deDataOfb($str, $iv){return $this->enDataOfb($str, $iv);}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function deDataCfb($str, $iv){$this->ck16($iv);$r = '';$this->dd($str);$l = strlen($str) / $this->len;for ($i = 0; $i < $l; $i++) {$s = substr($str, $i * $this->len, $this->len);$tr = [];$this->encode(array_values(unpack('N*', $iv)), $tr);$s1 = pack('N*', ...$tr);$s1 = $s ^ $s1;$iv = $s;$r .= $s1;}return $r;}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function enDataCfb($str, $iv){$this->ck16($iv);$r = '';$this->dd($str);$l = strlen($str) / $this->len;for ($i = 0; $i < $l; $i++) {$s = substr($str, $i * $this->len, $this->len);$tr = [];$this->encode(array_values(unpack('N*', $iv)), $tr);$s1 = pack('N*', ...$tr);$iv = $s ^ $s1;$r .= $iv;}return $r;}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function enDataCbc($str, $iv){$this->ck16($iv);$r = '';$this->dd($str);$l = strlen($str) / $this->len;for ($i = 0; $i < $l; $i++) {$s = substr($str, $i * $this->len, $this->len);$s = $iv ^ $s;$tr = [];$this->encode(array_values(unpack('N*', $s)), $tr);$iv = pack('N*', ...$tr);$r .= $iv;}return $r;}/*** @param string $str 加密字符串* @param string $iv 初始化字符串16位* @return string* @throws \Exception*/public function deDataCbc($str, $iv){$this->ck16($iv);$r = '';$this->dd($str);$l = strlen($str) / $this->len;for ($i = 0; $i < $l; $i++) {$s = substr($str, $i * $this->len, $this->len);$tr = [];$this->decode(array_values(unpack('N*', $s)), $tr);$s1 = pack('N*', ...$tr);$s1 = $iv ^ $s1;$iv = $s;$r .= $s1;}return $r;}/*** @param string $str 加密字符串* @return string*/public function enDataEcb($str){$r = [];$this->dd($str);$ar = unpack('N*', $str);do {$this->encode([current($ar), next($ar), next($ar), next($ar)], $r);} while (next($ar));return pack('N*', ...$r);}/*** @param string $str 解密字符串* @return string*/public function deDataEcb($str){$r = [];$this->dd($str);$ar = unpack('N*', $str);do {$this->decode([current($ar), next($ar), next($ar), next($ar)], $r);} while (next($ar));return pack('N*', ...$r);}private function encode($ar, &$r){for ($i = 0; $i < 32; $i++) {$ar[$i + 4] = $this->f($ar[$i], $ar[$i + 1], $ar[$i + 2], $ar[$i + 3], $this->rk[$i]);}$r[] = $ar[35];$r[] = $ar[34];$r[] = $ar[33];$r[] = $ar[32];}private function decode($ar, &$r){for ($i = 0; $i < 32; $i++) {$ar[$i + 4] = $this->f($ar[$i], $ar[$i + 1], $ar[$i + 2], $ar[$i + 3], $this->rk[31 - $i]);}$r[] = $ar[35];$r[] = $ar[34];$r[] = $ar[33];$r[] = $ar[32];}private function crk($key){$keys = array_values(unpack('N*', $key));$keys = [$keys[0] ^ $this->fk[0],$keys[1] ^ $this->fk[1],$keys[2] ^ $this->fk[2],$keys[3] ^ $this->fk[3]];for ($i = 0; $i < 32; $i++) {$this->rk[] = $keys[] = $keys[$i] ^ $this->t1($keys[$i + 1] ^ $keys[$i + 2] ^ $keys[$i + 3] ^ $this->ck[$i]);}}private function lm($a, $n){return ($a >> (32 - $n) | (($a << $n) & 0xffffffff));}private function f($x0, $x1, $x2, $x3, $r){return $x0 ^ $this->t($x1 ^ $x2 ^ $x3 ^ $r);}private function s($n){return $this->Sbox[($n & 0xff)] | $this->Sbox[(($n >> 8) & 0xff)] << 8 | $this->Sbox[(($n >> 16) & 0xff)] << 16 | $this->Sbox[(($n >> 24) & 0xff)] << 24;}private function t($n){$b = $this->s($n);return $b ^ $this->lm($b, 2) ^ $this->lm($b, 10) ^ $this->lm($b, 18) ^ $this->lm($b, 24);}private function t1($n){$b = $this->s($n);return $b ^ $this->lm($b, 13) ^ $this->lm($b, 23);}}
调用类
class RtSm4
{protected $sm4;protected $keyLen = 16;protected $ivLen = 16;function __construct($key){$this->sm4 = new Sm4($key);}public function encrypt($data, $type = 'sm4', $iv = '', $formatOut = 'hex'){if ($type != 'sm4-ecb') {$this->check_iv($iv);}$ret = '';switch ($type) {case 'sm4':case 'sm4-cbc':$data = $this->mystr_pad($data, $this->keyLen); //需要补齐$ret = $this->sm4->enDataCbc($data, $iv);break;case 'sm4-ecb':$data = $this->mystr_pad($data, $this->keyLen); //需要补齐$ret = $this->sm4->enDataEcb($data);break;case 'sm4-ctr':$ret = $this->sm4->enDataCtr($data, $iv);break;case 'sm4-ofb':$ret = $this->sm4->enDataOfb($data, $iv);break;case 'sm4-cfb':$ret = $this->sm4->enDataCfb($data, $iv);break;default:throw new Exception('bad type');}if ($formatOut == 'hex') {return bin2hex($ret);} else if ($formatOut == 'base64') {return base64_encode($ret);}return $ret;}public function decrypt($data, $type = 'sm4', $iv = '', $formatInput = 'hex'){if ($type != 'sm4-ecb') {$this->check_iv($iv);}if ($formatInput == 'hex') {$data = hex2bin($data);} else if ($formatInput == 'base64') {$data = base64_decode($data);}//else is rawswitch ($type) {case 'sm4':case 'sm4-cbc':$ret = $this->sm4->deDataCbc($data, $iv);$ret = $this->mystr_unpad($ret);break;case 'sm4-ecb':$ret = $this->sm4->deDataEcb($data);$ret = $this->mystr_unpad($ret);break;case 'sm4-ctr':$ret = $this->sm4->deDataCtr($data, $iv);break;case 'sm4-ofb':$ret = $this->sm4->deDataOfb($data, $iv);break;case 'sm4-cfb':$ret = $this->sm4->deDataCfb($data, $iv);break;default:throw new Exception('bad type');}return $ret;}//加密前补齐,特定后缀不适用全部的对接方protected function mystr_pad($data, $len = 16){$n = $len - strlen($data) % $len;$tmpString = $this->strToHex($data) . "80";$tmpString .= str_repeat("00", $n - 1);return $this->hexToStr($tmpString);}// 解密后去掉补齐,特定后缀不适用全部的对接方protected function mystr_unpad($data){$tmp = $this->strToHex($data);$lastIndex = strrpos($tmp, '80');if ($lastIndex !== false) {$tmp = substr($tmp, 0, $lastIndex);}return $this->hexToStr($tmp);}//加密前补齐,通用代码,无特定需求可用这个protected function mystr_pad_bak($data, $len = 16){$n = $len - strlen($data) % $len;return $data . str_repeat(chr($n), $n);}// 解密后去掉补齐 通用的代码,无特定需求可用这个protected function mystr_unpad_bak($data){$n = ord(substr($data, -1));return substr($data, 0, -$n);}protected function check_iv($iv){if (strlen($iv) != $this->ivLen) {throw new Exception('bad iv');}}protected function strToHex($string){$hex = unpack('H*', $string);return $hex[1];}protected function hexToStr($hex){$string = pack('H*', $hex);return $string;}
}
调用
$key = hex2bin('660e5d5xxxxxxx714f346e');
$iv = hex2bin('abcd0863xxxxxf67');
$sm4 = new RtSm4($key);
$string = 'xxxx';
$encodeText = $sm4->encrypt($string, 'sm4-cbc', $iv);
echo $encodeText . PHP_EOL;
echo $sm4->decrypt($encodeText, 'sm4-cbc', $iv). PHP_EOL;
相关文章:
PHP SM4 加密
PHP SM4 加密 sm4基类 class Sm4 {private $ck [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,0xc0c7ced5, 0xdce3ea…...
leetcode - 2825. Make String a Subsequence Using Cyclic Increments
Description You are given two 0-indexed strings str1 and str2. In an operation, you select a set of indices in str1, and for each index i in the set, increment str1[i] to the next character cyclically. That is ‘a’ becomes ‘b’, ‘b’ becomes ‘c’, an…...

工业—使用Flink处理Kafka中的数据_ChangeRecord1
使用 Flink 消费 Kafka 中 ChangeRecord 主题的数据,当某设备 30 秒状态连续为 “ 预警 ” ,输出预警 信息。当前预警信息输出后,最近30...
探索嵌入式硬件设计:揭秘智能设备的心脏
目录 引言 嵌入式系统简介 嵌入式硬件设计的组成部分 设计流程 微控制器选择 原理图设计 PCB布局 编程与调试 系统集成与测试 深入理解微控制器 存储器管理 输入/输出接口 通信接口 电源管理 硬件抽象层(HAL) 操作系统(OS&am…...

数据结构-最小生成树
一.最小生成树的定义 从V个顶点的图里生成的一颗树,这颗树有V个顶点是连通的,有V-1条边,并且边的权值和是最小的,而且不能有回路 二.Prim算法 Prim算法又叫加点法,算法比较适合稠密图 每次把边权最小的顶点加入到树中࿰…...
mac启动jmeter
// 设置使用java8,使用21版本会有问题 export JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/ export PATH$JAVA_HOME/bin:$PATH cd /Users/user/software/apache-jmeter-5.1.1 //设置不使用代理 sh jmeter -Jhttp.proxyHost -J…...
spring学习笔记之静态代理和动态代理
在 Spring 开发中,静态代理和动态代理是实现面向切面编程(AOP)的两种常见方式。两者的主要区别在于代理类的生成时间和方式。 静态代理 定义 静态代理是由开发者或工具在编译期明确创建代理类的方式,代理类和目标类在程序运行前就已经存在。 特点 代理类明确存在:需要…...

qemu搭建aarch64
qemu工具搭建aarch64系统 下载准备 下载qemu: https://qemu.weilnetz.de/w64/2022/qemu-w64-setup-20220831.exe 下载固件:https://publishing-ie-linaro-org.s3.amazonaws.com/releases/components/kernel/uefi-linaro/16.02/release/qemu64/QEMU_EFI.fd?Signat…...
delphi IDE 插件DelphiIDEPlugin_SearchProject,用于从项目组中查找项目
delphi IDE 插件DelphiIDEPlugin_SearchProject,用于从项目组中查找项目 安装后在菜单Tools下第一个子菜单项查找项目 delphiIDE插件DelphiIDEPlugin-SearchProject,用于从项目组中查找项目资源-CSDN文库...

【Vue】Scoped、组件间通信、Props检验
目录 Scoped 作用 *原理 组件通信 前置知识 什么是组件通信 为什么需要组件通信 如何进行组件通信 如何辨别两个组件的关系 父子组件通信 父传子 子传父 非父子组件通信 祖先传后代 语法 任意两个组件通信 步骤 Props校验 props是什么 作用 语法 组件的…...

openbmc dbus架构简析(二)
1.说明 以前看内核代码觉得难,是因为内核代码涉及到硬件原理与算法结构和层次递进的代码逻辑,现在的应用层因为业务的复杂与代码和内核的交互接口复杂,也变得有些难度了。 这篇文章是继:openbmc dbus架构简析的第二篇文章。 首先贴出来前篇…...

【二分查找】Leetcode例题
【1】69. x 的平方根 - 力扣(LeetCode) 🍡解题思路:首先想到的是暴力查找,从1开始依次比较x与num*num的大小,然后找出满足num*num<x且(num1)*(num1)>x的num值;再来看看能不能优化一下&…...
gitlab配置调试minio
官方文档 rails console 调试 查看配置Settings.uploads.object_store加载minio clientrequire fog/awsfog_connection Fog::Storage.new(provider: AWS,aws_access_key_id: 你的MINIO_ACCESS_KEY,aws_secret_access_key: 你的MINIO_SECRET_KEY,region: <S3 region>,e…...
Vue实战技巧:如何展示附件(PDF、MP4、Excel、Zip等)并修改名称下载
大家好,今天给大家分享一篇关于在Vue项目中展示附件(PDF、MP4、Excel、Zip等)并修改名称下载的教程。在实际开发过程中,这个功能非常实用,下面我们就一起来学习一下。 一、准备工作 首先,确保你的项目中已经…...

AI证件照制作 API 对接说明
AI证件照制作 API 对接说明 本文将介绍一种 AI证件照制作 API 对接说明,它是可以通过输入人像照片URL以及自己喜欢的模板来制作各种风格的证件照。 接下来介绍下 AI证件照制作 API 的对接说明。 申请流程 要使用 API,需要先到 AI证件照制作 API?inv…...

Macos用brew安装Nodejs亲手教程
首先确保brew已安装,搜索node资源,命令如下: brew search nodejs 演示结果如下: 安装nodejs brew install node22 或 brew install node 出现如下界面 表示正在安装,安装成功后,提示如下信息࿱…...
Node.js 新手教程
1、nodejs简介 Node.js 是一个开源和跨平台的 JavaScript 运行时环境。它是几乎所有类型项目的流行工具! Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的核心)。这使得 Node.js 的性能非常出色。 Node.js 应用程序在单个进…...

Latex转word(docx)或者说PDF转word 一个相对靠谱的方式
0. 前言 投文章过程中总会有各种各样的要求,其中提供word格式的手稿往往是令我头疼的一件事。尤其在多公式的文章中,其中公式转换是一个头疼的地方,还有很多图表,格式等等,想想就让人头疼欲裂。实践中摸索出一条相对靠…...
前端热门面试题目——React、Node
img 标签的 srcset 属性的作用 srcset 属性允许开发者为不同设备或分辨率提供多个图像选项,优化加载的图片以适应设备的屏幕大小和分辨率。这提高了性能和用户体验。 示例: <img src"default.jpg" srcset"small.jpg 480w, medium.j…...

Ansible自动化一键部署单节点集群架构
自动化部署利器:Ansible 一键部署脚本 在现代IT基础设施管理中,Ansible以其简洁、强大的自动化能力脱颖而出。以下是精心打造的Ansible自动化一键部署脚本,旨在简化部署流程,提升效率,确保一致性和可靠性。 通过这个…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...

一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...
初级程序员入门指南
初级程序员入门指南 在数字化浪潮中,编程已然成为极具价值的技能。对于渴望踏入程序员行列的新手而言,明晰入门路径与必备知识是开启征程的关键。本文将为初级程序员提供全面的入门指引。 一、明确学习方向 (一)编程语言抉择 编…...