Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xindoo
redis
提交
bb7dcc1e
R
redis
项目概览
xindoo
/
redis
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bb7dcc1e
编写于
4月 08, 2009
作者:
L
Ludovico Magnocavallo
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix decode bug, add flush and info commands
上级
ce7bef07
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
108 addition
and
104 deletion
+108
-104
client-libraries/php/redis.php
client-libraries/php/redis.php
+93
-97
client-libraries/php/tests.php
client-libraries/php/tests.php
+15
-7
未找到文件。
client-libraries/php/redis.php
浏览文件 @
bb7dcc1e
...
@@ -19,7 +19,7 @@ class Redis {
...
@@ -19,7 +19,7 @@ class Redis {
var
$port
;
var
$port
;
var
$_sock
;
var
$_sock
;
function
Redis
(
$host
,
$port
=
6379
)
{
function
Redis
(
$host
=
'localhost'
,
$port
=
6379
)
{
$this
->
host
=
$host
;
$this
->
host
=
$host
;
$this
->
port
=
$port
;
$this
->
port
=
$port
;
}
}
...
@@ -46,7 +46,7 @@ class Redis {
...
@@ -46,7 +46,7 @@ class Redis {
function
&
ping
()
{
function
&
ping
()
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"PING
\r\n
"
);
$this
->
_write
(
"PING
\r\n
"
);
return
$this
->
_simple
_response
();
return
$this
->
get
_response
();
}
}
function
&
do_echo
(
$s
)
{
function
&
do_echo
(
$s
)
{
...
@@ -61,7 +61,7 @@ class Redis {
...
@@ -61,7 +61,7 @@ class Redis {
(
$preserve
?
'SETNX'
:
'SET'
)
.
(
$preserve
?
'SETNX'
:
'SET'
)
.
"
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
"
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
);
return
$
preserve
?
$this
->
_numeric_response
()
:
$this
->
_simple
_response
();
return
$
this
->
get
_response
();
}
}
function
&
get
(
$name
)
{
function
&
get
(
$name
)
{
...
@@ -76,7 +76,7 @@ class Redis {
...
@@ -76,7 +76,7 @@ class Redis {
$this
->
_write
(
"INCR
$name
\r\n
"
);
$this
->
_write
(
"INCR
$name
\r\n
"
);
else
else
$this
->
_write
(
"INCRBY
$name
$amount
\r\n
"
);
$this
->
_write
(
"INCRBY
$name
$amount
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
decr
(
$name
,
$amount
=
1
)
{
function
&
decr
(
$name
,
$amount
=
1
)
{
...
@@ -85,19 +85,19 @@ class Redis {
...
@@ -85,19 +85,19 @@ class Redis {
$this
->
_write
(
"DECR
$name
\r\n
"
);
$this
->
_write
(
"DECR
$name
\r\n
"
);
else
else
$this
->
_write
(
"DECRBY
$name
$amount
\r\n
"
);
$this
->
_write
(
"DECRBY
$name
$amount
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
exists
(
$name
)
{
function
&
exists
(
$name
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"EXISTS
$name
\r\n
"
);
$this
->
_write
(
"EXISTS
$name
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
delete
(
$name
)
{
function
&
delete
(
$name
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"DEL
$name
\r\n
"
);
$this
->
_write
(
"DEL
$name
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
keys
(
$pattern
)
{
function
&
keys
(
$pattern
)
{
...
@@ -109,19 +109,13 @@ class Redis {
...
@@ -109,19 +109,13 @@ class Redis {
function
&
randomkey
()
{
function
&
randomkey
()
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"RANDOMKEY
\r\n
"
);
$this
->
_write
(
"RANDOMKEY
\r\n
"
);
$s
=&
trim
(
$this
->
_read
());
return
$this
->
get_response
();
$this
->
_check_for_error
(
$s
);
return
$s
;
}
}
function
&
rename
(
$src
,
$dst
,
$preserve
=
False
)
{
function
&
rename
(
$src
,
$dst
,
$preserve
=
False
)
{
$this
->
connect
();
$this
->
connect
();
if
(
$preserve
)
{
$this
->
_write
(
$preserve
?
"RENAMENX
$src
$dst
\r\n
"
:
"RENAME
$src
$dst
\r\n
"
);
$this
->
_write
(
"RENAMENX
$src
$dst
\r\n
"
);
return
$this
->
get_response
();
return
$this
->
_numeric_response
();
}
$this
->
_write
(
"RENAME
$src
$dst
\r\n
"
);
return
trim
(
$this
->
_simple_response
());
}
}
function
&
push
(
$name
,
$value
,
$tail
=
true
)
{
function
&
push
(
$name
,
$value
,
$tail
=
true
)
{
...
@@ -131,13 +125,13 @@ class Redis {
...
@@ -131,13 +125,13 @@ class Redis {
(
$tail
?
'RPUSH'
:
'LPUSH'
)
.
(
$tail
?
'RPUSH'
:
'LPUSH'
)
.
"
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
"
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
);
return
$this
->
_simple
_response
();
return
$this
->
get
_response
();
}
}
function
&
ltrim
(
$name
,
$start
,
$end
)
{
function
&
ltrim
(
$name
,
$start
,
$end
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"LTRIM
$name
$start
$end
\r\n
"
);
$this
->
_write
(
"LTRIM
$name
$start
$end
\r\n
"
);
return
$this
->
_simple
_response
();
return
$this
->
get
_response
();
}
}
function
&
lindex
(
$name
,
$index
)
{
function
&
lindex
(
$name
,
$index
)
{
...
@@ -158,95 +152,112 @@ class Redis {
...
@@ -158,95 +152,112 @@ class Redis {
function
&
llen
(
$name
)
{
function
&
llen
(
$name
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"LLEN
$name
\r\n
"
);
$this
->
_write
(
"LLEN
$name
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
lrange
(
$name
,
$start
,
$end
)
{
function
&
lrange
(
$name
,
$start
,
$end
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"LRANGE
$name
$start
$end
\r\n
"
);
$this
->
_write
(
"LRANGE
$name
$start
$end
\r\n
"
);
return
$this
->
_get_multi
();
return
$this
->
get_response
();
}
}
function
&
sort
(
$name
,
$query
=
false
)
{
function
&
sort
(
$name
,
$query
=
false
)
{
$this
->
connect
();
$this
->
connect
();
if
(
$query
===
false
)
{
$this
->
_write
(
$query
==
false
?
"SORT
$name
\r\n
"
:
"SORT
$name
$query
\r\n
"
);
$this
->
_write
(
"SORT
$name
\r\n
"
);
return
$this
->
get_response
();
}
else
{
$this
->
_write
(
"SORT
$name
$query
\r\n
"
);
}
return
$this
->
_get_multi
();
}
}
function
&
lset
(
$name
,
$value
,
$index
)
{
function
&
lset
(
$name
,
$value
,
$index
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"LSET
$name
$index
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
$this
->
_write
(
"LSET
$name
$index
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
return
$this
->
_simple
_response
();
return
$this
->
get
_response
();
}
}
function
&
sadd
(
$name
,
$value
)
{
function
&
sadd
(
$name
,
$value
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"SADD
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
$this
->
_write
(
"SADD
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
srem
(
$name
,
$value
)
{
function
&
srem
(
$name
,
$value
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"SREM
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
$this
->
_write
(
"SREM
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
sismember
(
$name
,
$value
)
{
function
&
sismember
(
$name
,
$value
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"SISMEMBER
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
$this
->
_write
(
"SISMEMBER
$name
"
.
strlen
(
$value
)
.
"
\r\n
$value
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
sinter
(
$sets
)
{
function
&
sinter
(
$sets
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
'SINTER '
.
implode
(
' '
,
$sets
)
.
"
\r\n
"
);
$this
->
_write
(
'SINTER '
.
implode
(
' '
,
$sets
)
.
"
\r\n
"
);
return
$this
->
_get_multi
();
return
$this
->
get_response
();
}
}
function
&
smembers
(
$name
)
{
function
&
smembers
(
$name
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"SMEMBERS
$name
\r\n
"
);
$this
->
_write
(
"SMEMBERS
$name
\r\n
"
);
return
$this
->
_get_multi
();
return
$this
->
get_response
();
}
}
function
&
scard
(
$name
)
{
function
&
scard
(
$name
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"SCARD
$name
\r\n
"
);
$this
->
_write
(
"SCARD
$name
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
select_db
(
$name
)
{
function
&
select_db
(
$name
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"SELECT
$name
\r\n
"
);
$this
->
_write
(
"SELECT
$name
\r\n
"
);
return
$this
->
_simple
_response
();
return
$this
->
get
_response
();
}
}
function
&
move
(
$name
,
$db
)
{
function
&
move
(
$name
,
$db
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"MOVE
$name
$db
\r\n
"
);
$this
->
_write
(
"MOVE
$name
$db
\r\n
"
);
return
$this
->
_numeric
_response
();
return
$this
->
get
_response
();
}
}
function
&
save
(
$background
=
false
)
{
function
&
save
(
$background
=
false
)
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
((
$background
?
"BGSAVE
\r\n
"
:
"SAVE
\r\n
"
));
$this
->
_write
((
$background
?
"BGSAVE
\r\n
"
:
"SAVE
\r\n
"
));
return
$this
->
_simple
_response
();
return
$this
->
get
_response
();
}
}
function
&
lastsave
()
{
function
&
lastsave
()
{
$this
->
connect
();
$this
->
connect
();
$this
->
_write
(
"LASTSAVE
\r\n
"
);
$this
->
_write
(
"LASTSAVE
\r\n
"
);
return
$this
->
_numeric_response
();
return
$this
->
get_response
();
}
function
&
flush
(
$all
=
false
)
{
$this
->
connect
();
$this
->
_write
(
$all
?
"FLUSH
\r\n
"
:
"FLUSHDB
\r\n
"
);
return
$this
->
get_response
();
}
function
&
info
()
{
$this
->
connect
();
$this
->
_write
(
"INFO
\r\n
"
);
$info
=
array
();
$data
=&
$this
->
get_response
();
foreach
(
explode
(
"
\r\n
"
,
$data
)
as
$l
)
{
if
(
!
$l
)
continue
;
list
(
$k
,
$v
)
=
explode
(
':'
,
$l
,
2
);
$_v
=
strpos
(
$v
,
'.'
)
!==
false
?
(
float
)
$v
:
(
int
)
$v
;
$info
[
$k
]
=
(
string
)
$_v
==
$v
?
$_v
:
$v
;
}
return
$info
;
}
}
function
&
_write
(
$s
)
{
function
&
_write
(
$s
)
{
while
(
$s
)
{
while
(
$s
)
{
$i
=
fwrite
(
$this
->
_sock
,
$s
);
$i
=
fwrite
(
$this
->
_sock
,
$s
);
if
(
$i
==
0
)
if
(
$i
==
0
)
// || $i == strlen($s))
break
;
break
;
$s
=
substr
(
$s
,
$i
);
$s
=
substr
(
$s
,
$i
);
}
}
...
@@ -259,72 +270,57 @@ class Redis {
...
@@ -259,72 +270,57 @@ class Redis {
trigger_error
(
"Cannot read from socket."
,
E_USER_ERROR
);
trigger_error
(
"Cannot read from socket."
,
E_USER_ERROR
);
}
}
function
_check_for_error
(
&
$s
)
{
function
&
get_response
()
{
if
(
!
$s
||
$s
[
0
]
!=
'-'
)
$data
=
trim
(
$this
->
_read
());
return
;
$c
=
$data
[
0
];
if
(
substr
(
$s
,
0
,
4
)
==
'-ERR'
)
$data
=
substr
(
$data
,
1
);
trigger_error
(
"Redis error: "
.
trim
(
substr
(
$s
,
4
)),
E_USER_ERROR
);
switch
(
$c
)
{
trigger_error
(
"Redis error: "
.
substr
(
trim
(
$this
->
_read
()),
5
),
E_USER_ERROR
);
case
'-'
:
}
trigger_error
(
substr
(
$data
,
0
,
4
)
==
'ERR '
?
substr
(
$data
,
4
)
:
$data
,
E_USER_ERROR
);
break
;
function
&
_simple_response
()
{
case
'+'
:
$s
=&
trim
(
$this
->
_read
());
return
$data
;
if
(
$s
[
0
]
==
'+'
)
case
'*'
:
return
substr
(
$s
,
1
);
$num
=
(
int
)
$data
;
if
(
$err
=&
$this
->
_check_for_error
(
$s
))
if
((
string
)
$num
!=
$data
)
return
$err
;
trigger_error
(
"Cannot convert multi-response header '
$data
' to integer"
,
E_USER_ERROR
);
trigger_error
(
"Cannot parse first line '
$s
' for a simple response"
,
E_USER_ERROR
);
$result
=
array
();
}
for
(
$i
=
0
;
$i
<
$num
;
$i
++
)
$result
[]
=&
$this
->
_get_value
();
function
&
_numeric_response
(
$allow_negative
=
True
)
{
return
$result
;
$s
=&
trim
(
$this
->
_read
());
default
:
$i
=
(
int
)
$s
;
return
$this
->
_get_value
(
$c
.
$data
);
if
(
$i
.
''
==
$s
)
{
if
(
!
$allow_negative
&&
$i
<
0
)
$this
->
_check_for_error
(
$s
);
return
$i
;
}
}
if
(
$s
==
'nil'
)
}
function
&
_get_value
(
$data
=
null
)
{
if
(
$data
===
null
)
$data
=&
trim
(
$this
->
_read
());
if
(
$data
==
'$-1'
)
return
null
;
return
null
;
trigger_error
(
"Cannot parse '
$s
' as numeric response."
);
$c
=
$data
[
0
];
}
$data
=
substr
(
$data
,
1
);
$i
=
strpos
(
$data
,
'.'
)
!==
false
?
(
int
)
$data
:
(
float
)
$data
;
function
&
_get_value
()
{
if
((
string
)
$i
!=
$data
)
$s
=&
trim
(
$this
->
_read
());
trigger_error
(
"Cannot convert data '
$c$data
' to integer"
,
E_USER_ERROR
);
if
(
$s
==
'nil'
)
if
(
$c
==
':'
)
return
''
;
return
$i
;
else
if
(
$s
[
0
]
==
'-'
)
if
(
$c
!=
'$'
)
$this
->
_check_for_error
(
$s
);
trigger_error
(
"Unkown response prefix for '
$c$data
'"
,
E_USER_ERROR
);
$i
=
(
int
)
$s
;
if
(
$i
.
''
!=
$s
)
trigger_error
(
"Cannot parse '
$s
' as data length."
);
$buffer
=
''
;
$buffer
=
''
;
while
(
$i
>
0
)
{
while
(
true
)
{
$s
=
$this
->
_read
();
$data
=&
$this
->
_read
();
$l
=
strlen
(
$s
);
$i
-=
strlen
(
$data
);
$i
-=
$l
;
$buffer
.
=
$data
;
if
(
$l
>
$i
)
// ending crlf
if
(
$i
<
0
)
$s
=
rtrim
(
$s
);
break
;
$buffer
.
=
$s
;
}
if
(
$i
==
0
)
// let's restore the trailing crlf
$buffer
.
=
$this
->
_read
();
return
$buffer
;
}
function
&
_get_multi
()
{
$results
=
array
();
$num
=&
$this
->
_numeric_response
(
false
);
if
(
$num
===
false
)
return
$results
;
while
(
$num
)
{
$results
[]
=&
$this
->
_get_value
();
$num
-=
1
;
}
}
return
$results
;
return
substr
(
$buffer
,
0
,
-
2
)
;
}
}
}
}
//$r =& new Redis();
//var_dump($r->info());
?>
?>
client-libraries/php/tests.php
浏览文件 @
bb7dcc1e
...
@@ -6,6 +6,8 @@ require_once('redis.php');
...
@@ -6,6 +6,8 @@ require_once('redis.php');
$r
=&
new
Redis
(
'localhost'
);
$r
=&
new
Redis
(
'localhost'
);
$r
->
connect
();
$r
->
connect
();
$r
->
select_db
(
9
);
$r
->
flush
();
echo
$r
->
ping
()
.
"
\n
"
;
echo
$r
->
ping
()
.
"
\n
"
;
echo
$r
->
do_echo
(
'ECHO test'
)
.
"
\n
"
;
echo
$r
->
do_echo
(
'ECHO test'
)
.
"
\n
"
;
echo
"SET aaa "
.
$r
->
set
(
'aaa'
,
'bbb'
)
.
"
\n
"
;
echo
"SET aaa "
.
$r
->
set
(
'aaa'
,
'bbb'
)
.
"
\n
"
;
...
@@ -61,18 +63,24 @@ echo 'SREM s0 bbb ' . $r->srem('s0', 'bbb') . "\n";
...
@@ -61,18 +63,24 @@ echo 'SREM s0 bbb ' . $r->srem('s0', 'bbb') . "\n";
echo
'SINTER s0 s1 '
.
print_r
(
$r
->
sinter
(
array
(
's0'
,
's1'
)),
true
)
.
"
\n
"
;
echo
'SINTER s0 s1 '
.
print_r
(
$r
->
sinter
(
array
(
's0'
,
's1'
)),
true
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SELECT 1 '
.
$r
->
select_db
(
1
)
.
"
\n
"
;
echo
'SELECT 8 '
.
$r
->
select_db
(
8
)
.
"
\n
"
;
echo
'EXISTS s1 '
.
$r
->
exists
(
's1'
)
.
"
\n
"
;
if
(
$r
->
exists
(
's1'
))
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SELECT 9 '
.
$r
->
select_db
(
9
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SELECT 0 '
.
$r
->
select_db
(
0
)
.
"
\n
"
;
echo
'MOVE s1 8 '
.
$r
->
move
(
's1'
,
8
)
.
"
\n
"
;
echo
'EXISTS s1 '
.
$r
->
exists
(
's1'
)
.
"
\n
"
;
if
(
$r
->
exists
(
's1'
))
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SELECT 8 '
.
$r
->
select_db
(
8
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'MOVE s1 1 '
.
$r
->
move
(
's1'
,
1
)
.
"
\n
"
;
echo
'SELECT 9 '
.
$r
->
select_db
(
9
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SELECT 1 '
.
$r
->
select_db
(
1
)
.
"
\n
"
;
echo
'SMEMBERS s1 '
.
print_r
(
$r
->
smembers
(
's1'
),
true
)
.
"
\n
"
;
echo
'SELECT 0 '
.
$r
->
select_db
(
0
)
.
"
\n
"
;
echo
'SAVE '
.
$r
->
save
()
.
"
\n
"
;
echo
'SAVE '
.
$r
->
save
()
.
"
\n
"
;
echo
'BGSAVE '
.
$r
->
save
(
true
)
.
"
\n
"
;
echo
'BGSAVE '
.
$r
->
save
(
true
)
.
"
\n
"
;
echo
'LASTSAVE '
.
$r
->
lastsave
()
.
"
\n
"
;
echo
'LASTSAVE '
.
$r
->
lastsave
()
.
"
\n
"
;
echo
'INFO '
.
print_r
(
$r
->
info
())
.
"
\n
"
;
?>
?>
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录