设为首页 收藏本站
查看: 1761|回复: 0

[经验分享] TEA 加密解法,统一了C语言、Java与PHP的运算结果

[复制链接]

尚未签到

发表于 2015-8-25 07:34:29 | 显示全部楼层 |阅读模式
  去年PHP与Andriod终端通讯,想使用TEA加密,却发现Java实现的TEA只能由Java解密、PHP实现的TEA只能由PHP解密。这不是我们想要的。
  昨天中午有空,想起加密这回事,仔细研究了TEA算法,本人笨,经过十五个小时的摸索,终于实现了C语言、Java与32bit的PHP加密解密一致性。
  首先,来一段网上流行的C语言描述的TEA算法:



#include <stdint.h>
void encrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */
uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
for (i=0; i < 32; i++) {                       /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);  
}                                              /* end cycle */
v[0]=v0; v[1]=v1;
}
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
for (i=0; i<32; i++) {                         /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;                                   
}                                              /* end cycle */
v[0]=v0; v[1]=v1;
}
  这段代码出现在Wiki百科、百度百科,描述的就是TEA加密解密算法的核心。可惜,如果不加思考与分析,就使用这段代码,就完蛋了。因为这是一段错误的代码。
  TEA加密,就是使用一个128bit的密钥,对64bit的明文,经过16轮、32轮或64轮的运算,生成64bit的密文。下面是我修改过的代码:



#include <stdio.h>
#include <stdint.h>
void encrypt (uint32_t v[], uint32_t k[]) {
uint32_t v0=v[0], v1=v[1], sum=0, i;           /* set up */
uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
for (i=0; i < 32; i++) {                       /* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}                                              /* end cycle */
v[0]=v0; v[1]=v1;
}
void decrypt (uint32_t v[], uint32_t k[]) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
for (i=0; i<32; i++) {                         /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;                                   
}                                              /* end cycle */
v[0]=v0; v[1]=v1;
}
int main() {
uint32_t v[2] = {0x20, 0x10}, k[4] = {0x04, 0x03, 0x02, 0x01};
printf("Encrypt And Decrypt:\n");
printf("%08X%08X\n", v[0], v[1]);
encrypt(v, k);
printf("%08X%08X\n", v[0], v[1]);
decrypt(v, k);
printf("%08X%08X\n", v[0], v[1]);
printf("Key:\n");
printf("%08X%08X%08X%08X\n", k[0], k[1], k[2], k[3]);
return 0;
}
  相对于C语言,Java显示非常臃肿,可能是本人Java水平太次了,只能写成这样子了。下面是Java的实现:



/**
* @author: heiing 2013-01-20 01:20
*/
public class TEA {
public static byte[] encrypt(byte[] data, byte[] key) {
int data_len = data.length; // 数据的长度
if (data_len == 0) {
return new byte[] {};
}
TEA t = new TEA();
if (!t.setKey(key)) {
return new byte[] {};
}
int group_len = 8;
int residues = data_len % group_len; // 余数
int dlen = data_len - residues;
// 用于储存加密的密文,第一字节为余数的大小
int result_len = data_len + 1;
if (residues > 0) {
result_len += group_len - residues;
}
byte[] result = new byte[result_len];
result[0] = (byte)residues;
byte[] plain = new byte[group_len];
byte[] enc = new byte[group_len];
for (int i = 0; i < dlen; i += group_len) {
for (int j = 0; j < group_len; j++) {
plain[j] = data[i + j];
}
enc = t.encrypt_group(plain);
for (int k = 0; k < group_len; k++) {
result[i + k + 1] = enc[k];
}
}
if (residues > 0) {
for (int j = 0; j < residues; j++) {
plain[j] = data[dlen + j];
}
int padding = group_len - residues;
for (int j = 0; j < padding; j++) {
plain[residues + j] = (byte)0x00;
}
enc = t.encrypt_group(plain);
for (int k = 0; k < group_len; k++) {
result[dlen + k + 1] = enc[k];
}
}
return result;
}
public static byte[] decrypt(byte[] data, byte[] key) {
int group_len = 8;
if (data.length % group_len != 1) {
return new byte[] {};
}
TEA t = new TEA();
if (!t.setKey(key)) {
return new byte[] {};
}
int data_len = data.length - 1, dlen; // 数据的长度
int residues = (int)(data[0]); // 余数
if (residues > 0) {
dlen = data_len - group_len;
} else {
dlen = data_len;
}
byte[] result = new byte[dlen + residues];
byte[] dec = new byte[group_len];
byte[] enc = new byte[group_len];
for (int i = 0; i < dlen; i += group_len) {
for (int j = 0; j < group_len; j++) {
enc[j] = data[i + j + 1];
}
dec = t.decrypt_group(enc);
for (int k = 0; k < group_len; k++) {
result[i + k] = dec[k];
}
}
if (residues > 0) {
for (int j = 0; j < group_len; j++) {
enc[j] = data[dlen + j + 1];
}
dec = t.decrypt_group(enc);
for (int k = 0; k < residues; k++) {
result[dlen + k] = dec[k];
}
}
return result;
}
/**
* 设置密钥
* @param k 密钥
* @return 密钥长度为16个byte时, 设置密钥并返回true,否则返回false
*/
public boolean setKey(byte[] k) {
if (k.length != 16) {
return false;
}
k0 = bytes_to_uint32(new byte[] {k[0], k[1], k[2], k[3]});
k1 = bytes_to_uint32(new byte[] {k[4], k[5], k[6], k[7]});
k2 = bytes_to_uint32(new byte[] {k[8], k[9], k[10], k[11]});
k3 = bytes_to_uint32(new byte[] {k[12], k[13], k[14], k[15]});
return true;
}
/**
* 设置加密的轮数,默认为32轮
* @param loops 加密轮数
* @return 轮数为16、32、64时,返回true,否则返回false
*/
public boolean setLoops(int loops) {
switch (loops) {
case 16:
case 32:
case 64:
this.loops = loops;
return true;
}
return false;
}
private static long UINT32_MAX = 0xFFFFFFFFL;
private static long BYTE_1 = 0xFFL;
private static long BYTE_2 = 0xFF00L;
private static long BYTE_3 = 0xFF0000L;
private static long BYTE_4 = 0xFF000000L;
private static long delta = 0x9E3779B9L;
private long k0, k1, k2, k3;
private int loops = 32;
/**
* 加密一组明文
* @param v 需要加密的明文
* @return 返回密文
*/
private byte[] encrypt_group(byte[] v) {
long v0 = bytes_to_uint32(new byte[] {v[0], v[1], v[2], v[3]});
long v1 = bytes_to_uint32(new byte[] {v[4], v[5], v[6], v[7]});
long sum = 0L;
long v0_xor_1 = 0L, v0_xor_2 = 0L, v0_xor_3 = 0L;
long v1_xor_1 = 0L, v1_xor_2 = 0L, v1_xor_3 = 0L;
for (int i = 0; i < loops; i++) {
sum = toUInt32(sum + delta);
v0_xor_1 = toUInt32(toUInt32(v1 << 4) + k0);
v0_xor_2 = toUInt32(v1 + sum);
v0_xor_3 = toUInt32((v1 >> 5) + k1);
v0 = toUInt32(  v0 + toUInt32(v0_xor_1 ^ v0_xor_2 ^ v0_xor_3)  );
v1_xor_1 = toUInt32(toUInt32(v0 << 4) + k2);
v1_xor_2 = toUInt32(v0 + sum);
v1_xor_3 = toUInt32((v0 >> 5) + k3);
System.out.printf("%08X\t%08X\t%08X\t%08X\n", i, v0, v0 >> 5, k3);
v1 = toUInt32(  v1 + toUInt32(v1_xor_1 ^ v1_xor_2 ^ v1_xor_3)  );
}
byte[] b0 = long_to_bytes(v0, 4);
byte[] b1 = long_to_bytes(v1, 4);
return new byte[] {b0[0], b0[1], b0[2], b0[3], b1[0], b1[1], b1[2], b1[3]};
}
/**
* 解密一组密文
* @param v 要解密的密文
* @return 返回明文
*/
private byte[] decrypt_group(byte[] v) {
long v0 = bytes_to_uint32(new byte[] {v[0], v[1], v[2], v[3]});
long v1 = bytes_to_uint32(new byte[] {v[4], v[5], v[6], v[7]});
long sum = 0xC6EF3720L, tmp = 0L;
for (int i = 0; i < loops; i++) {
tmp = toUInt32(toUInt32(v0 << 4) + k2);
v1 = toUInt32(  v1 - toUInt32(tmp ^  toUInt32(v0 + sum) ^ toUInt32((v0 >> 5) + k3))  );
tmp = toUInt32(toUInt32(v1 << 4) + k0);
v0 = toUInt32(  v0 - toUInt32(tmp ^  toUInt32(v1 + sum) ^ toUInt32((v1 >> 5) + k1))  );
sum = toUInt32(sum - delta);
}
byte[] b0 = long_to_bytes(v0, 4);
byte[] b1 = long_to_bytes(v1, 4);
return new byte[] {b0[0], b0[1], b0[2], b0[3], b1[0], b1[1], b1[2], b1[3]};
}

/**
* 将 long 类型的 n 转为 byte 数组,如果 len 为 4,则只返回低32位的4个byte
* @param n 需要转换的long
* @param len 若为4,则只返回低32位的4个byte,否则返回8个byte
* @return 转换后byte数组
*/
private static byte[] long_to_bytes(long n, int len) {
byte a = (byte)((n & BYTE_4) >> 24);
byte b = (byte)((n & BYTE_3) >> 16);
byte c = (byte)((n & BYTE_2) >> 8);
byte d = (byte)(n & BYTE_1);
if (len == 4) {
return new byte[] {a, b, c, d};
}
byte ha = (byte)(n >> 56);
byte hb = (byte)((n >> 48) & BYTE_1);
byte hc = (byte)((n >> 40) & BYTE_1);
byte hd = (byte)((n >> 32) & BYTE_1);
return new byte[] {ha, hb, hc, hd, a, b, c, d};
}
/**
* 将4个byte转为 Unsigned Integer 32,以 long 形式返回
* @param bs 需要转换的字节
* @return 返回 long,高32位为0,低32位视为Unsigned Integer
*/
private static long bytes_to_uint32(byte[] bs) {
return ((bs[0]<<24) & BYTE_4) +
((bs[1]<<16) & BYTE_3) +
((bs[2]<<8)  & BYTE_2) +
(bs[3] & BYTE_1);
}
/**
* 将long的高32位清除,只保留低32位,低32位视为Unsigned Integer
* @param n 需要清除的long
* @return 返回高32位全为0的long
*/
private static long toUInt32(long n) {
return n & UINT32_MAX;
}

// -------------------------------------------------------
// 以下 是用于Debug的函数
// -------------------------------------------------------
private static void println_array(byte[] b) {
for (byte x : b) {
System.out.printf("%02X ", x);
}
System.out.println();
}
/*private static void println_array(long[] b) {
for (long x : b) {
System.out.printf("%016X ", x);
}
System.out.println();
}*/
private static void test() {
}
public static void main(String[] args) {
//        byte[] bs = new byte[] {(byte)0xFF, (byte)0xEE, (byte)0xDD, (byte)0xCC};
//        System.out.printf("%016X\n", bytes_to_uint32(bs));
//        System.out.println(bytes_to_uint32(bs));
//        
//        
TEA t = new TEA();
byte[] pnt = new byte[] {
0x00, 0x00, 0x00, 0x20,
0x00, 0x00, 0x00, 0x10
};
byte[] k = new byte[] {
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x01
};
t.setKey(k);
//        byte[] enc = t.encrypt(v, k);
//        byte[] dec = t.decrypt(enc, k);
byte[] enc = t.encrypt_group(pnt);
//byte[] enc = new byte[] {(byte) 0xC1, (byte) 0xC6, 0x48, 0x7A, (byte) 0x9E, 0x6F, (byte) 0xF2, 0x56};
byte[] dec = t.decrypt_group(enc);
//println_array(v_from_byte_to_long(new byte[]{ 0x7F, 0x1E, 0x55, 0x56, 0x32, 0x35, 0x65, 0x78 }));
//println_array(k_from_byte_to_long(new byte[]{ 0x7F, 0x1E, 0x55, 0x56, 0x32, 0x35, 0x65, 0x78, 0x6F, 0x1E, 0x55, 0x56, 0x32, 0x35, 0x65, 0x78 }));
//println_array(long_to_bytes((long)0x7E987654, 8));
//byte b = (byte)0xEF;
//println_array(new long[] { (b << 24) & 0xFF000000L } );
//println_array(new long[] {(byte)0xEF});
//        String[] plain = new String[32];
//        for (i = 0; i < 32; i++) {
//            plain = String.
//        }
//        byte[] pnt = "123".getBytes();
//        byte[] enc = encrypt(pnt, k);
//        byte[] dec = decrypt(enc, k);
        
System.out.println("Key:");
println_array(k);
System.out.println("Encrypt And Decrypt:");
println_array(pnt);
println_array(enc);
println_array(dec);
}
}
  如果安装的32bit的PHP的话,那么PHP的整数应该是比较蛋疼的,下面是PHP的实现:




/**
* @author: heiing 2013-01-20 03:55
*/
class TEA {
public static function encrypt($data, $key) {
$data_len = strlen($data);
if (0 == $data_len) {
return '';
}
$t = new TEA();
if (!$t->setKey($key)) {
return '';
}
$group_len = 8;
$residues = $data_len % $group_len;
if ($residues > 0) {
$pad_len = $group_len - $residues;
$data .= str_repeat("\0", $pad_len);
$data_len += $pad_len;
}
$result = array(chr($residues));
for ($i = 0; $i < $data_len; $i += $group_len) {
$result[] = $t->encrypt_group(substr($data, $i, $group_len));
}
return implode('', $result);
}
public static function decrypt($data, $key) {
$group_len = 8;
$data_len = strlen($data);
if ($data_len % $group_len != 1) {
return '';
}
$t = new TEA();
if (!$t->setKey($key)) {
return '';
}
$residues = ord($data{0});
$result = array();
for ($i = 1; $i < $data_len; $i += $group_len) {
$result[] = $t->decrypt_group(substr($data, $i, $group_len));
}
if ($residues > 0) {
$lastpos = count($result) - 1;
$result[$lastpos] = substr($result[$lastpos], 0, $residues);
}
return implode('', $result);
}
/**
* 设置密钥
* @param string $key 密钥
* @return boolean 密钥长度为16个byte时, 设置密钥并返回true,否则返回false
*/
public function setKey($key) {
if (strlen($key) != 16) {
return false;
}
$this->k0 = self::bytes_to_uint32(substr($key, 0, 4));
$this->k1 = self::bytes_to_uint32(substr($key, 4, 4));
$this->k2 = self::bytes_to_uint32(substr($key, 8, 4));
$this->k3 = self::bytes_to_uint32(substr($key, 12, 4));
return true;
}
/**
* 设置加密的轮数,默认为32轮
* @param int $loops 加密轮数
* @return boolean 轮数为16、32、64时,返回true,否则返回false
*/
public function setLoops($loops) {
switch ($loops) {
case 16:
case 32:
case 64:
$this->loops = $loops;
return true;
}
return false;
}
const UINT32_MAX = 0xFFFFFFFF;
const BYTE_1 = 0xFF;
const BYTE_2 = 0xFF00;
const BYTE_3 = 0xFF0000;
const BYTE_4 = 0xFF000000;
const RSHIFT_5 = 0x07FFFFFF;
const delta = 0x9E3779B9;
private $k0 = 0, $k1 = 0, $k2 = 0, $k3 = 0;
private $loops = 32;
/**
* 加密一组明文
* @param string $v 需要加密的明文
* @return string 返回密文
*/
private function encrypt_group($v) {
$v0 = self::bytes_to_uint32(substr($v, 0, 4));
$v1 = self::bytes_to_uint32(substr($v, 4));
$sum = 0;
for ($i = 0; $i < $this->loops; ++$i) {
$sum = self::toUInt32($sum + self::delta);
$v0_xor_1 = self::toUInt32(self::toUInt32($v1 << 4) + $this->k0);
$v0_xor_2 = self::toUInt32($v1 + $sum);
$v0_xor_3 = self::toUInt32(($v1 >> 5 & self::RSHIFT_5) + $this->k1);
$v0 = self::toUInt32( $v0 + self::toUInt32($v0_xor_1 ^ $v0_xor_2 ^ $v0_xor_3) );
$v1_xor_1 = self::toUInt32(self::toUInt32($v0 << 4) + $this->k2);
$v1_xor_2 = self::toUInt32($v0 + $sum);
$v1_xor_3 = self::toUInt32(($v0 >> 5 & self::RSHIFT_5) + $this->k3);
$v1 = self::toUInt32( $v1 + self::toUInt32($v1_xor_1 ^ $v1_xor_2 ^ $v1_xor_3) );
}
return self::long_to_bytes($v0, 4) . self::long_to_bytes($v1, 4);
}
/**
* 解密一组密文
* @param string $v 要解密的密文
* @return string 返回明文
*/
private function decrypt_group($v) {
$v0 = self::bytes_to_uint32(substr($v, 0, 4));
$v1 = self::bytes_to_uint32(substr($v, 4));
$sum = 0xC6EF3720;
for ($i = 0; $i < $this->loops; ++$i) {
$v1_xor_1 = self::toUInt32(self::toUInt32($v0 << 4) + $this->k2);
$v1_xor_2 = self::toUInt32($v0 + $sum);
$v1_xor_3 = self::toUInt32(($v0 >> 5 & self::RSHIFT_5) + $this->k3);
$v1 = self::toUInt32( $v1 - self::toUInt32($v1_xor_1 ^ $v1_xor_2 ^ $v1_xor_3) );
$v0_xor_1 = self::toUInt32(self::toUInt32($v1 << 4) + $this->k0);
$v0_xor_2 = self::toUInt32($v1 + $sum);
$v0_xor_3 = self::toUInt32(($v1 >> 5 & self::RSHIFT_5) + $this->k1);
$v0 = self::toUInt32( $v0 - self::toUInt32($v0_xor_1 ^ $v0_xor_2 ^ $v0_xor_3) );
$sum = self::toUInt32($sum - self::delta);
}
return self::long_to_bytes($v0, 4) . self::long_to_bytes($v1, 4);
}
/**
* 将 long 类型的 $n 转为 byte 数组,如果 len 为 4,则只返回低32位的4个byte
* @param int $n 需要转换的long
* @param int $len 若为4,则只返回低32位的4个byte,否则返回8个byte
* @return string 转换后byte数组
*/
private static function long_to_bytes($n, $len) {
$a = (self::BYTE_4 & $n) >> 24;
$b = (self::BYTE_3 & $n) >> 16;
$c = (self::BYTE_2 & $n) >> 8;
$d = self::BYTE_1 & $n;
$p4 = pack('CCCC', $a, $b, $c, $d);
if (4 == $len) {
return $p4;
}
return self::long_to_bytes($n >> 32, 4) . $p4;
}
/**
* 将4个byte转为 Unsigned Integer 32,以 long 形式返回
* @param string $bs 需要转换的字节
* @return int 返回 long
*/
private static function bytes_to_uint32($bs) {
$a = (0xFFFFFFFF & ord($bs{0})) << 24;
$b = (0xFFFFFFFF & ord($bs{1})) << 16;
$c = (0xFFFFFFFF & ord($bs{2})) << 8;
$d = ord($bs{3});
return $a + $b + $c + $d;
}
/**
* 将long的高32位清除,只保留低32位,低32位视为Unsigned Integer
* @param int $n 需要清除的long
* @return int 返回高32位全为0的long
*/
private static function toUInt32($n) {
return $n & self::UINT32_MAX;
}
// -------------------------------------------------------
// 以下 是用于Debug的函数
// -------------------------------------------------------
public static function printx($s) {
$l = strlen($s);
for($i = 0; $i < $l; ++$i) {
printf('%1$02X ', ord($s{$i}));
}
echo "\n";
}
public static function main() {
echo "\n---------start---------\n";
$zero = str_repeat(chr(0), 3);
$key = $zero . chr(4) . $zero . chr(3) . $zero . chr(2) . $zero . chr(1);
$pnt = $zero . chr(0x20) . $zero . chr(0x10);
$t = new TEA();
$t->setKey($key);
$enc = $t->encrypt_group($pnt);
$dec = $t->decrypt_group($enc);
//        $pnt = '123';
//        $enc = TEA::encrypt($pnt, $key);
//        $dec = TEA::decrypt($enc, $key);
printf("Key:\n");
self::printx($key);
printf("Encrypt And Decrypt:\n");
self::printx($pnt);
self::printx($enc);
self::printx($dec);
/*//printf('%1$0X ', 0x9E3779B9);
printf('%1$0X ', self::toUInt32( self::bytes_to_uint32(chr(0xFF) . chr(0xEE) . chr(0xDD) . chr(0xCC)) * 2));
echo "\n";
self::printx(self::long_to_bytes(0x12345678, 4));
self::printx(self::long_to_bytes(0x98, 4));*/
}
}
  经过这一次实践,造成不同语言的加密结果不一致的原因是整数类型的不一致。TEA要求使用32位无符号整数进行运算,而Java与PHP的没有无符号的整数,Java可以使用Long来兼容,而32位的PHP就稍为麻烦一些,在位运算时需要特别留意。Java要注意的是需要使用L后缀来表示一个Long型常量,比如 delta,一不小心就成了负的整数。32位的PHP在右移时,很容易把符号位称过来,又成了负数,因此右移5位时,需要0x07FFFFFF来修正。
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-103737-1-1.html 上篇帖子: PHP开发之MVC架构 下篇帖子: asp.net 连php soap 出了一个怪问题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表