118 changed files with 14906 additions and 0 deletions
@ -0,0 +1,9 @@ |
|||
{ |
|||
"require": { |
|||
"yansongda/pay": "^2.8", |
|||
"overtrue/wechat": "~4.0", |
|||
"qiniu/php-sdk": "^7.2", |
|||
"workerman/workerman": "^4.0", |
|||
"workerman/mysql": "^1.0" |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
|
After Width: | Height: | Size: 62 KiB |
@ -0,0 +1,11 @@ |
|||
<?php |
|||
global $_W; |
|||
pdo_query("CREATE TABLE IF NOT EXISTS " . tablename('wlmerchant_setting') . " ( |
|||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT, |
|||
`uniacid` int(11) NOT NULL, |
|||
`plugin` varchar(200) NOT NULL, |
|||
`key` varchar(64) NOT NULL, |
|||
`value` text NOT NULL, |
|||
PRIMARY KEY (`id`) |
|||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;"); |
|||
?> |
|||
@ -0,0 +1,40 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<manifest xmlns="http://www.we7.cc" versionCode="1.0"> |
|||
<application setting="false"> |
|||
<name><![CDATA[智慧城市同城V4]]></name> |
|||
<identifie><![CDATA[weliam_smartcity]]></identifie> |
|||
<version><![CDATA[1.0.40]]></version> |
|||
<type><![CDATA[biz]]></type> |
|||
<ability><![CDATA[智慧城市同城V4]]></ability> |
|||
<description><![CDATA[智慧城市同城V4]]></description> |
|||
<author> <![CDATA[微连科技]]></author> |
|||
<url><![CDATA[http://bbs.we7.cc/]]></url> |
|||
</application> |
|||
<platform> |
|||
<subscribes> |
|||
<message type="subscribe"></message> |
|||
</subscribes> |
|||
<handles> |
|||
<message type="text" /> |
|||
<message type="image" /> |
|||
<message type="voice" /> |
|||
<message type="location" /> |
|||
<message type="subscribe" /> |
|||
<message type="qr" /> |
|||
<message type="trace" /> |
|||
<message type="click" /> |
|||
</handles> |
|||
<supports> |
|||
<item type="app" ></item> |
|||
</supports> |
|||
<rule embed="false" /> |
|||
<card embed="false" /> |
|||
</platform> |
|||
<bindings> |
|||
</bindings> |
|||
<permissions> |
|||
</permissions> |
|||
<install><![CDATA[install.php]]></install> |
|||
<uninstall><![CDATA[]]></uninstall> |
|||
<upgrade><![CDATA[]]></upgrade> |
|||
</manifest> |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
defined('IN_IA') or exit('Access Denied'); |
|||
require_once __DIR__ . "/core/common/defines.php"; |
|||
require_once PATH_CORE . "common/autoload.php"; |
|||
Func_loader::core('global'); |
|||
|
|||
class Weliam_smartcityModule extends WeModule { |
|||
public function welcomeDisplay() { |
|||
global $_W, $_GPC; |
|||
header('location: ' . web_url('dashboard/dashboard/index')); |
|||
exit(); |
|||
} |
|||
} |
|||
class Weliam_smartcity1Module extends WeModule { |
|||
public function welcomeDisplay() { |
|||
global $_W, $_GPC; |
|||
header('location: ' . web_url('dashboard/dashboard/index')); |
|||
exit(); |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
<?php |
|||
defined('IN_IA') or exit('Access Denied'); |
|||
require_once __DIR__ . "/core/common/defines.php"; |
|||
require_once PATH_CORE . "common/autoload.php"; |
|||
require __DIR__ . "/vendor/autoload.php"; |
|||
Func_loader::core('global'); |
|||
|
|||
|
|||
class Weliam_smartcityModuleProcessor extends WeModuleProcessor { |
|||
|
|||
public function respond() { |
|||
global $_W; |
|||
$_W['wlsetting'] = Setting::wlsetting_load(); |
|||
$rule = pdo_fetch('select * from ' . tablename('rule') . ' where id=:id limit 1', array(':id' => $this->rule)); |
|||
if (empty($rule)) { |
|||
return false; |
|||
} |
|||
$message = $this->message; |
|||
$fansinfo = Member::wl_fans_info($message['from']); |
|||
$_W['wlmember'] = Member::wl_member_create($fansinfo, 'wechat'); |
|||
$_W['mid'] = $_W['wlmember']['id']; |
|||
$dotime = pdo_get('wlmerchant_member',array('id' => $_W['mid']),array('protime')); |
|||
$dotime = $dotime['protime']; |
|||
if(time() - 10 < $dotime){ |
|||
return false; |
|||
}else{ |
|||
pdo_update('wlmerchant_member',array('protime' => time()),array('id' => $_W['mid'])); |
|||
} |
|||
file_put_contents(PATH_DATA . "processor_qr.log", var_export($message, true) . PHP_EOL, FILE_APPEND); |
|||
|
|||
$names = explode(':', $rule['name']); |
|||
$plugin = (isset($names[1]) ? $names[1] : ''); |
|||
|
|||
if (!empty($plugin)) { |
|||
$plugin::Processor($message); |
|||
} |
|||
} |
|||
} |
|||
class Weliam_smartcity1ModuleProcessor extends WeModuleProcessor { |
|||
|
|||
public function respond() { |
|||
global $_W; |
|||
$_W['wlsetting'] = Setting::wlsetting_load(); |
|||
$rule = pdo_fetch('select * from ' . tablename('rule') . ' where id=:id limit 1', array(':id' => $this->rule)); |
|||
if (empty($rule)) { |
|||
return false; |
|||
} |
|||
$message = $this->message; |
|||
$fansinfo = Member::wl_fans_info($message['from']); |
|||
$_W['wlmember'] = Member::wl_member_create($fansinfo, 'wechat'); |
|||
$_W['mid'] = $_W['wlmember']['id']; |
|||
file_put_contents(PATH_DATA . "processor_qr.log", var_export($message, true) . PHP_EOL, FILE_APPEND); |
|||
|
|||
$names = explode(':', $rule['name']); |
|||
$plugin = (isset($names[1]) ? $names[1] : ''); |
|||
|
|||
if (!empty($plugin)) { |
|||
$plugin::Processor($message); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,373 @@ |
|||
<?php |
|||
defined('IN_IA') or exit('Access Denied'); |
|||
require_once __DIR__ . "/core/common/defines.php"; |
|||
require_once PATH_CORE . "common/autoload.php"; |
|||
Func_loader::core('global'); |
|||
|
|||
class Weliam_smartcityModuleReceiver extends WeModuleReceiver { |
|||
|
|||
public function receive() { |
|||
global $_W; |
|||
$_W['wlsetting'] = Setting::wlsetting_load(); |
|||
$message = $this->message; |
|||
$fansinfo = Member::wl_fans_info($message['from']); |
|||
$_W['wlmember'] = Member::wl_member_create($fansinfo, 'wechat'); |
|||
$_W['mid'] = $_W['wlmember']['id']; |
|||
$dotime = pdo_get('wlmerchant_member',array('id' => $_W['mid']),array('protime')); |
|||
$dotime = $dotime['protime']; |
|||
if(time() - 10 < $dotime){ |
|||
return false; |
|||
}else{ |
|||
pdo_update('wlmerchant_member',array('protime' => time()),array('id' => $_W['mid'])); |
|||
} |
|||
file_put_contents(PATH_DATA . "receiver_qr.log", var_export($message, true) . PHP_EOL, FILE_APPEND); |
|||
|
|||
if (!empty($message['scene'])) { |
|||
$name = pdo_getcolumn('qrcode', array('scene_str' => $message['scene'], 'uniacid' => $_W['uniacid']), 'name'); |
|||
$names = explode(':', $name); |
|||
$plugin = (isset($names[1]) ? $names[1] : ''); |
|||
if (!empty($plugin)) { |
|||
$plugin::Processor($message); |
|||
} |
|||
} else { |
|||
$scanrecord = pdo_fetch("SELECT cardid,scantime,type,url FROM " |
|||
. tablename('wlmerchant_halfcard_qrscan') |
|||
. " WHERE uniacid = {$_W['uniacid']} AND openid = '{$message['from']}' order by id desc"); |
|||
if (!empty($scanrecord) && ($scanrecord['scantime'] + 120) > time()) { |
|||
//一卡通实卡 |
|||
if (empty($scanrecord['type'])) { |
|||
$card = pdo_get('wlmerchant_halfcard_realcard', array('uniacid' => $_W['uniacid'], 'id' => $scanrecord['cardid'])); |
|||
if (!empty($card)) { |
|||
//一卡通未绑定 |
|||
if ($card['status'] == 1) { |
|||
$setting = Setting::wlsetting_read('halfcard'); |
|||
$imgurl = $setting['cardimg'] ? $setting['cardimg'] : URL_MODULE . 'plugin/halfcard/app/resource/images/cord-bg.jpg'; |
|||
$returnmess = array(array('title' => urlencode("点击立即激活此卡"), 'description' => urlencode('激活此卡'), 'picurl' => tomedia($imgurl), 'url' => app_url('halfcard/halfcard_app/realcard', array('cardsn' => $card['cardsn'], 'salt' => $card['salt'])))); |
|||
Weixinqrcode::send_news($returnmess, $message); |
|||
} |
|||
//一卡通已绑定 |
|||
if ($card['status'] == 2) { |
|||
Weixinqrcode::send_text('关注成功,请重新扫描二维码操作', $message); |
|||
} |
|||
//一卡通已禁止 |
|||
if ($card['status'] == 3) { |
|||
Weixinqrcode::send_text('抱歉,此卡已失效!', $message); |
|||
} |
|||
} |
|||
} else { |
|||
switch ($scanrecord['type']) { |
|||
case 'rush': |
|||
$rushgoods = Rush::getSingleActive($scanrecord['cardid'] , 'name,thumb'); |
|||
$title = $rushgoods['name']; |
|||
$imgurl = $rushgoods['thumb']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 1 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
$desc = '手快有,手慢无...'; |
|||
break; |
|||
case 'wlcoupon': |
|||
$wlCoupon = wlCoupon::getSingleCoupons($scanrecord['cardid'] , 'title,logo'); |
|||
$title = $wlCoupon['title']; |
|||
$imgurl = $wlCoupon['logo']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 5 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'wlfightgroup': |
|||
$group = Wlfightgroup::getSingleGood($scanrecord['cardid'] , 'name,logo'); |
|||
$title = $group['name']; |
|||
$imgurl = $group['logo']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 3 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'wlgroupdetail': |
|||
$group = pdo_get('wlmerchant_fightgroup_group' , ['id' => $scanrecord['cardid']] , ['goodsid']); |
|||
$goods = Wlfightgroup::getSingleGood($group['goodsid'] , 'name,logo'); |
|||
$title = $goods['name']; |
|||
$imgurl = $goods['logo']; |
|||
$url = h5_url('pages/subPages/group/assemble/assemble' , ['group_id' => $scanrecord['cardid']]); |
|||
break; |
|||
case 'groupon': |
|||
$groupon = pdo_get('wlmerchant_groupon_activity' , ['id' => $scanrecord['cardid']] , [ |
|||
'name' , |
|||
'thumb' |
|||
]); |
|||
$title = $groupon['name']; |
|||
$imgurl = $groupon['thumb']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 2 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'bargain': |
|||
$groupon = pdo_get('wlmerchant_bargain_activity' , ['id' => $scanrecord['cardid']] , [ |
|||
'name' , |
|||
'thumb' |
|||
]); |
|||
$title = $groupon['name']; |
|||
$imgurl = $groupon['thumb']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 7 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'helpBargain': |
|||
$bargainuser = pdo_get('wlmerchant_bargain_userlist' , ['id' => $scanrecord['cardid']] , ['activityid']); |
|||
$barActivity = pdo_get('wlmerchant_bargain_activity' , ['id' => $bargainuser['activityid']] , [ |
|||
'name' , |
|||
'thumb' |
|||
]); |
|||
$title = $barActivity['name']; |
|||
$imgurl = $barActivity['thumb']; |
|||
$desc = '邀您一起砍!'; |
|||
$url = h5_url('pages/subPages/bargin/barginDetail/barginDetail' , ['bargin_id' => $scanrecord['cardid']]); |
|||
break; |
|||
case 'payOnline': |
|||
$title = '在线买单'; |
|||
$url = h5_url('pages/subPages2/newBuyOrder/buyOrder' , ['sid' => $scanrecord['cardid']]); |
|||
break; |
|||
case 'distribution': |
|||
$base = Setting::wlsetting_read('distribution'); |
|||
$title = $base['gztitle'] ? $base['gztitle'] : '申请分销商'; |
|||
$imgurl = tomedia($base['gzthumb']); |
|||
$desc = $base['gzdesc']; |
|||
$url = h5_url('pages/subPages/dealer/apply/apply'); |
|||
break; |
|||
case 'draw': |
|||
$activity = pdo_get('wlmerchant_draw',array('id' => $scanrecord['cardid']),array('title','share_image')); |
|||
$title = $activity['title']; |
|||
$imgurl = tomedia($activity['share_image']); |
|||
$desc = '快来参与吧'; |
|||
$url = h5_url('pages/subPages2/drawGame/drawGame',['id'=>$scanrecord['cardid']]); |
|||
break; |
|||
case 'activity': |
|||
$activity = pdo_get('wlmerchant_activitylist',array('id' => $scanrecord['cardid']),array('title','share_image','thumb')); |
|||
$title = $activity['title']; |
|||
$imgurl = !empty($activity['share_image'])? tomedia($activity['share_image']) : tomedia($activity['thumb']); |
|||
$desc = '快来报名吧'; |
|||
$url = h5_url('pages/subPages2/coursegoods/coursegoods',['id'=>$scanrecord['cardid']]); |
|||
break; |
|||
case 'housekeep': |
|||
$activity = pdo_get('wlmerchant_housekeep_service',array('id' => $scanrecord['cardid']),array('title','share_image','thumb')); |
|||
$title = $activity['title']; |
|||
$imgurl = !empty($activity['share_image'])? tomedia($activity['share_image']) : tomedia($activity['thumb']); |
|||
$desc = '快来看看吧'; |
|||
$url = h5_url('pages/subPages2/homemaking/homemakingDetails/homemakingDetails',['id'=>$scanrecord['cardid']]); |
|||
break; |
|||
case 'mobilerecharge': |
|||
$title = '点击充值'; |
|||
$desc = '欢迎使用'.$_W['wlsetting']['base']['name']; |
|||
$imgurl = $_W['wlsetting']['mobilerecharge']['share_image']; |
|||
$url = h5_url('pages/subPages2/voucherCenter/voucherCenter'); |
|||
break; |
|||
case 'integral': |
|||
$goods = pdo_get('wlmerchant_consumption_goods',array('id' => $scanrecord['cardid']),array('title','thumb')); |
|||
$title = $goods['title']; |
|||
$desc = '快来兑换吧'; |
|||
$imgurl = tomedia($goods['thumb']); |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'goodsType' => 'integral', |
|||
'goods_id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
default: |
|||
$title = $_W['wlsetting']['base']['name']; |
|||
$desc = '欢迎使用' . $_W['wlsetting']['base']['name']; |
|||
$imgurl = $_W['wlsetting']['base']['logo']; |
|||
$url = $scanrecord['url'] ? : h5_url('pages/mainPages/index/index'); |
|||
break; |
|||
} |
|||
|
|||
//信息补充 |
|||
if(!$title) $title = $_W['wlsetting']['base']['name']; |
|||
if(!$desc) $desc = '欢迎使用'.$_W['wlsetting']['base']['name']; |
|||
if(!$imgurl) $imgurl = $_W['wlsetting']['base']['logo']; |
|||
if(!$url) $url = h5_url('pages/mainPages/index/index'); |
|||
|
|||
|
|||
$returnmess = array(array('title' => urlencode($title), 'description' => urlencode($desc), 'picurl' => tomedia($imgurl), 'url' => $url)); |
|||
Weixinqrcode::send_news($returnmess, $message); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
class Weliam_smartcity1ModuleReceiver extends WeModuleReceiver { |
|||
|
|||
public function receive() { |
|||
global $_W; |
|||
$_W['wlsetting'] = Setting::wlsetting_load(); |
|||
$message = $this->message; |
|||
$fansinfo = Member::wl_fans_info($message['from']); |
|||
$_W['wlmember'] = Member::wl_member_create($fansinfo, 'wechat'); |
|||
$_W['mid'] = $_W['wlmember']['id']; |
|||
file_put_contents(PATH_DATA . "receiver_qr.log", var_export($message, true) . PHP_EOL, FILE_APPEND); |
|||
|
|||
if (!empty($message['scene'])) { |
|||
$name = pdo_getcolumn('qrcode', array('scene_str' => $message['scene'], 'uniacid' => $_W['uniacid']), 'name'); |
|||
$names = explode(':', $name); |
|||
$plugin = (isset($names[1]) ? $names[1] : ''); |
|||
if (!empty($plugin)) { |
|||
$plugin::Processor($message); |
|||
} |
|||
} else { |
|||
$scanrecord = pdo_fetch("SELECT cardid,scantime,type,url FROM " |
|||
. tablename('wlmerchant_halfcard_qrscan') |
|||
. " WHERE uniacid = {$_W['uniacid']} AND openid = '{$message['from']}' order by id desc"); |
|||
if (!empty($scanrecord) && ($scanrecord['scantime'] + 120) > time()) { |
|||
//一卡通实卡 |
|||
if (empty($scanrecord['type'])) { |
|||
$card = pdo_get('wlmerchant_halfcard_realcard', array('uniacid' => $_W['uniacid'], 'id' => $scanrecord['cardid'])); |
|||
if (!empty($card)) { |
|||
//一卡通未绑定 |
|||
if ($card['status'] == 1) { |
|||
$setting = Setting::wlsetting_read('halfcard'); |
|||
$imgurl = $setting['cardimg'] ? $setting['cardimg'] : URL_MODULE . 'plugin/halfcard/app/resource/images/cord-bg.jpg'; |
|||
$returnmess = array(array('title' => urlencode("点击立即激活此卡"), 'description' => urlencode('激活此卡'), 'picurl' => tomedia($imgurl), 'url' => app_url('halfcard/halfcard_app/realcard', array('cardsn' => $card['cardsn'], 'salt' => $card['salt'])))); |
|||
Weixinqrcode::send_news($returnmess, $message); |
|||
} |
|||
//一卡通已绑定 |
|||
if ($card['status'] == 2) { |
|||
Weixinqrcode::send_text('关注成功,请重新扫描二维码操作', $message); |
|||
} |
|||
//一卡通已禁止 |
|||
if ($card['status'] == 3) { |
|||
Weixinqrcode::send_text('抱歉,此卡已失效!', $message); |
|||
} |
|||
} |
|||
} else { |
|||
switch ($scanrecord['type']) { |
|||
case 'rush': |
|||
$rushgoods = Rush::getSingleActive($scanrecord['cardid'] , 'name,thumb'); |
|||
$title = $rushgoods['name']; |
|||
$imgurl = $rushgoods['thumb']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 1 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
$desc = '手快有,手慢无...'; |
|||
break; |
|||
case 'wlcoupon': |
|||
$wlCoupon = wlCoupon::getSingleCoupons($scanrecord['cardid'] , 'title,logo'); |
|||
$title = $wlCoupon['title']; |
|||
$imgurl = $wlCoupon['logo']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 5 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'wlfightgroup': |
|||
$group = Wlfightgroup::getSingleGood($scanrecord['cardid'] , 'name,logo'); |
|||
$title = $group['name']; |
|||
$imgurl = $group['logo']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 3 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'wlgroupdetail': |
|||
$group = pdo_get('wlmerchant_fightgroup_group' , ['id' => $scanrecord['cardid']] , ['goodsid']); |
|||
$goods = Wlfightgroup::getSingleGood($group['goodsid'] , 'name,logo'); |
|||
$title = $goods['name']; |
|||
$imgurl = $goods['logo']; |
|||
$url = h5_url('pages/subPages/group/assemble/assemble' , ['group_id' => $scanrecord['cardid']]); |
|||
break; |
|||
case 'groupon': |
|||
$groupon = pdo_get('wlmerchant_groupon_activity' , ['id' => $scanrecord['cardid']] , [ |
|||
'name' , |
|||
'thumb' |
|||
]); |
|||
$title = $groupon['name']; |
|||
$imgurl = $groupon['thumb']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 2 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'bargain': |
|||
$groupon = pdo_get('wlmerchant_bargain_activity' , ['id' => $scanrecord['cardid']] , [ |
|||
'name' , |
|||
'thumb' |
|||
]); |
|||
$title = $groupon['name']; |
|||
$imgurl = $groupon['thumb']; |
|||
$url = h5_url('pages/subPages/goods/index' , [ |
|||
'type' => 7 , |
|||
'id' => $scanrecord['cardid'] |
|||
]); |
|||
break; |
|||
case 'helpBargain': |
|||
$bargainuser = pdo_get('wlmerchant_bargain_userlist' , ['id' => $scanrecord['cardid']] , ['activityid']); |
|||
$barActivity = pdo_get('wlmerchant_bargain_activity' , ['id' => $bargainuser['activityid']] , [ |
|||
'name' , |
|||
'thumb' |
|||
]); |
|||
$title = $barActivity['name']; |
|||
$imgurl = $barActivity['thumb']; |
|||
$desc = '邀您一起砍!'; |
|||
$url = h5_url('pages/subPages/bargin/barginDetail/barginDetail' , ['bargin_id' => $scanrecord['cardid']]); |
|||
break; |
|||
case 'payOnline': |
|||
$title = '在线买单'; |
|||
$url = h5_url('pages/subPages2/newBuyOrder/buyOrder' , ['sid' => $scanrecord['cardid']]); |
|||
break; |
|||
case 'distribution': |
|||
$base = Setting::wlsetting_read('distribution'); |
|||
$title = $base['gztitle'] ? $base['gztitle'] : '申请分销商'; |
|||
$imgurl = tomedia($base['gzthumb']); |
|||
$desc = $base['gzdesc']; |
|||
$url = h5_url('pages/subPages/dealer/apply/apply'); |
|||
break; |
|||
case 'draw': |
|||
$activity = pdo_get('wlmerchant_draw',array('id' => $scanrecord['cardid']),array('title','share_image')); |
|||
$title = $activity['title']; |
|||
$imgurl = tomedia($activity['share_image']); |
|||
$desc = '快来参与吧'; |
|||
$url = h5_url('pages/subPages2/drawGame/drawGame',['id'=>$scanrecord['cardid']]); |
|||
break; |
|||
case 'activity': |
|||
$activity = pdo_get('wlmerchant_activitylist',array('id' => $scanrecord['cardid']),array('title','share_image','thumb')); |
|||
$title = $activity['title']; |
|||
$imgurl = !empty($activity['share_image'])? tomedia($activity['share_image']) : tomedia($activity['thumb']); |
|||
$desc = '快来报名吧'; |
|||
$url = h5_url('pages/subPages2/coursegoods/coursegoods',['id'=>$scanrecord['cardid']]); |
|||
break; |
|||
case 'housekeep': |
|||
$activity = pdo_get('wlmerchant_housekeep_service',array('id' => $scanrecord['cardid']),array('title','share_image','thumb')); |
|||
$title = $activity['title']; |
|||
$imgurl = !empty($activity['share_image'])? tomedia($activity['share_image']) : tomedia($activity['thumb']); |
|||
$desc = '快来看看吧'; |
|||
$url = h5_url('pages/subPages2/homemaking/homemakingDetails/homemakingDetails',['id'=>$scanrecord['cardid']]); |
|||
break; |
|||
case 'mobilerecharge': |
|||
$title = '点击充值'; |
|||
$desc = '欢迎使用'.$_W['wlsetting']['base']['name']; |
|||
$imgurl = $_W['wlsetting']['mobilerecharge']['share_image']; |
|||
$url = h5_url('pages/subPages2/voucherCenter/voucherCenter'); |
|||
break; |
|||
default: |
|||
$title = $_W['wlsetting']['base']['name']; |
|||
$desc = '欢迎使用' . $_W['wlsetting']['base']['name']; |
|||
$imgurl = $_W['wlsetting']['base']['logo']; |
|||
$url = $scanrecord['url'] ? : h5_url('pages/mainPages/index/index'); |
|||
break; |
|||
} |
|||
|
|||
//信息补充 |
|||
if(!$title) $title = $_W['wlsetting']['base']['name']; |
|||
if(!$desc) $desc = '欢迎使用'.$_W['wlsetting']['base']['name']; |
|||
if(!$imgurl) $imgurl = $_W['wlsetting']['base']['logo']; |
|||
if(!$url) $url = h5_url('pages/mainPages/index/index'); |
|||
|
|||
|
|||
$returnmess = array(array('title' => urlencode($title), 'description' => urlencode($desc), 'picurl' => tomedia($imgurl), 'url' => $url)); |
|||
Weixinqrcode::send_news($returnmess, $message); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,174 @@ |
|||
<?php |
|||
defined('IN_IA') or exit('Access Denied'); |
|||
file_exists(__DIR__ . "/vendor/autoload.php") && require_once __DIR__ . "/vendor/autoload.php"; |
|||
require_once __DIR__ . "/core/common/defines.php"; |
|||
require_once PATH_CORE . "common/autoload.php"; |
|||
Func_loader::core('global'); |
|||
|
|||
class Weliam_smartcityModuleSite extends WeModuleSite { |
|||
|
|||
public function __call($name, $arguments) { |
|||
global $_W, $_GPC; |
|||
$isWeb = stripos($name, 'doWeb') === 0; |
|||
$isMobile = stripos($name, 'doMobile') === 0; |
|||
$_W['catalog'] = $catalog = !empty($isWeb) ? 'sys' : 'app'; |
|||
$_W['plugin'] = $plugin = !empty($_GPC['p']) ? $_GPC['p'] : 'dashboard'; |
|||
$_W['controller'] = $controller = !empty($_GPC['ac']) ? $_GPC['ac'] : 'dashboard'; |
|||
$_W['method'] = $method = !empty($_GPC['do']) ? $_GPC['do'] : 'index'; |
|||
$_W['wlsetting'] = Setting::wlsetting_load(); |
|||
$_W['wlsetting']['trade']['credittext'] = $_W['wlsetting']['trade']['credittext'] ? $_W['wlsetting']['trade']['credittext'] : '积分'; |
|||
$_W['wlsetting']['trade']['moneytext'] = $_W['wlsetting']['trade']['moneytext'] ? $_W['wlsetting']['trade']['moneytext'] : '余额'; |
|||
if (!in_array($_W['method'], array('qrcodeimg', 'Notify', 'captcha')) && !in_array($_W['controller'], array('wxapp')) && $_GPC['r'] != 'api') { |
|||
Func_loader::$catalog('cover'); |
|||
} |
|||
if ($isWeb || $isMobile) { |
|||
wl_new_method($plugin, $controller, $method, $_W['catalog']); |
|||
} |
|||
trigger_error("访问的模块 {$plugin} 不存在.", E_USER_WARNING); |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* Comment: 微信自动登录 |
|||
*/ |
|||
public function doMobileWechatsign() { |
|||
global $_W, $_GPC; |
|||
$auth_userinfo = mc_oauth_userinfo(); |
|||
if (empty($auth_userinfo['openid'])) { |
|||
die('授权信息获取失败,请退出重试'); |
|||
} |
|||
$userinfo = array( |
|||
'uid' => intval(mc_openid2uid($auth_userinfo['openid'])), |
|||
'openid' => $auth_userinfo['openid'], |
|||
'nickname' => $auth_userinfo['nickname'], |
|||
'unionid' => $auth_userinfo['unionid'], |
|||
'avatar' => $auth_userinfo['headimgurl'] |
|||
); |
|||
$member = Member::wl_member_create($userinfo, 'wechat'); |
|||
$backurl = h5_url(urldecode($_GPC['vueurl'])); |
|||
$token = pdo_getcolumn(PDO_NAME.'login',array('token'=>$member['tokey'],'refresh_time >' => time()),'secret_key'); |
|||
if(empty($token)) { |
|||
$res = Login::generateToken($member['tokey'], 'login'); |
|||
$token = $res['message']; |
|||
} |
|||
wl_setcookie('user_token',$token,86400); |
|||
$url = $backurl ? $backurl: h5_url('pages/subPages/userCenter'); |
|||
|
|||
echo "<script>window.location=\"" . $url . "\";</script>"; |
|||
exit; |
|||
} |
|||
|
|||
/** |
|||
* Comment: 通过分享链接进入平台时对链接的处理和跳转 |
|||
* Author: zzw |
|||
* Date: 2019/9/23 15:23 |
|||
*/ |
|||
public function doMobileReturnRequest() { |
|||
global $_W, $_GPC; |
|||
$link = $_GPC['link'] ?: h5_url('pages/mainPages/index/index'); |
|||
//链接转换操作 |
|||
$list = Links::getTransformationLink(); |
|||
foreach($list as $linkKey => $linkVal){ |
|||
$link = str_replace($linkKey,$linkVal,$link); |
|||
} |
|||
#1、判断link是否存在token信息,存在则删除 |
|||
$http = explode('?#', $link); |
|||
$linkArr = explode('?', $http[1]); |
|||
$paramsStr = $linkArr[1]; |
|||
$position = strpos($paramsStr, '&token=');//开始位置 |
|||
if ($position > 0) $linkArr[1] = substr($paramsStr, 0, $position) |
|||
. substr($paramsStr, 39 + strlen(substr($paramsStr, 0, $position)), strlen($paramsStr)); |
|||
$link = $http[0] . '?#' . $linkArr[0] . '?' . $linkArr[1]; |
|||
#2、规避head_id=undefined的参数 |
|||
$link = str_replace('&head_id=undefined', '', $link); |
|||
#3、跳转至分享链接 |
|||
|
|||
header('Location:' . $link); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
class Weliam_smartcity1ModuleSite extends WeModuleSite { |
|||
|
|||
public function __call($name, $arguments) { |
|||
global $_W, $_GPC; |
|||
$isWeb = stripos($name, 'doWeb') === 0; |
|||
$isMobile = stripos($name, 'doMobile') === 0; |
|||
$_W['catalog'] = $catalog = !empty($isWeb) ? 'sys' : 'app'; |
|||
$_W['plugin'] = $plugin = !empty($_GPC['p']) ? $_GPC['p'] : 'dashboard'; |
|||
$_W['controller'] = $controller = !empty($_GPC['ac']) ? $_GPC['ac'] : 'dashboard'; |
|||
$_W['method'] = $method = !empty($_GPC['do']) ? $_GPC['do'] : 'index'; |
|||
$_W['wlsetting'] = Setting::wlsetting_load(); |
|||
$_W['wlsetting']['trade']['credittext'] = $_W['wlsetting']['trade']['credittext'] ? $_W['wlsetting']['trade']['credittext'] : '积分'; |
|||
$_W['wlsetting']['trade']['moneytext'] = $_W['wlsetting']['trade']['moneytext'] ? $_W['wlsetting']['trade']['moneytext'] : '余额'; |
|||
if (!in_array($_W['method'], array('qrcodeimg', 'Notify', 'captcha')) && !in_array($_W['controller'], array('wxapp')) && $_GPC['r'] != 'api') { |
|||
Func_loader::$catalog('cover'); |
|||
} |
|||
if ($isWeb || $isMobile) { |
|||
wl_new_method($plugin, $controller, $method, $_W['catalog']); |
|||
} |
|||
trigger_error("访问的模块 {$plugin} 不存在.", E_USER_WARNING); |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* Comment: 微信自动登录 |
|||
*/ |
|||
public function doMobileWechatsign() { |
|||
global $_W, $_GPC; |
|||
$auth_userinfo = mc_oauth_userinfo(); |
|||
if (empty($auth_userinfo['openid'])) { |
|||
die('授权信息获取失败,请退出重试'); |
|||
} |
|||
$userinfo = array( |
|||
'uid' => intval(mc_openid2uid($auth_userinfo['openid'])), |
|||
'openid' => $auth_userinfo['openid'], |
|||
'nickname' => $auth_userinfo['nickname'], |
|||
'unionid' => $auth_userinfo['unionid'], |
|||
'avatar' => $auth_userinfo['headimgurl'] |
|||
); |
|||
$member = Member::wl_member_create($userinfo, 'wechat'); |
|||
$backurl = h5_url(urldecode($_GPC['vueurl'])); |
|||
$token = pdo_getcolumn(PDO_NAME.'login',array('token'=>$member['tokey'],'refresh_time >' => time()),'secret_key'); |
|||
if(empty($token)) { |
|||
$res = Login::generateToken($member['tokey'], 'login'); |
|||
$token = $res['message']; |
|||
} |
|||
wl_setcookie('user_token',$token,86400); |
|||
$url = $backurl ? $backurl: h5_url('pages/subPages/userCenter'); |
|||
|
|||
echo "<script>window.location=\"" . $url . "\";</script>"; |
|||
exit; |
|||
} |
|||
|
|||
/** |
|||
* Comment: 通过分享链接进入平台时对链接的处理和跳转 |
|||
* Author: zzw |
|||
* Date: 2019/9/23 15:23 |
|||
*/ |
|||
public function doMobileReturnRequest() { |
|||
global $_W, $_GPC; |
|||
$link = $_GPC['link'] ?: h5_url('pages/mainPages/index/index'); |
|||
//链接转换操作 |
|||
$list = Links::getTransformationLink(); |
|||
foreach($list as $linkKey => $linkVal){ |
|||
$link = str_replace($linkKey,$linkVal,$link); |
|||
} |
|||
#1、判断link是否存在token信息,存在则删除 |
|||
$http = explode('?#', $link); |
|||
$linkArr = explode('?', $http[1]); |
|||
$paramsStr = $linkArr[1]; |
|||
$position = strpos($paramsStr, '&token=');//开始位置 |
|||
if ($position > 0) $linkArr[1] = substr($paramsStr, 0, $position) |
|||
. substr($paramsStr, 39 + strlen(substr($paramsStr, 0, $position)), strlen($paramsStr)); |
|||
$link = $http[0] . '?#' . $linkArr[0] . '?' . $linkArr[1]; |
|||
#2、规避head_id=undefined的参数 |
|||
$link = str_replace('&head_id=undefined', '', $link); |
|||
#3、跳转至分享链接 |
|||
|
|||
header('Location:' . $link); |
|||
} |
|||
|
|||
|
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,96 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\EventDispatcher; |
|||
|
|||
use Psr\EventDispatcher\StoppableEventInterface; |
|||
|
|||
if (interface_exists(StoppableEventInterface::class)) { |
|||
/** |
|||
* Event is the base class for classes containing event data. |
|||
* |
|||
* This class contains no event data. It is used by events that do not pass |
|||
* state information to an event handler when an event is raised. |
|||
* |
|||
* You can call the method stopPropagation() to abort the execution of |
|||
* further listeners in your event listener. |
|||
* |
|||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> |
|||
* @author Jonathan Wage <jonwage@gmail.com> |
|||
* @author Roman Borschel <roman@code-factory.org> |
|||
* @author Bernhard Schussek <bschussek@gmail.com> |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
*/ |
|||
class Event implements StoppableEventInterface |
|||
{ |
|||
private $propagationStopped = false; |
|||
|
|||
/** |
|||
* Returns whether further event listeners should be triggered. |
|||
*/ |
|||
public function isPropagationStopped(): bool |
|||
{ |
|||
return $this->propagationStopped; |
|||
} |
|||
|
|||
/** |
|||
* Stops the propagation of the event to further event listeners. |
|||
* |
|||
* If multiple event listeners are connected to the same event, no |
|||
* further event listener will be triggered once any trigger calls |
|||
* stopPropagation(). |
|||
*/ |
|||
public function stopPropagation(): void |
|||
{ |
|||
$this->propagationStopped = true; |
|||
} |
|||
} |
|||
} else { |
|||
/** |
|||
* Event is the base class for classes containing event data. |
|||
* |
|||
* This class contains no event data. It is used by events that do not pass |
|||
* state information to an event handler when an event is raised. |
|||
* |
|||
* You can call the method stopPropagation() to abort the execution of |
|||
* further listeners in your event listener. |
|||
* |
|||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> |
|||
* @author Jonathan Wage <jonwage@gmail.com> |
|||
* @author Roman Borschel <roman@code-factory.org> |
|||
* @author Bernhard Schussek <bschussek@gmail.com> |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
*/ |
|||
class Event |
|||
{ |
|||
private $propagationStopped = false; |
|||
|
|||
/** |
|||
* Returns whether further event listeners should be triggered. |
|||
*/ |
|||
public function isPropagationStopped(): bool |
|||
{ |
|||
return $this->propagationStopped; |
|||
} |
|||
|
|||
/** |
|||
* Stops the propagation of the event to further event listeners. |
|||
* |
|||
* If multiple event listeners are connected to the same event, no |
|||
* further event listener will be triggered once any trigger calls |
|||
* stopPropagation(). |
|||
*/ |
|||
public function stopPropagation(): void |
|||
{ |
|||
$this->propagationStopped = true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\EventDispatcher; |
|||
|
|||
use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; |
|||
|
|||
if (interface_exists(PsrEventDispatcherInterface::class)) { |
|||
/** |
|||
* Allows providing hooks on domain-specific lifecycles by dispatching events. |
|||
*/ |
|||
interface EventDispatcherInterface extends PsrEventDispatcherInterface |
|||
{ |
|||
/** |
|||
* Dispatches an event to all registered listeners. |
|||
* |
|||
* For BC with Symfony 4, the $eventName argument is not declared explicitly on the |
|||
* signature of the method. Implementations that are not bound by this BC constraint |
|||
* MUST declare it explicitly, as allowed by PHP. |
|||
* |
|||
* @param object $event The event to pass to the event handlers/listeners |
|||
* @param string|null $eventName The name of the event to dispatch. If not supplied, |
|||
* the class of $event should be used instead. |
|||
* |
|||
* @return object The passed $event MUST be returned |
|||
*/ |
|||
public function dispatch($event/*, string $eventName = null*/); |
|||
} |
|||
} else { |
|||
/** |
|||
* Allows providing hooks on domain-specific lifecycles by dispatching events. |
|||
*/ |
|||
interface EventDispatcherInterface |
|||
{ |
|||
/** |
|||
* Dispatches an event to all registered listeners. |
|||
* |
|||
* For BC with Symfony 4, the $eventName argument is not declared explicitly on the |
|||
* signature of the method. Implementations that are not bound by this BC constraint |
|||
* MUST declare it explicitly, as allowed by PHP. |
|||
* |
|||
* @param object $event The event to pass to the event handlers/listeners |
|||
* @param string|null $eventName The name of the event to dispatch. If not supplied, |
|||
* the class of $event should be used instead. |
|||
* |
|||
* @return object The passed $event MUST be returned |
|||
*/ |
|||
public function dispatch($event/*, string $eventName = null*/); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2018-2019 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,9 @@ |
|||
Symfony EventDispatcher Contracts |
|||
================================= |
|||
|
|||
A set of abstractions extracted out of the Symfony components. |
|||
|
|||
Can be used to build on semantics that the Symfony components proved useful - and |
|||
that already have battle tested implementations. |
|||
|
|||
See https://github.com/symfony/contracts/blob/master/README.md for more information. |
|||
@ -0,0 +1,34 @@ |
|||
{ |
|||
"name": "symfony/event-dispatcher-contracts", |
|||
"type": "library", |
|||
"description": "Generic abstractions related to dispatching event", |
|||
"keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], |
|||
"homepage": "https://symfony.com", |
|||
"license": "MIT", |
|||
"authors": [ |
|||
{ |
|||
"name": "Nicolas Grekas", |
|||
"email": "p@tchwork.com" |
|||
}, |
|||
{ |
|||
"name": "Symfony Community", |
|||
"homepage": "https://symfony.com/contributors" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": "^7.1.3" |
|||
}, |
|||
"suggest": { |
|||
"psr/event-dispatcher": "", |
|||
"symfony/event-dispatcher-implementation": "" |
|||
}, |
|||
"autoload": { |
|||
"psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" } |
|||
}, |
|||
"minimum-stability": "dev", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.1-dev" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,283 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* Copyright (c) 2014 TrueServer B.V. |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is furnished |
|||
* to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in all |
|||
* copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
* |
|||
* Originally forked from |
|||
* https://github.com/true/php-punycode/blob/v2.1.1/src/Punycode.php |
|||
*/ |
|||
|
|||
namespace Symfony\Polyfill\Intl\Idn; |
|||
|
|||
/** |
|||
* Partial intl implementation in pure PHP. |
|||
* |
|||
* Implemented: |
|||
* - idn_to_ascii - Convert domain name to IDNA ASCII form |
|||
* - idn_to_utf8 - Convert domain name from IDNA ASCII to Unicode |
|||
* |
|||
* @author Renan Gonçalves <renan.saddam@gmail.com> |
|||
* @author Sebastian Kroczek <sk@xbug.de> |
|||
* @author Dmitry Lukashin <dmitry@lukashin.ru> |
|||
* @author Laurent Bassin <laurent@bassin.info> |
|||
* |
|||
* @internal |
|||
*/ |
|||
final class Idn |
|||
{ |
|||
const INTL_IDNA_VARIANT_2003 = 0; |
|||
const INTL_IDNA_VARIANT_UTS46 = 1; |
|||
|
|||
private static $encodeTable = array( |
|||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', |
|||
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', |
|||
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
|||
); |
|||
|
|||
private static $decodeTable = array( |
|||
'a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'e' => 4, 'f' => 5, |
|||
'g' => 6, 'h' => 7, 'i' => 8, 'j' => 9, 'k' => 10, 'l' => 11, |
|||
'm' => 12, 'n' => 13, 'o' => 14, 'p' => 15, 'q' => 16, 'r' => 17, |
|||
's' => 18, 't' => 19, 'u' => 20, 'v' => 21, 'w' => 22, 'x' => 23, |
|||
'y' => 24, 'z' => 25, '0' => 26, '1' => 27, '2' => 28, '3' => 29, |
|||
'4' => 30, '5' => 31, '6' => 32, '7' => 33, '8' => 34, '9' => 35, |
|||
); |
|||
|
|||
public static function idn_to_ascii($domain, $options, $variant, &$idna_info = array()) |
|||
{ |
|||
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) { |
|||
@trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED); |
|||
} |
|||
|
|||
if (self::INTL_IDNA_VARIANT_UTS46 === $variant) { |
|||
$domain = mb_strtolower($domain, 'utf-8'); |
|||
} |
|||
|
|||
$parts = explode('.', $domain); |
|||
|
|||
foreach ($parts as $i => &$part) { |
|||
if ('' === $part && \count($parts) > 1 + $i) { |
|||
return false; |
|||
} |
|||
if (false === $part = self::encodePart($part)) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
$output = implode('.', $parts); |
|||
|
|||
$idna_info = array( |
|||
'result' => \strlen($output) > 255 ? false : $output, |
|||
'isTransitionalDifferent' => false, |
|||
'errors' => 0, |
|||
); |
|||
|
|||
return $idna_info['result']; |
|||
} |
|||
|
|||
public static function idn_to_utf8($domain, $options, $variant, &$idna_info = array()) |
|||
{ |
|||
if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) { |
|||
@trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED); |
|||
} |
|||
|
|||
$parts = explode('.', $domain); |
|||
|
|||
foreach ($parts as &$part) { |
|||
$length = \strlen($part); |
|||
if ($length < 1 || 63 < $length) { |
|||
continue; |
|||
} |
|||
if (0 !== strpos($part, 'xn--')) { |
|||
continue; |
|||
} |
|||
|
|||
$part = substr($part, 4); |
|||
$part = self::decodePart($part); |
|||
} |
|||
|
|||
$output = implode('.', $parts); |
|||
|
|||
$idna_info = array( |
|||
'result' => \strlen($output) > 255 ? false : $output, |
|||
'isTransitionalDifferent' => false, |
|||
'errors' => 0, |
|||
); |
|||
|
|||
return $idna_info['result']; |
|||
} |
|||
|
|||
private static function encodePart($input) |
|||
{ |
|||
$codePoints = self::listCodePoints($input); |
|||
|
|||
$n = 128; |
|||
$bias = 72; |
|||
$delta = 0; |
|||
$h = $b = \count($codePoints['basic']); |
|||
|
|||
$output = ''; |
|||
foreach ($codePoints['basic'] as $code) { |
|||
$output .= mb_chr($code, 'utf-8'); |
|||
} |
|||
if ($input === $output) { |
|||
return $output; |
|||
} |
|||
if ($b > 0) { |
|||
$output .= '-'; |
|||
} |
|||
|
|||
$codePoints['nonBasic'] = array_unique($codePoints['nonBasic']); |
|||
sort($codePoints['nonBasic']); |
|||
|
|||
$i = 0; |
|||
$length = mb_strlen($input, 'utf-8'); |
|||
while ($h < $length) { |
|||
$m = $codePoints['nonBasic'][$i++]; |
|||
$delta += ($m - $n) * ($h + 1); |
|||
$n = $m; |
|||
|
|||
foreach ($codePoints['all'] as $c) { |
|||
if ($c < $n || $c < 128) { |
|||
++$delta; |
|||
} |
|||
if ($c === $n) { |
|||
$q = $delta; |
|||
for ($k = 36;; $k += 36) { |
|||
$t = self::calculateThreshold($k, $bias); |
|||
if ($q < $t) { |
|||
break; |
|||
} |
|||
|
|||
$code = $t + (($q - $t) % (36 - $t)); |
|||
$output .= self::$encodeTable[$code]; |
|||
|
|||
$q = ($q - $t) / (36 - $t); |
|||
} |
|||
|
|||
$output .= self::$encodeTable[$q]; |
|||
$bias = self::adapt($delta, $h + 1, ($h === $b)); |
|||
$delta = 0; |
|||
++$h; |
|||
} |
|||
} |
|||
|
|||
++$delta; |
|||
++$n; |
|||
} |
|||
|
|||
$output = 'xn--'.$output; |
|||
|
|||
return \strlen($output) < 1 || 63 < \strlen($output) ? false : strtolower($output); |
|||
} |
|||
|
|||
private static function listCodePoints($input) |
|||
{ |
|||
$codePoints = array( |
|||
'all' => array(), |
|||
'basic' => array(), |
|||
'nonBasic' => array(), |
|||
); |
|||
|
|||
$length = mb_strlen($input, 'utf-8'); |
|||
for ($i = 0; $i < $length; ++$i) { |
|||
$char = mb_substr($input, $i, 1, 'utf-8'); |
|||
$code = mb_ord($char, 'utf-8'); |
|||
if ($code < 128) { |
|||
$codePoints['all'][] = $codePoints['basic'][] = $code; |
|||
} else { |
|||
$codePoints['all'][] = $codePoints['nonBasic'][] = $code; |
|||
} |
|||
} |
|||
|
|||
return $codePoints; |
|||
} |
|||
|
|||
private static function calculateThreshold($k, $bias) |
|||
{ |
|||
if ($k <= $bias + 1) { |
|||
return 1; |
|||
} |
|||
if ($k >= $bias + 26) { |
|||
return 26; |
|||
} |
|||
|
|||
return $k - $bias; |
|||
} |
|||
|
|||
private static function adapt($delta, $numPoints, $firstTime) |
|||
{ |
|||
$delta = (int) ($firstTime ? $delta / 700 : $delta / 2); |
|||
$delta += (int) ($delta / $numPoints); |
|||
|
|||
$k = 0; |
|||
while ($delta > 35 * 13) { |
|||
$delta = (int) ($delta / 35); |
|||
$k = $k + 36; |
|||
} |
|||
|
|||
return $k + (int) (36 * $delta / ($delta + 38)); |
|||
} |
|||
|
|||
private static function decodePart($input) |
|||
{ |
|||
$n = 128; |
|||
$i = 0; |
|||
$bias = 72; |
|||
$output = ''; |
|||
|
|||
$pos = strrpos($input, '-'); |
|||
if (false !== $pos) { |
|||
$output = substr($input, 0, $pos++); |
|||
} else { |
|||
$pos = 0; |
|||
} |
|||
|
|||
$outputLength = \strlen($output); |
|||
$inputLength = \strlen($input); |
|||
|
|||
while ($pos < $inputLength) { |
|||
$oldi = $i; |
|||
$w = 1; |
|||
|
|||
for ($k = 36;; $k += 36) { |
|||
$digit = self::$decodeTable[$input[$pos++]]; |
|||
$i += $digit * $w; |
|||
$t = self::calculateThreshold($k, $bias); |
|||
|
|||
if ($digit < $t) { |
|||
break; |
|||
} |
|||
|
|||
$w *= 36 - $t; |
|||
} |
|||
|
|||
$bias = self::adapt($i - $oldi, ++$outputLength, 0 === $oldi); |
|||
$n = $n + (int) ($i / $outputLength); |
|||
$i = $i % $outputLength; |
|||
$output = mb_substr($output, 0, $i, 'utf-8').mb_chr($n, 'utf-8').mb_substr($output, $i, $outputLength - 1, 'utf-8'); |
|||
|
|||
++$i; |
|||
} |
|||
|
|||
return $output; |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2018-2019 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,12 @@ |
|||
Symfony Polyfill / Intl: Idn |
|||
============================ |
|||
|
|||
This component provides `idn_to_ascii` and `idn_to_utf8` functions to users who run php versions without the intl extension. |
|||
|
|||
More information can be found in the |
|||
[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). |
|||
|
|||
License |
|||
======= |
|||
|
|||
This library is released under the [MIT license](LICENSE). |
|||
@ -0,0 +1,59 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
use Symfony\Polyfill\Intl\Idn as p; |
|||
|
|||
if (!function_exists('idn_to_ascii')) { |
|||
define('U_IDNA_PROHIBITED_ERROR', 66560); |
|||
define('U_IDNA_ERROR_START', 66560); |
|||
define('U_IDNA_UNASSIGNED_ERROR', 66561); |
|||
define('U_IDNA_CHECK_BIDI_ERROR', 66562); |
|||
define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563); |
|||
define('U_IDNA_ACE_PREFIX_ERROR', 66564); |
|||
define('U_IDNA_VERIFICATION_ERROR', 66565); |
|||
define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566); |
|||
define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567); |
|||
define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568); |
|||
define('U_IDNA_ERROR_LIMIT', 66569); |
|||
define('U_STRINGPREP_PROHIBITED_ERROR', 66560); |
|||
define('U_STRINGPREP_UNASSIGNED_ERROR', 66561); |
|||
define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562); |
|||
define('IDNA_DEFAULT', 0); |
|||
define('IDNA_ALLOW_UNASSIGNED', 1); |
|||
define('IDNA_USE_STD3_RULES', 2); |
|||
define('IDNA_CHECK_BIDI', 4); |
|||
define('IDNA_CHECK_CONTEXTJ', 8); |
|||
define('IDNA_NONTRANSITIONAL_TO_ASCII', 16); |
|||
define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32); |
|||
define('INTL_IDNA_VARIANT_2003', 0); |
|||
define('INTL_IDNA_VARIANT_UTS46', 1); |
|||
define('IDNA_ERROR_EMPTY_LABEL', 1); |
|||
define('IDNA_ERROR_LABEL_TOO_LONG', 2); |
|||
define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4); |
|||
define('IDNA_ERROR_LEADING_HYPHEN', 8); |
|||
define('IDNA_ERROR_TRAILING_HYPHEN', 16); |
|||
define('IDNA_ERROR_HYPHEN_3_4', 32); |
|||
define('IDNA_ERROR_LEADING_COMBINING_MARK', 64); |
|||
define('IDNA_ERROR_DISALLOWED', 128); |
|||
define('IDNA_ERROR_PUNYCODE', 256); |
|||
define('IDNA_ERROR_LABEL_HAS_DOT', 512); |
|||
define('IDNA_ERROR_INVALID_ACE_LABEL', 1024); |
|||
define('IDNA_ERROR_BIDI', 2048); |
|||
define('IDNA_ERROR_CONTEXTJ', 4096); |
|||
|
|||
if (PHP_VERSION_ID < 70400) { |
|||
function idn_to_ascii($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_2003, &$idna_info = array()) { return p\Idn::idn_to_ascii($domain, $options, $variant, $idna_info); } |
|||
function idn_to_utf8($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_2003, &$idna_info = array()) { return p\Idn::idn_to_utf8($domain, $options, $variant, $idna_info); } |
|||
} else { |
|||
function idn_to_ascii($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) { return p\Idn::idn_to_ascii($domain, $options, $variant, $idna_info); } |
|||
function idn_to_utf8($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) { return p\Idn::idn_to_utf8($domain, $options, $variant, $idna_info); } |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
{ |
|||
"name": "symfony/polyfill-intl-idn", |
|||
"type": "library", |
|||
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", |
|||
"keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "idn"], |
|||
"homepage": "https://symfony.com", |
|||
"license": "MIT", |
|||
"authors": [ |
|||
{ |
|||
"name": "Laurent Bassin", |
|||
"email": "laurent@bassin.info" |
|||
}, |
|||
{ |
|||
"name": "Symfony Community", |
|||
"homepage": "https://symfony.com/contributors" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": ">=5.3.3", |
|||
"symfony/polyfill-mbstring": "^1.3", |
|||
"symfony/polyfill-php72": "^1.9" |
|||
}, |
|||
"autoload": { |
|||
"psr-4": { "Symfony\\Polyfill\\Intl\\Idn\\": "" }, |
|||
"files": [ "bootstrap.php" ] |
|||
}, |
|||
"suggest": { |
|||
"ext-intl": "For best performance" |
|||
}, |
|||
"minimum-stability": "dev", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.12-dev" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2015-2019 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,829 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Polyfill\Mbstring; |
|||
|
|||
/** |
|||
* Partial mbstring implementation in PHP, iconv based, UTF-8 centric. |
|||
* |
|||
* Implemented: |
|||
* - mb_chr - Returns a specific character from its Unicode code point |
|||
* - mb_convert_encoding - Convert character encoding |
|||
* - mb_convert_variables - Convert character code in variable(s) |
|||
* - mb_decode_mimeheader - Decode string in MIME header field |
|||
* - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED |
|||
* - mb_decode_numericentity - Decode HTML numeric string reference to character |
|||
* - mb_encode_numericentity - Encode character to HTML numeric string reference |
|||
* - mb_convert_case - Perform case folding on a string |
|||
* - mb_detect_encoding - Detect character encoding |
|||
* - mb_get_info - Get internal settings of mbstring |
|||
* - mb_http_input - Detect HTTP input character encoding |
|||
* - mb_http_output - Set/Get HTTP output character encoding |
|||
* - mb_internal_encoding - Set/Get internal character encoding |
|||
* - mb_list_encodings - Returns an array of all supported encodings |
|||
* - mb_ord - Returns the Unicode code point of a character |
|||
* - mb_output_handler - Callback function converts character encoding in output buffer |
|||
* - mb_scrub - Replaces ill-formed byte sequences with substitute characters |
|||
* - mb_strlen - Get string length |
|||
* - mb_strpos - Find position of first occurrence of string in a string |
|||
* - mb_strrpos - Find position of last occurrence of a string in a string |
|||
* - mb_str_split - Convert a string to an array |
|||
* - mb_strtolower - Make a string lowercase |
|||
* - mb_strtoupper - Make a string uppercase |
|||
* - mb_substitute_character - Set/Get substitution character |
|||
* - mb_substr - Get part of string |
|||
* - mb_stripos - Finds position of first occurrence of a string within another, case insensitive |
|||
* - mb_stristr - Finds first occurrence of a string within another, case insensitive |
|||
* - mb_strrchr - Finds the last occurrence of a character in a string within another |
|||
* - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive |
|||
* - mb_strripos - Finds position of last occurrence of a string within another, case insensitive |
|||
* - mb_strstr - Finds first occurrence of a string within another |
|||
* - mb_strwidth - Return width of string |
|||
* - mb_substr_count - Count the number of substring occurrences |
|||
* |
|||
* Not implemented: |
|||
* - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) |
|||
* - mb_ereg_* - Regular expression with multibyte support |
|||
* - mb_parse_str - Parse GET/POST/COOKIE data and set global variable |
|||
* - mb_preferred_mime_name - Get MIME charset string |
|||
* - mb_regex_encoding - Returns current encoding for multibyte regex as string |
|||
* - mb_regex_set_options - Set/Get the default options for mbregex functions |
|||
* - mb_send_mail - Send encoded mail |
|||
* - mb_split - Split multibyte string using regular expression |
|||
* - mb_strcut - Get part of string |
|||
* - mb_strimwidth - Get truncated string with specified width |
|||
* |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
final class Mbstring |
|||
{ |
|||
const MB_CASE_FOLD = PHP_INT_MAX; |
|||
|
|||
private static $encodingList = array('ASCII', 'UTF-8'); |
|||
private static $language = 'neutral'; |
|||
private static $internalEncoding = 'UTF-8'; |
|||
private static $caseFold = array( |
|||
array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"), |
|||
array('μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'), |
|||
); |
|||
|
|||
public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) |
|||
{ |
|||
if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) { |
|||
$fromEncoding = self::mb_detect_encoding($s, $fromEncoding); |
|||
} else { |
|||
$fromEncoding = self::getEncoding($fromEncoding); |
|||
} |
|||
|
|||
$toEncoding = self::getEncoding($toEncoding); |
|||
|
|||
if ('BASE64' === $fromEncoding) { |
|||
$s = base64_decode($s); |
|||
$fromEncoding = $toEncoding; |
|||
} |
|||
|
|||
if ('BASE64' === $toEncoding) { |
|||
return base64_encode($s); |
|||
} |
|||
|
|||
if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { |
|||
if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { |
|||
$fromEncoding = 'Windows-1252'; |
|||
} |
|||
if ('UTF-8' !== $fromEncoding) { |
|||
$s = iconv($fromEncoding, 'UTF-8//IGNORE', $s); |
|||
} |
|||
|
|||
return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s); |
|||
} |
|||
|
|||
if ('HTML-ENTITIES' === $fromEncoding) { |
|||
$s = html_entity_decode($s, ENT_COMPAT, 'UTF-8'); |
|||
$fromEncoding = 'UTF-8'; |
|||
} |
|||
|
|||
return iconv($fromEncoding, $toEncoding.'//IGNORE', $s); |
|||
} |
|||
|
|||
public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) |
|||
{ |
|||
$vars = array(&$a, &$b, &$c, &$d, &$e, &$f); |
|||
|
|||
$ok = true; |
|||
array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { |
|||
if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { |
|||
$ok = false; |
|||
} |
|||
}); |
|||
|
|||
return $ok ? $fromEncoding : false; |
|||
} |
|||
|
|||
public static function mb_decode_mimeheader($s) |
|||
{ |
|||
return iconv_mime_decode($s, 2, self::$internalEncoding); |
|||
} |
|||
|
|||
public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) |
|||
{ |
|||
trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING); |
|||
} |
|||
|
|||
public static function mb_decode_numericentity($s, $convmap, $encoding = null) |
|||
{ |
|||
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { |
|||
trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING); |
|||
|
|||
return null; |
|||
} |
|||
|
|||
if (!\is_array($convmap) || !$convmap) { |
|||
return false; |
|||
} |
|||
|
|||
if (null !== $encoding && !\is_scalar($encoding)) { |
|||
trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING); |
|||
|
|||
return ''; // Instead of null (cf. mb_encode_numericentity). |
|||
} |
|||
|
|||
$s = (string) $s; |
|||
if ('' === $s) { |
|||
return ''; |
|||
} |
|||
|
|||
$encoding = self::getEncoding($encoding); |
|||
|
|||
if ('UTF-8' === $encoding) { |
|||
$encoding = null; |
|||
if (!preg_match('//u', $s)) { |
|||
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|||
} |
|||
} else { |
|||
$s = iconv($encoding, 'UTF-8//IGNORE', $s); |
|||
} |
|||
|
|||
$cnt = floor(\count($convmap) / 4) * 4; |
|||
|
|||
for ($i = 0; $i < $cnt; $i += 4) { |
|||
// collector_decode_htmlnumericentity ignores $convmap[$i + 3] |
|||
$convmap[$i] += $convmap[$i + 2]; |
|||
$convmap[$i + 1] += $convmap[$i + 2]; |
|||
} |
|||
|
|||
$s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { |
|||
$c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; |
|||
for ($i = 0; $i < $cnt; $i += 4) { |
|||
if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { |
|||
return Mbstring::mb_chr($c - $convmap[$i + 2]); |
|||
} |
|||
} |
|||
|
|||
return $m[0]; |
|||
}, $s); |
|||
|
|||
if (null === $encoding) { |
|||
return $s; |
|||
} |
|||
|
|||
return iconv('UTF-8', $encoding.'//IGNORE', $s); |
|||
} |
|||
|
|||
public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) |
|||
{ |
|||
if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { |
|||
trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', E_USER_WARNING); |
|||
|
|||
return null; |
|||
} |
|||
|
|||
if (!\is_array($convmap) || !$convmap) { |
|||
return false; |
|||
} |
|||
|
|||
if (null !== $encoding && !\is_scalar($encoding)) { |
|||
trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', E_USER_WARNING); |
|||
|
|||
return null; // Instead of '' (cf. mb_decode_numericentity). |
|||
} |
|||
|
|||
if (null !== $is_hex && !\is_scalar($is_hex)) { |
|||
trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', E_USER_WARNING); |
|||
|
|||
return null; |
|||
} |
|||
|
|||
$s = (string) $s; |
|||
if ('' === $s) { |
|||
return ''; |
|||
} |
|||
|
|||
$encoding = self::getEncoding($encoding); |
|||
|
|||
if ('UTF-8' === $encoding) { |
|||
$encoding = null; |
|||
if (!preg_match('//u', $s)) { |
|||
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|||
} |
|||
} else { |
|||
$s = iconv($encoding, 'UTF-8//IGNORE', $s); |
|||
} |
|||
|
|||
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4); |
|||
|
|||
$cnt = floor(\count($convmap) / 4) * 4; |
|||
$i = 0; |
|||
$len = \strlen($s); |
|||
$result = ''; |
|||
|
|||
while ($i < $len) { |
|||
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; |
|||
$uchr = substr($s, $i, $ulen); |
|||
$i += $ulen; |
|||
$c = self::mb_ord($uchr); |
|||
|
|||
for ($j = 0; $j < $cnt; $j += 4) { |
|||
if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { |
|||
$cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; |
|||
$result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; |
|||
continue 2; |
|||
} |
|||
} |
|||
$result .= $uchr; |
|||
} |
|||
|
|||
if (null === $encoding) { |
|||
return $result; |
|||
} |
|||
|
|||
return iconv('UTF-8', $encoding.'//IGNORE', $result); |
|||
} |
|||
|
|||
public static function mb_convert_case($s, $mode, $encoding = null) |
|||
{ |
|||
$s = (string) $s; |
|||
if ('' === $s) { |
|||
return ''; |
|||
} |
|||
|
|||
$encoding = self::getEncoding($encoding); |
|||
|
|||
if ('UTF-8' === $encoding) { |
|||
$encoding = null; |
|||
if (!preg_match('//u', $s)) { |
|||
$s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); |
|||
} |
|||
} else { |
|||
$s = iconv($encoding, 'UTF-8//IGNORE', $s); |
|||
} |
|||
|
|||
if (MB_CASE_TITLE == $mode) { |
|||
static $titleRegexp = null; |
|||
if (null === $titleRegexp) { |
|||
$titleRegexp = self::getData('titleCaseRegexp'); |
|||
} |
|||
$s = preg_replace_callback($titleRegexp, array(__CLASS__, 'title_case'), $s); |
|||
} else { |
|||
if (MB_CASE_UPPER == $mode) { |
|||
static $upper = null; |
|||
if (null === $upper) { |
|||
$upper = self::getData('upperCase'); |
|||
} |
|||
$map = $upper; |
|||
} else { |
|||
if (self::MB_CASE_FOLD === $mode) { |
|||
$s = str_replace(self::$caseFold[0], self::$caseFold[1], $s); |
|||
} |
|||
|
|||
static $lower = null; |
|||
if (null === $lower) { |
|||
$lower = self::getData('lowerCase'); |
|||
} |
|||
$map = $lower; |
|||
} |
|||
|
|||
static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4); |
|||
|
|||
$i = 0; |
|||
$len = \strlen($s); |
|||
|
|||
while ($i < $len) { |
|||
$ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; |
|||
$uchr = substr($s, $i, $ulen); |
|||
$i += $ulen; |
|||
|
|||
if (isset($map[$uchr])) { |
|||
$uchr = $map[$uchr]; |
|||
$nlen = \strlen($uchr); |
|||
|
|||
if ($nlen == $ulen) { |
|||
$nlen = $i; |
|||
do { |
|||
$s[--$nlen] = $uchr[--$ulen]; |
|||
} while ($ulen); |
|||
} else { |
|||
$s = substr_replace($s, $uchr, $i - $ulen, $ulen); |
|||
$len += $nlen - $ulen; |
|||
$i += $nlen - $ulen; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (null === $encoding) { |
|||
return $s; |
|||
} |
|||
|
|||
return iconv('UTF-8', $encoding.'//IGNORE', $s); |
|||
} |
|||
|
|||
public static function mb_internal_encoding($encoding = null) |
|||
{ |
|||
if (null === $encoding) { |
|||
return self::$internalEncoding; |
|||
} |
|||
|
|||
$encoding = self::getEncoding($encoding); |
|||
|
|||
if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) { |
|||
self::$internalEncoding = $encoding; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function mb_language($lang = null) |
|||
{ |
|||
if (null === $lang) { |
|||
return self::$language; |
|||
} |
|||
|
|||
switch ($lang = strtolower($lang)) { |
|||
case 'uni': |
|||
case 'neutral': |
|||
self::$language = $lang; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function mb_list_encodings() |
|||
{ |
|||
return array('UTF-8'); |
|||
} |
|||
|
|||
public static function mb_encoding_aliases($encoding) |
|||
{ |
|||
switch (strtoupper($encoding)) { |
|||
case 'UTF8': |
|||
case 'UTF-8': |
|||
return array('utf8'); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function mb_check_encoding($var = null, $encoding = null) |
|||
{ |
|||
if (null === $encoding) { |
|||
if (null === $var) { |
|||
return false; |
|||
} |
|||
$encoding = self::$internalEncoding; |
|||
} |
|||
|
|||
return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var); |
|||
} |
|||
|
|||
public static function mb_detect_encoding($str, $encodingList = null, $strict = false) |
|||
{ |
|||
if (null === $encodingList) { |
|||
$encodingList = self::$encodingList; |
|||
} else { |
|||
if (!\is_array($encodingList)) { |
|||
$encodingList = array_map('trim', explode(',', $encodingList)); |
|||
} |
|||
$encodingList = array_map('strtoupper', $encodingList); |
|||
} |
|||
|
|||
foreach ($encodingList as $enc) { |
|||
switch ($enc) { |
|||
case 'ASCII': |
|||
if (!preg_match('/[\x80-\xFF]/', $str)) { |
|||
return $enc; |
|||
} |
|||
break; |
|||
|
|||
case 'UTF8': |
|||
case 'UTF-8': |
|||
if (preg_match('//u', $str)) { |
|||
return 'UTF-8'; |
|||
} |
|||
break; |
|||
|
|||
default: |
|||
if (0 === strncmp($enc, 'ISO-8859-', 9)) { |
|||
return $enc; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function mb_detect_order($encodingList = null) |
|||
{ |
|||
if (null === $encodingList) { |
|||
return self::$encodingList; |
|||
} |
|||
|
|||
if (!\is_array($encodingList)) { |
|||
$encodingList = array_map('trim', explode(',', $encodingList)); |
|||
} |
|||
$encodingList = array_map('strtoupper', $encodingList); |
|||
|
|||
foreach ($encodingList as $enc) { |
|||
switch ($enc) { |
|||
default: |
|||
if (strncmp($enc, 'ISO-8859-', 9)) { |
|||
return false; |
|||
} |
|||
// no break |
|||
case 'ASCII': |
|||
case 'UTF8': |
|||
case 'UTF-8': |
|||
} |
|||
} |
|||
|
|||
self::$encodingList = $encodingList; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public static function mb_strlen($s, $encoding = null) |
|||
{ |
|||
$encoding = self::getEncoding($encoding); |
|||
if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|||
return \strlen($s); |
|||
} |
|||
|
|||
return @iconv_strlen($s, $encoding); |
|||
} |
|||
|
|||
public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) |
|||
{ |
|||
$encoding = self::getEncoding($encoding); |
|||
if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|||
return strpos($haystack, $needle, $offset); |
|||
} |
|||
|
|||
$needle = (string) $needle; |
|||
if ('' === $needle) { |
|||
trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return iconv_strpos($haystack, $needle, $offset, $encoding); |
|||
} |
|||
|
|||
public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) |
|||
{ |
|||
$encoding = self::getEncoding($encoding); |
|||
if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|||
return strrpos($haystack, $needle, $offset); |
|||
} |
|||
|
|||
if ($offset != (int) $offset) { |
|||
$offset = 0; |
|||
} elseif ($offset = (int) $offset) { |
|||
if ($offset < 0) { |
|||
$haystack = self::mb_substr($haystack, 0, $offset, $encoding); |
|||
$offset = 0; |
|||
} else { |
|||
$haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); |
|||
} |
|||
} |
|||
|
|||
$pos = iconv_strrpos($haystack, $needle, $encoding); |
|||
|
|||
return false !== $pos ? $offset + $pos : false; |
|||
} |
|||
|
|||
public static function mb_str_split($string, $split_length = 1, $encoding = null) |
|||
{ |
|||
if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) { |
|||
trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING); |
|||
|
|||
return null; |
|||
} |
|||
|
|||
if ($split_length < 1) { |
|||
trigger_error('The length of each segment must be greater than zero', E_USER_WARNING); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
if (null === $encoding) { |
|||
$encoding = mb_internal_encoding(); |
|||
} |
|||
|
|||
$result = array(); |
|||
$length = mb_strlen($string, $encoding); |
|||
|
|||
for ($i = 0; $i < $length; $i += $split_length) { |
|||
$result[] = mb_substr($string, $i, $split_length, $encoding); |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
public static function mb_strtolower($s, $encoding = null) |
|||
{ |
|||
return self::mb_convert_case($s, MB_CASE_LOWER, $encoding); |
|||
} |
|||
|
|||
public static function mb_strtoupper($s, $encoding = null) |
|||
{ |
|||
return self::mb_convert_case($s, MB_CASE_UPPER, $encoding); |
|||
} |
|||
|
|||
public static function mb_substitute_character($c = null) |
|||
{ |
|||
if (0 === strcasecmp($c, 'none')) { |
|||
return true; |
|||
} |
|||
|
|||
return null !== $c ? false : 'none'; |
|||
} |
|||
|
|||
public static function mb_substr($s, $start, $length = null, $encoding = null) |
|||
{ |
|||
$encoding = self::getEncoding($encoding); |
|||
if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|||
return (string) substr($s, $start, null === $length ? 2147483647 : $length); |
|||
} |
|||
|
|||
if ($start < 0) { |
|||
$start = iconv_strlen($s, $encoding) + $start; |
|||
if ($start < 0) { |
|||
$start = 0; |
|||
} |
|||
} |
|||
|
|||
if (null === $length) { |
|||
$length = 2147483647; |
|||
} elseif ($length < 0) { |
|||
$length = iconv_strlen($s, $encoding) + $length - $start; |
|||
if ($length < 0) { |
|||
return ''; |
|||
} |
|||
} |
|||
|
|||
return (string) iconv_substr($s, $start, $length, $encoding); |
|||
} |
|||
|
|||
public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) |
|||
{ |
|||
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); |
|||
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); |
|||
|
|||
return self::mb_strpos($haystack, $needle, $offset, $encoding); |
|||
} |
|||
|
|||
public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) |
|||
{ |
|||
$pos = self::mb_stripos($haystack, $needle, 0, $encoding); |
|||
|
|||
return self::getSubpart($pos, $part, $haystack, $encoding); |
|||
} |
|||
|
|||
public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) |
|||
{ |
|||
$encoding = self::getEncoding($encoding); |
|||
if ('CP850' === $encoding || 'ASCII' === $encoding) { |
|||
return strrchr($haystack, $needle, $part); |
|||
} |
|||
$needle = self::mb_substr($needle, 0, 1, $encoding); |
|||
$pos = iconv_strrpos($haystack, $needle, $encoding); |
|||
|
|||
return self::getSubpart($pos, $part, $haystack, $encoding); |
|||
} |
|||
|
|||
public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) |
|||
{ |
|||
$needle = self::mb_substr($needle, 0, 1, $encoding); |
|||
$pos = self::mb_strripos($haystack, $needle, $encoding); |
|||
|
|||
return self::getSubpart($pos, $part, $haystack, $encoding); |
|||
} |
|||
|
|||
public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) |
|||
{ |
|||
$haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); |
|||
$needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); |
|||
|
|||
return self::mb_strrpos($haystack, $needle, $offset, $encoding); |
|||
} |
|||
|
|||
public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) |
|||
{ |
|||
$pos = strpos($haystack, $needle); |
|||
if (false === $pos) { |
|||
return false; |
|||
} |
|||
if ($part) { |
|||
return substr($haystack, 0, $pos); |
|||
} |
|||
|
|||
return substr($haystack, $pos); |
|||
} |
|||
|
|||
public static function mb_get_info($type = 'all') |
|||
{ |
|||
$info = array( |
|||
'internal_encoding' => self::$internalEncoding, |
|||
'http_output' => 'pass', |
|||
'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', |
|||
'func_overload' => 0, |
|||
'func_overload_list' => 'no overload', |
|||
'mail_charset' => 'UTF-8', |
|||
'mail_header_encoding' => 'BASE64', |
|||
'mail_body_encoding' => 'BASE64', |
|||
'illegal_chars' => 0, |
|||
'encoding_translation' => 'Off', |
|||
'language' => self::$language, |
|||
'detect_order' => self::$encodingList, |
|||
'substitute_character' => 'none', |
|||
'strict_detection' => 'Off', |
|||
); |
|||
|
|||
if ('all' === $type) { |
|||
return $info; |
|||
} |
|||
if (isset($info[$type])) { |
|||
return $info[$type]; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public static function mb_http_input($type = '') |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
public static function mb_http_output($encoding = null) |
|||
{ |
|||
return null !== $encoding ? 'pass' === $encoding : 'pass'; |
|||
} |
|||
|
|||
public static function mb_strwidth($s, $encoding = null) |
|||
{ |
|||
$encoding = self::getEncoding($encoding); |
|||
|
|||
if ('UTF-8' !== $encoding) { |
|||
$s = iconv($encoding, 'UTF-8//IGNORE', $s); |
|||
} |
|||
|
|||
$s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); |
|||
|
|||
return ($wide << 1) + iconv_strlen($s, 'UTF-8'); |
|||
} |
|||
|
|||
public static function mb_substr_count($haystack, $needle, $encoding = null) |
|||
{ |
|||
return substr_count($haystack, $needle); |
|||
} |
|||
|
|||
public static function mb_output_handler($contents, $status) |
|||
{ |
|||
return $contents; |
|||
} |
|||
|
|||
public static function mb_chr($code, $encoding = null) |
|||
{ |
|||
if (0x80 > $code %= 0x200000) { |
|||
$s = \chr($code); |
|||
} elseif (0x800 > $code) { |
|||
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); |
|||
} elseif (0x10000 > $code) { |
|||
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|||
} else { |
|||
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|||
} |
|||
|
|||
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { |
|||
$s = mb_convert_encoding($s, $encoding, 'UTF-8'); |
|||
} |
|||
|
|||
return $s; |
|||
} |
|||
|
|||
public static function mb_ord($s, $encoding = null) |
|||
{ |
|||
if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { |
|||
$s = mb_convert_encoding($s, 'UTF-8', $encoding); |
|||
} |
|||
|
|||
if (1 === \strlen($s)) { |
|||
return \ord($s); |
|||
} |
|||
|
|||
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; |
|||
if (0xF0 <= $code) { |
|||
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; |
|||
} |
|||
if (0xE0 <= $code) { |
|||
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; |
|||
} |
|||
if (0xC0 <= $code) { |
|||
return (($code - 0xC0) << 6) + $s[2] - 0x80; |
|||
} |
|||
|
|||
return $code; |
|||
} |
|||
|
|||
private static function getSubpart($pos, $part, $haystack, $encoding) |
|||
{ |
|||
if (false === $pos) { |
|||
return false; |
|||
} |
|||
if ($part) { |
|||
return self::mb_substr($haystack, 0, $pos, $encoding); |
|||
} |
|||
|
|||
return self::mb_substr($haystack, $pos, null, $encoding); |
|||
} |
|||
|
|||
private static function html_encoding_callback(array $m) |
|||
{ |
|||
$i = 1; |
|||
$entities = ''; |
|||
$m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8')); |
|||
|
|||
while (isset($m[$i])) { |
|||
if (0x80 > $m[$i]) { |
|||
$entities .= \chr($m[$i++]); |
|||
continue; |
|||
} |
|||
if (0xF0 <= $m[$i]) { |
|||
$c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; |
|||
} elseif (0xE0 <= $m[$i]) { |
|||
$c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; |
|||
} else { |
|||
$c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; |
|||
} |
|||
|
|||
$entities .= '&#'.$c.';'; |
|||
} |
|||
|
|||
return $entities; |
|||
} |
|||
|
|||
private static function title_case(array $s) |
|||
{ |
|||
return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8'); |
|||
} |
|||
|
|||
private static function getData($file) |
|||
{ |
|||
if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { |
|||
return require $file; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private static function getEncoding($encoding) |
|||
{ |
|||
if (null === $encoding) { |
|||
return self::$internalEncoding; |
|||
} |
|||
|
|||
$encoding = strtoupper($encoding); |
|||
|
|||
if ('8BIT' === $encoding || 'BINARY' === $encoding) { |
|||
return 'CP850'; |
|||
} |
|||
if ('UTF8' === $encoding) { |
|||
return 'UTF-8'; |
|||
} |
|||
|
|||
return $encoding; |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
Symfony Polyfill / Mbstring |
|||
=========================== |
|||
|
|||
This component provides a partial, native PHP implementation for the |
|||
[Mbstring](http://php.net/mbstring) extension. |
|||
|
|||
More information can be found in the |
|||
[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). |
|||
|
|||
License |
|||
======= |
|||
|
|||
This library is released under the [MIT license](LICENSE). |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
@ -0,0 +1,62 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
use Symfony\Polyfill\Mbstring as p; |
|||
|
|||
if (!function_exists('mb_strlen')) { |
|||
define('MB_CASE_UPPER', 0); |
|||
define('MB_CASE_LOWER', 1); |
|||
define('MB_CASE_TITLE', 2); |
|||
|
|||
function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); } |
|||
function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); } |
|||
function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); } |
|||
function mb_decode_numericentity($s, $convmap, $enc = null) { return p\Mbstring::mb_decode_numericentity($s, $convmap, $enc); } |
|||
function mb_encode_numericentity($s, $convmap, $enc = null, $is_hex = false) { return p\Mbstring::mb_encode_numericentity($s, $convmap, $enc, $is_hex); } |
|||
function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); } |
|||
function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); } |
|||
function mb_language($lang = null) { return p\Mbstring::mb_language($lang); } |
|||
function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } |
|||
function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } |
|||
function mb_check_encoding($var = null, $encoding = null) { return p\Mbstring::mb_check_encoding($var, $encoding); } |
|||
function mb_detect_encoding($str, $encodingList = null, $strict = false) { return p\Mbstring::mb_detect_encoding($str, $encodingList, $strict); } |
|||
function mb_detect_order($encodingList = null) { return p\Mbstring::mb_detect_order($encodingList); } |
|||
function mb_parse_str($s, &$result = array()) { parse_str($s, $result); } |
|||
function mb_strlen($s, $enc = null) { return p\Mbstring::mb_strlen($s, $enc); } |
|||
function mb_strpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strpos($s, $needle, $offset, $enc); } |
|||
function mb_strtolower($s, $enc = null) { return p\Mbstring::mb_strtolower($s, $enc); } |
|||
function mb_strtoupper($s, $enc = null) { return p\Mbstring::mb_strtoupper($s, $enc); } |
|||
function mb_substitute_character($char = null) { return p\Mbstring::mb_substitute_character($char); } |
|||
function mb_substr($s, $start, $length = 2147483647, $enc = null) { return p\Mbstring::mb_substr($s, $start, $length, $enc); } |
|||
function mb_stripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_stripos($s, $needle, $offset, $enc); } |
|||
function mb_stristr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_stristr($s, $needle, $part, $enc); } |
|||
function mb_strrchr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrchr($s, $needle, $part, $enc); } |
|||
function mb_strrichr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strrichr($s, $needle, $part, $enc); } |
|||
function mb_strripos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strripos($s, $needle, $offset, $enc); } |
|||
function mb_strrpos($s, $needle, $offset = 0, $enc = null) { return p\Mbstring::mb_strrpos($s, $needle, $offset, $enc); } |
|||
function mb_strstr($s, $needle, $part = false, $enc = null) { return p\Mbstring::mb_strstr($s, $needle, $part, $enc); } |
|||
function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } |
|||
function mb_http_output($enc = null) { return p\Mbstring::mb_http_output($enc); } |
|||
function mb_strwidth($s, $enc = null) { return p\Mbstring::mb_strwidth($s, $enc); } |
|||
function mb_substr_count($haystack, $needle, $enc = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $enc); } |
|||
function mb_output_handler($contents, $status) { return p\Mbstring::mb_output_handler($contents, $status); } |
|||
function mb_http_input($type = '') { return p\Mbstring::mb_http_input($type); } |
|||
function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null) { return p\Mbstring::mb_convert_variables($toEncoding, $fromEncoding, $a, $b, $c, $d, $e, $f); } |
|||
} |
|||
if (!function_exists('mb_chr')) { |
|||
function mb_ord($s, $enc = null) { return p\Mbstring::mb_ord($s, $enc); } |
|||
function mb_chr($code, $enc = null) { return p\Mbstring::mb_chr($code, $enc); } |
|||
function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); } |
|||
} |
|||
|
|||
if (!function_exists('mb_str_split')) { |
|||
function mb_str_split($string, $split_length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $split_length, $encoding); } |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
{ |
|||
"name": "symfony/polyfill-mbstring", |
|||
"type": "library", |
|||
"description": "Symfony polyfill for the Mbstring extension", |
|||
"keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], |
|||
"homepage": "https://symfony.com", |
|||
"license": "MIT", |
|||
"authors": [ |
|||
{ |
|||
"name": "Nicolas Grekas", |
|||
"email": "p@tchwork.com" |
|||
}, |
|||
{ |
|||
"name": "Symfony Community", |
|||
"homepage": "https://symfony.com/contributors" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": ">=5.3.3" |
|||
}, |
|||
"autoload": { |
|||
"psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, |
|||
"files": [ "bootstrap.php" ] |
|||
}, |
|||
"suggest": { |
|||
"ext-mbstring": "For best performance" |
|||
}, |
|||
"minimum-stability": "dev", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.12-dev" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2015-2019 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,216 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Polyfill\Php72; |
|||
|
|||
/** |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
final class Php72 |
|||
{ |
|||
private static $hashMask; |
|||
|
|||
public static function utf8_encode($s) |
|||
{ |
|||
$s .= $s; |
|||
$len = \strlen($s); |
|||
|
|||
for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { |
|||
switch (true) { |
|||
case $s[$i] < "\x80": $s[$j] = $s[$i]; break; |
|||
case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; |
|||
default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break; |
|||
} |
|||
} |
|||
|
|||
return substr($s, 0, $j); |
|||
} |
|||
|
|||
public static function utf8_decode($s) |
|||
{ |
|||
$s = (string) $s; |
|||
$len = \strlen($s); |
|||
|
|||
for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { |
|||
switch ($s[$i] & "\xF0") { |
|||
case "\xC0": |
|||
case "\xD0": |
|||
$c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F"); |
|||
$s[$j] = $c < 256 ? \chr($c) : '?'; |
|||
break; |
|||
|
|||
case "\xF0": |
|||
++$i; |
|||
// no break |
|||
|
|||
case "\xE0": |
|||
$s[$j] = '?'; |
|||
$i += 2; |
|||
break; |
|||
|
|||
default: |
|||
$s[$j] = $s[$i]; |
|||
} |
|||
} |
|||
|
|||
return substr($s, 0, $j); |
|||
} |
|||
|
|||
public static function php_os_family() |
|||
{ |
|||
if ('\\' === \DIRECTORY_SEPARATOR) { |
|||
return 'Windows'; |
|||
} |
|||
|
|||
$map = array( |
|||
'Darwin' => 'Darwin', |
|||
'DragonFly' => 'BSD', |
|||
'FreeBSD' => 'BSD', |
|||
'NetBSD' => 'BSD', |
|||
'OpenBSD' => 'BSD', |
|||
'Linux' => 'Linux', |
|||
'SunOS' => 'Solaris', |
|||
); |
|||
|
|||
return isset($map[PHP_OS]) ? $map[PHP_OS] : 'Unknown'; |
|||
} |
|||
|
|||
public static function spl_object_id($object) |
|||
{ |
|||
if (null === self::$hashMask) { |
|||
self::initHashMask(); |
|||
} |
|||
if (null === $hash = spl_object_hash($object)) { |
|||
return; |
|||
} |
|||
|
|||
return self::$hashMask ^ hexdec(substr($hash, 16 - \PHP_INT_SIZE, \PHP_INT_SIZE)); |
|||
} |
|||
|
|||
public static function sapi_windows_vt100_support($stream, $enable = null) |
|||
{ |
|||
if (!\is_resource($stream)) { |
|||
trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
$meta = stream_get_meta_data($stream); |
|||
|
|||
if ('STDIO' !== $meta['stream_type']) { |
|||
trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', E_USER_WARNING); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
// We cannot actually disable vt100 support if it is set |
|||
if (false === $enable || !self::stream_isatty($stream)) { |
|||
return false; |
|||
} |
|||
|
|||
// The native function does not apply to stdin |
|||
$meta = array_map('strtolower', $meta); |
|||
$stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; |
|||
|
|||
return !$stdin |
|||
&& (false !== getenv('ANSICON') |
|||
|| 'ON' === getenv('ConEmuANSI') |
|||
|| 'xterm' === getenv('TERM') |
|||
|| 'Hyper' === getenv('TERM_PROGRAM')); |
|||
} |
|||
|
|||
public static function stream_isatty($stream) |
|||
{ |
|||
if (!\is_resource($stream)) { |
|||
trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
if ('\\' === \DIRECTORY_SEPARATOR) { |
|||
$stat = @fstat($stream); |
|||
// Check if formatted mode is S_IFCHR |
|||
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; |
|||
} |
|||
|
|||
return \function_exists('posix_isatty') && @posix_isatty($stream); |
|||
} |
|||
|
|||
private static function initHashMask() |
|||
{ |
|||
$obj = (object) array(); |
|||
self::$hashMask = -1; |
|||
|
|||
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below |
|||
$obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'); |
|||
foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) { |
|||
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { |
|||
$frame['line'] = 0; |
|||
break; |
|||
} |
|||
} |
|||
if (!empty($frame['line'])) { |
|||
ob_start(); |
|||
debug_zval_dump($obj); |
|||
self::$hashMask = (int) substr(ob_get_clean(), 17); |
|||
} |
|||
|
|||
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - \PHP_INT_SIZE, \PHP_INT_SIZE)); |
|||
} |
|||
|
|||
public static function mb_chr($code, $encoding = null) |
|||
{ |
|||
if (0x80 > $code %= 0x200000) { |
|||
$s = \chr($code); |
|||
} elseif (0x800 > $code) { |
|||
$s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); |
|||
} elseif (0x10000 > $code) { |
|||
$s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|||
} else { |
|||
$s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); |
|||
} |
|||
|
|||
if ('UTF-8' !== $encoding) { |
|||
$s = mb_convert_encoding($s, $encoding, 'UTF-8'); |
|||
} |
|||
|
|||
return $s; |
|||
} |
|||
|
|||
public static function mb_ord($s, $encoding = null) |
|||
{ |
|||
if (null == $encoding) { |
|||
$s = mb_convert_encoding($s, 'UTF-8'); |
|||
} elseif ('UTF-8' !== $encoding) { |
|||
$s = mb_convert_encoding($s, 'UTF-8', $encoding); |
|||
} |
|||
|
|||
if (1 === \strlen($s)) { |
|||
return \ord($s); |
|||
} |
|||
|
|||
$code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; |
|||
if (0xF0 <= $code) { |
|||
return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; |
|||
} |
|||
if (0xE0 <= $code) { |
|||
return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; |
|||
} |
|||
if (0xC0 <= $code) { |
|||
return (($code - 0xC0) << 6) + $s[2] - 0x80; |
|||
} |
|||
|
|||
return $code; |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
Symfony Polyfill / Php72 |
|||
======================== |
|||
|
|||
This component provides functions added to PHP 7.2 core: |
|||
|
|||
- [`spl_object_id`](https://php.net/spl_object_id) |
|||
- [`stream_isatty`](https://php.net/stream_isatty) |
|||
|
|||
On Windows only: |
|||
|
|||
- [`sapi_windows_vt100_support`](https://php.net/sapi_windows_vt100_support) |
|||
|
|||
Moved to core since 7.2 (was in the optional XML extension earlier): |
|||
|
|||
- [`utf8_encode`](https://php.net/utf8_encode) |
|||
- [`utf8_decode`](https://php.net/utf8_decode) |
|||
|
|||
Also, it provides a constant added to PHP 7.2: |
|||
- [`PHP_OS_FAMILY`](http://php.net/manual/en/reserved.constants.php#constant.php-os-family) |
|||
|
|||
More information can be found in the |
|||
[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). |
|||
|
|||
License |
|||
======= |
|||
|
|||
This library is released under the [MIT license](LICENSE). |
|||
@ -0,0 +1,36 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
use Symfony\Polyfill\Php72 as p; |
|||
|
|||
if (PHP_VERSION_ID < 70200) { |
|||
if ('\\' === DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) { |
|||
function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); } |
|||
} |
|||
if (!function_exists('stream_isatty')) { |
|||
function stream_isatty($stream) { return p\Php72::stream_isatty($stream); } |
|||
} |
|||
if (!function_exists('utf8_encode')) { |
|||
function utf8_encode($s) { return p\Php72::utf8_encode($s); } |
|||
function utf8_decode($s) { return p\Php72::utf8_decode($s); } |
|||
} |
|||
if (!function_exists('spl_object_id')) { |
|||
function spl_object_id($s) { return p\Php72::spl_object_id($s); } |
|||
} |
|||
if (!defined('PHP_OS_FAMILY')) { |
|||
define('PHP_OS_FAMILY', p\Php72::php_os_family()); |
|||
} |
|||
if (!function_exists('mb_chr')) { |
|||
function mb_ord($s, $enc = null) { return p\Php72::mb_ord($s, $enc); } |
|||
function mb_chr($code, $enc = null) { return p\Php72::mb_chr($code, $enc); } |
|||
function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); } |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
{ |
|||
"name": "symfony/polyfill-php72", |
|||
"type": "library", |
|||
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", |
|||
"keywords": ["polyfill", "shim", "compatibility", "portable"], |
|||
"homepage": "https://symfony.com", |
|||
"license": "MIT", |
|||
"authors": [ |
|||
{ |
|||
"name": "Nicolas Grekas", |
|||
"email": "p@tchwork.com" |
|||
}, |
|||
{ |
|||
"name": "Symfony Community", |
|||
"homepage": "https://symfony.com/contributors" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": ">=5.3.3" |
|||
}, |
|||
"autoload": { |
|||
"psr-4": { "Symfony\\Polyfill\\Php72\\": "" }, |
|||
"files": [ "bootstrap.php" ] |
|||
}, |
|||
"minimum-stability": "dev", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.12-dev" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
vendor/ |
|||
composer.lock |
|||
phpunit.xml |
|||
.php_cs.cache |
|||
@ -0,0 +1,24 @@ |
|||
<?php |
|||
|
|||
return PhpCsFixer\Config::create() |
|||
->setRules([ |
|||
'@Symfony' => true, |
|||
'@Symfony:risky' => true, |
|||
'@PHPUnit48Migration:risky' => true, |
|||
'php_unit_no_expectation_annotation' => false, // part of `PHPUnitXYMigration:risky` ruleset, to be enabled when PHPUnit 4.x support will be dropped, as we don't want to rewrite exceptions handling twice |
|||
'array_syntax' => ['syntax' => 'short'], |
|||
'fopen_flags' => false, |
|||
'ordered_imports' => true, |
|||
'protected_to_private' => false, |
|||
// Part of @Symfony:risky in PHP-CS-Fixer 2.13.0. To be removed from the config file once upgrading |
|||
'native_function_invocation' => ['include' => ['@compiler_optimized'], 'scope' => 'namespaced'], |
|||
// Part of future @Symfony ruleset in PHP-CS-Fixer To be removed from the config file once upgrading |
|||
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], |
|||
]) |
|||
->setRiskyAllowed(true) |
|||
->setFinder( |
|||
PhpCsFixer\Finder::create() |
|||
->in(__DIR__) |
|||
->name('*.php') |
|||
) |
|||
; |
|||
@ -0,0 +1,47 @@ |
|||
language: php |
|||
sudo: false |
|||
cache: |
|||
directories: |
|||
- $HOME/.composer/cache/files |
|||
- $HOME/symfony-bridge/.phpunit |
|||
|
|||
env: |
|||
global: |
|||
- PHPUNIT_FLAGS="-v" |
|||
- SYMFONY_PHPUNIT_DIR="$HOME/symfony-bridge/.phpunit" |
|||
|
|||
matrix: |
|||
fast_finish: true |
|||
include: |
|||
# Minimum supported dependencies with the latest and oldest PHP version |
|||
- php: 7.2 |
|||
env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors" |
|||
|
|||
- php: 7.1 |
|||
- php: 7.2 |
|||
env: COVERAGE=true PHPUNIT_FLAGS="-v --coverage-text" |
|||
|
|||
# Latest commit to master |
|||
- php: 7.2 |
|||
env: STABILITY="dev" |
|||
|
|||
allow_failures: |
|||
# Dev-master is allowed to fail. |
|||
- env: STABILITY="dev" |
|||
|
|||
before_install: |
|||
- if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi |
|||
- if ! [ -z "$STABILITY" ]; then composer config minimum-stability ${STABILITY}; fi; |
|||
- if ! [ -v "$DEPENDENCIES" ]; then composer require --no-update ${DEPENDENCIES}; fi; |
|||
|
|||
install: |
|||
# To be removed when this issue will be resolved: https://github.com/composer/composer/issues/5355 |
|||
- if [[ "$COMPOSER_FLAGS" == *"--prefer-lowest"* ]]; then composer update --prefer-dist --no-interaction --prefer-stable --quiet; fi |
|||
- composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction |
|||
- ./vendor/bin/simple-phpunit install |
|||
|
|||
script: |
|||
- composer validate --strict --no-check-lock |
|||
# simple-phpunit is the PHPUnit wrapper provided by the PHPUnit Bridge component and |
|||
# it helps with testing legacy code and deprecations (composer require symfony/phpunit-bridge) |
|||
- ./vendor/bin/simple-phpunit $PHPUNIT_FLAGS |
|||
@ -0,0 +1,18 @@ |
|||
CHANGELOG |
|||
========= |
|||
|
|||
* 1.1.0 (2018-08-30) |
|||
|
|||
* Added support for creating PSR-7 messages using PSR-17 factories |
|||
|
|||
* 1.0.2 (2017-12-19) |
|||
|
|||
* Fixed request target in PSR7 Request (mtibben) |
|||
|
|||
* 1.0.1 (2017-12-04) |
|||
|
|||
* Added support for Symfony 4 (dunglas) |
|||
|
|||
* 1.0.0 (2016-09-14) |
|||
|
|||
* Initial release |
|||
@ -0,0 +1,175 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Factory; |
|||
|
|||
@trigger_error(sprintf('The "%s" class is deprecated since symfony/psr-http-message-bridge 1.2, use PsrHttpFactory instead.', DiactorosFactory::class), E_USER_DEPRECATED); |
|||
|
|||
use Psr\Http\Message\UploadedFileInterface; |
|||
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; |
|||
use Symfony\Component\HttpFoundation\BinaryFileResponse; |
|||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
use Symfony\Component\HttpFoundation\StreamedResponse; |
|||
use Zend\Diactoros\Response as DiactorosResponse; |
|||
use Zend\Diactoros\ServerRequest; |
|||
use Zend\Diactoros\ServerRequestFactory as DiactorosRequestFactory; |
|||
use Zend\Diactoros\Stream as DiactorosStream; |
|||
use Zend\Diactoros\UploadedFile as DiactorosUploadedFile; |
|||
|
|||
/** |
|||
* Builds Psr\HttpMessage instances using the Zend Diactoros implementation. |
|||
* |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
* |
|||
* @deprecated since symfony/psr-http-message-bridge 1.2, use PsrHttpFactory instead |
|||
*/ |
|||
class DiactorosFactory implements HttpMessageFactoryInterface |
|||
{ |
|||
public function __construct() |
|||
{ |
|||
if (!class_exists('Zend\Diactoros\ServerRequestFactory')) { |
|||
throw new \RuntimeException('Zend Diactoros must be installed to use the DiactorosFactory.'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function createRequest(Request $symfonyRequest) |
|||
{ |
|||
$server = method_exists('Zend\Diactoros\ServerRequestFactory', 'normalizeServer') |
|||
? DiactorosRequestFactory::normalizeServer($symfonyRequest->server->all()) |
|||
: \Zend\Diactoros\normalizeServer($symfonyRequest->server->all()); |
|||
$headers = $symfonyRequest->headers->all(); |
|||
|
|||
$body = new DiactorosStream($symfonyRequest->getContent(true)); |
|||
|
|||
$files = method_exists('Zend\Diactoros\ServerRequestFactory', 'normalizeFiles') |
|||
? DiactorosRequestFactory::normalizeFiles($this->getFiles($symfonyRequest->files->all())) |
|||
: \Zend\Diactoros\normalizeUploadedFiles($this->getFiles($symfonyRequest->files->all())); |
|||
|
|||
$request = new ServerRequest( |
|||
$server, |
|||
$files, |
|||
$symfonyRequest->getSchemeAndHttpHost().$symfonyRequest->getRequestUri(), |
|||
$symfonyRequest->getMethod(), |
|||
$body, |
|||
$headers |
|||
); |
|||
|
|||
$request = $request |
|||
->withCookieParams($symfonyRequest->cookies->all()) |
|||
->withQueryParams($symfonyRequest->query->all()) |
|||
->withParsedBody($symfonyRequest->request->all()) |
|||
->withRequestTarget($symfonyRequest->getRequestUri()) |
|||
; |
|||
|
|||
foreach ($symfonyRequest->attributes->all() as $key => $value) { |
|||
$request = $request->withAttribute($key, $value); |
|||
} |
|||
|
|||
return $request; |
|||
} |
|||
|
|||
/** |
|||
* Converts Symfony uploaded files array to the PSR one. |
|||
* |
|||
* @param array $uploadedFiles |
|||
* |
|||
* @return array |
|||
*/ |
|||
private function getFiles(array $uploadedFiles) |
|||
{ |
|||
$files = []; |
|||
|
|||
foreach ($uploadedFiles as $key => $value) { |
|||
if (null === $value) { |
|||
$files[$key] = new DiactorosUploadedFile(null, 0, UPLOAD_ERR_NO_FILE, null, null); |
|||
continue; |
|||
} |
|||
if ($value instanceof UploadedFile) { |
|||
$files[$key] = $this->createUploadedFile($value); |
|||
} else { |
|||
$files[$key] = $this->getFiles($value); |
|||
} |
|||
} |
|||
|
|||
return $files; |
|||
} |
|||
|
|||
/** |
|||
* Creates a PSR-7 UploadedFile instance from a Symfony one. |
|||
* |
|||
* @param UploadedFile $symfonyUploadedFile |
|||
* |
|||
* @return UploadedFileInterface |
|||
*/ |
|||
private function createUploadedFile(UploadedFile $symfonyUploadedFile) |
|||
{ |
|||
return new DiactorosUploadedFile( |
|||
$symfonyUploadedFile->getRealPath(), |
|||
(int) $symfonyUploadedFile->getSize(), |
|||
$symfonyUploadedFile->getError(), |
|||
$symfonyUploadedFile->getClientOriginalName(), |
|||
$symfonyUploadedFile->getClientMimeType() |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function createResponse(Response $symfonyResponse) |
|||
{ |
|||
if ($symfonyResponse instanceof BinaryFileResponse) { |
|||
$stream = new DiactorosStream($symfonyResponse->getFile()->getPathname(), 'r'); |
|||
} else { |
|||
$stream = new DiactorosStream('php://temp', 'wb+'); |
|||
if ($symfonyResponse instanceof StreamedResponse) { |
|||
ob_start(function ($buffer) use ($stream) { |
|||
$stream->write($buffer); |
|||
|
|||
return ''; |
|||
}); |
|||
|
|||
$symfonyResponse->sendContent(); |
|||
ob_end_clean(); |
|||
} else { |
|||
$stream->write($symfonyResponse->getContent()); |
|||
} |
|||
} |
|||
|
|||
$headers = $symfonyResponse->headers->all(); |
|||
if (!isset($headers['Set-Cookie']) && !isset($headers['set-cookie'])) { |
|||
$cookies = $symfonyResponse->headers->getCookies(); |
|||
if (!empty($cookies)) { |
|||
$headers['Set-Cookie'] = []; |
|||
foreach ($cookies as $cookie) { |
|||
$headers['Set-Cookie'][] = $cookie->__toString(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
$response = new DiactorosResponse( |
|||
$stream, |
|||
$symfonyResponse->getStatusCode(), |
|||
$headers |
|||
); |
|||
|
|||
$protocolVersion = $symfonyResponse->getProtocolVersion(); |
|||
if ('1.1' !== $protocolVersion) { |
|||
$response = $response->withProtocolVersion($protocolVersion); |
|||
} |
|||
|
|||
return $response; |
|||
} |
|||
} |
|||
@ -0,0 +1,280 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Factory; |
|||
|
|||
use Psr\Http\Message\ResponseInterface; |
|||
use Psr\Http\Message\ServerRequestInterface; |
|||
use Psr\Http\Message\StreamInterface; |
|||
use Psr\Http\Message\UploadedFileInterface; |
|||
use Psr\Http\Message\UriInterface; |
|||
use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; |
|||
use Symfony\Component\HttpFoundation\Cookie; |
|||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
use Symfony\Component\HttpFoundation\StreamedResponse; |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
* |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class HttpFoundationFactory implements HttpFoundationFactoryInterface |
|||
{ |
|||
/** |
|||
* @var int The maximum output buffering size for each iteration when sending the response |
|||
*/ |
|||
private $responseBufferMaxLength; |
|||
|
|||
public function __construct(int $responseBufferMaxLength = 16372) |
|||
{ |
|||
$this->responseBufferMaxLength = $responseBufferMaxLength; |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function createRequest(ServerRequestInterface $psrRequest) |
|||
{ |
|||
$server = []; |
|||
$uri = $psrRequest->getUri(); |
|||
|
|||
if ($uri instanceof UriInterface) { |
|||
$server['SERVER_NAME'] = $uri->getHost(); |
|||
$server['SERVER_PORT'] = $uri->getPort(); |
|||
$server['REQUEST_URI'] = $uri->getPath(); |
|||
$server['QUERY_STRING'] = $uri->getQuery(); |
|||
} |
|||
|
|||
$server['REQUEST_METHOD'] = $psrRequest->getMethod(); |
|||
|
|||
$server = array_replace($server, $psrRequest->getServerParams()); |
|||
|
|||
$parsedBody = $psrRequest->getParsedBody(); |
|||
$parsedBody = \is_array($parsedBody) ? $parsedBody : []; |
|||
|
|||
$request = new Request( |
|||
$psrRequest->getQueryParams(), |
|||
$parsedBody, |
|||
$psrRequest->getAttributes(), |
|||
$psrRequest->getCookieParams(), |
|||
$this->getFiles($psrRequest->getUploadedFiles()), |
|||
$server, |
|||
$psrRequest->getBody()->__toString() |
|||
); |
|||
$request->headers->replace($psrRequest->getHeaders()); |
|||
|
|||
return $request; |
|||
} |
|||
|
|||
/** |
|||
* Converts to the input array to $_FILES structure. |
|||
* |
|||
* @param array $uploadedFiles |
|||
* |
|||
* @return array |
|||
*/ |
|||
private function getFiles(array $uploadedFiles) |
|||
{ |
|||
$files = []; |
|||
|
|||
foreach ($uploadedFiles as $key => $value) { |
|||
if ($value instanceof UploadedFileInterface) { |
|||
$files[$key] = $this->createUploadedFile($value); |
|||
} else { |
|||
$files[$key] = $this->getFiles($value); |
|||
} |
|||
} |
|||
|
|||
return $files; |
|||
} |
|||
|
|||
/** |
|||
* Creates Symfony UploadedFile instance from PSR-7 ones. |
|||
* |
|||
* @param UploadedFileInterface $psrUploadedFile |
|||
* |
|||
* @return UploadedFile |
|||
*/ |
|||
private function createUploadedFile(UploadedFileInterface $psrUploadedFile) |
|||
{ |
|||
$temporaryPath = ''; |
|||
$clientFileName = ''; |
|||
if (UPLOAD_ERR_NO_FILE !== $psrUploadedFile->getError()) { |
|||
$temporaryPath = $this->getTemporaryPath(); |
|||
$psrUploadedFile->moveTo($temporaryPath); |
|||
|
|||
$clientFileName = $psrUploadedFile->getClientFilename(); |
|||
} |
|||
|
|||
if (class_exists('Symfony\Component\HttpFoundation\HeaderUtils')) { |
|||
// Symfony 4.1+ |
|||
return new UploadedFile( |
|||
$temporaryPath, |
|||
null === $clientFileName ? '' : $clientFileName, |
|||
$psrUploadedFile->getClientMediaType(), |
|||
$psrUploadedFile->getError(), |
|||
true |
|||
); |
|||
} |
|||
|
|||
return new UploadedFile( |
|||
$temporaryPath, |
|||
null === $clientFileName ? '' : $clientFileName, |
|||
$psrUploadedFile->getClientMediaType(), |
|||
$psrUploadedFile->getSize(), |
|||
$psrUploadedFile->getError(), |
|||
true |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Gets a temporary file path. |
|||
* |
|||
* @return string |
|||
*/ |
|||
protected function getTemporaryPath() |
|||
{ |
|||
return tempnam(sys_get_temp_dir(), uniqid('symfony', true)); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function createResponse(ResponseInterface $psrResponse, bool $streamed = false) |
|||
{ |
|||
$cookies = $psrResponse->getHeader('Set-Cookie'); |
|||
$psrResponse = $psrResponse->withoutHeader('Set-Cookie'); |
|||
|
|||
if ($streamed) { |
|||
$response = new StreamedResponse( |
|||
$this->createStreamedResponseCallback($psrResponse->getBody()), |
|||
$psrResponse->getStatusCode(), |
|||
$psrResponse->getHeaders() |
|||
); |
|||
} else { |
|||
$response = new Response( |
|||
$psrResponse->getBody()->__toString(), |
|||
$psrResponse->getStatusCode(), |
|||
$psrResponse->getHeaders() |
|||
); |
|||
} |
|||
|
|||
$response->setProtocolVersion($psrResponse->getProtocolVersion()); |
|||
|
|||
foreach ($cookies as $cookie) { |
|||
$response->headers->setCookie($this->createCookie($cookie)); |
|||
} |
|||
|
|||
return $response; |
|||
} |
|||
|
|||
/** |
|||
* Creates a Cookie instance from a cookie string. |
|||
* |
|||
* Some snippets have been taken from the Guzzle project: https://github.com/guzzle/guzzle/blob/5.3/src/Cookie/SetCookie.php#L34 |
|||
* |
|||
* @param string $cookie |
|||
* |
|||
* @return Cookie |
|||
* |
|||
* @throws \InvalidArgumentException |
|||
*/ |
|||
private function createCookie($cookie) |
|||
{ |
|||
foreach (explode(';', $cookie) as $part) { |
|||
$part = trim($part); |
|||
|
|||
$data = explode('=', $part, 2); |
|||
$name = $data[0]; |
|||
$value = isset($data[1]) ? trim($data[1], " \n\r\t\0\x0B\"") : null; |
|||
|
|||
if (!isset($cookieName)) { |
|||
$cookieName = $name; |
|||
$cookieValue = $value; |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if ('expires' === strtolower($name) && null !== $value) { |
|||
$cookieExpire = new \DateTime($value); |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if ('path' === strtolower($name) && null !== $value) { |
|||
$cookiePath = $value; |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if ('domain' === strtolower($name) && null !== $value) { |
|||
$cookieDomain = $value; |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if ('secure' === strtolower($name)) { |
|||
$cookieSecure = true; |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if ('httponly' === strtolower($name)) { |
|||
$cookieHttpOnly = true; |
|||
|
|||
continue; |
|||
} |
|||
|
|||
if ('samesite' === strtolower($name) && null !== $value) { |
|||
$samesite = $value; |
|||
|
|||
continue; |
|||
} |
|||
} |
|||
|
|||
if (!isset($cookieName)) { |
|||
throw new \InvalidArgumentException('The value of the Set-Cookie header is malformed.'); |
|||
} |
|||
|
|||
return new Cookie( |
|||
$cookieName, |
|||
$cookieValue, |
|||
isset($cookieExpire) ? $cookieExpire : 0, |
|||
isset($cookiePath) ? $cookiePath : '/', |
|||
isset($cookieDomain) ? $cookieDomain : null, |
|||
isset($cookieSecure), |
|||
isset($cookieHttpOnly), |
|||
false, |
|||
isset($samesite) ? $samesite : null |
|||
); |
|||
} |
|||
|
|||
private function createStreamedResponseCallback(StreamInterface $body): callable |
|||
{ |
|||
return function () use ($body) { |
|||
if ($body->isSeekable()) { |
|||
$body->rewind(); |
|||
} |
|||
|
|||
if (!$body->isReadable()) { |
|||
echo $body; |
|||
|
|||
return; |
|||
} |
|||
|
|||
while (!$body->eof()) { |
|||
echo $body->read($this->responseBufferMaxLength); |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,172 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Factory; |
|||
|
|||
use Psr\Http\Message\ResponseFactoryInterface; |
|||
use Psr\Http\Message\ServerRequestFactoryInterface; |
|||
use Psr\Http\Message\StreamFactoryInterface; |
|||
use Psr\Http\Message\UploadedFileFactoryInterface; |
|||
use Psr\Http\Message\UploadedFileInterface; |
|||
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; |
|||
use Symfony\Component\HttpFoundation\BinaryFileResponse; |
|||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
use Symfony\Component\HttpFoundation\StreamedResponse; |
|||
|
|||
/** |
|||
* Builds Psr\HttpMessage instances using a PSR-17 implementation. |
|||
* |
|||
* @author Antonio J. García Lagar <aj@garcialagar.es> |
|||
*/ |
|||
class PsrHttpFactory implements HttpMessageFactoryInterface |
|||
{ |
|||
private $serverRequestFactory; |
|||
private $streamFactory; |
|||
private $uploadedFileFactory; |
|||
private $responseFactory; |
|||
|
|||
public function __construct(ServerRequestFactoryInterface $serverRequestFactory, StreamFactoryInterface $streamFactory, UploadedFileFactoryInterface $uploadedFileFactory, ResponseFactoryInterface $responseFactory) |
|||
{ |
|||
$this->serverRequestFactory = $serverRequestFactory; |
|||
$this->streamFactory = $streamFactory; |
|||
$this->uploadedFileFactory = $uploadedFileFactory; |
|||
$this->responseFactory = $responseFactory; |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function createRequest(Request $symfonyRequest) |
|||
{ |
|||
$request = $this->serverRequestFactory->createServerRequest( |
|||
$symfonyRequest->getMethod(), |
|||
$symfonyRequest->getUri(), |
|||
$symfonyRequest->server->all() |
|||
); |
|||
|
|||
foreach ($symfonyRequest->headers->all() as $name => $value) { |
|||
$request = $request->withHeader($name, $value); |
|||
} |
|||
|
|||
$body = $this->streamFactory->createStreamFromResource($symfonyRequest->getContent(true)); |
|||
|
|||
$request = $request |
|||
->withBody($body) |
|||
->withUploadedFiles($this->getFiles($symfonyRequest->files->all())) |
|||
->withCookieParams($symfonyRequest->cookies->all()) |
|||
->withQueryParams($symfonyRequest->query->all()) |
|||
->withParsedBody($symfonyRequest->request->all()) |
|||
; |
|||
|
|||
foreach ($symfonyRequest->attributes->all() as $key => $value) { |
|||
$request = $request->withAttribute($key, $value); |
|||
} |
|||
|
|||
return $request; |
|||
} |
|||
|
|||
/** |
|||
* Converts Symfony uploaded files array to the PSR one. |
|||
* |
|||
* @param array $uploadedFiles |
|||
* |
|||
* @return array |
|||
*/ |
|||
private function getFiles(array $uploadedFiles) |
|||
{ |
|||
$files = []; |
|||
|
|||
foreach ($uploadedFiles as $key => $value) { |
|||
if (null === $value) { |
|||
$files[$key] = $this->uploadedFileFactory->createUploadedFile($this->streamFactory->createStream(), 0, UPLOAD_ERR_NO_FILE); |
|||
continue; |
|||
} |
|||
if ($value instanceof UploadedFile) { |
|||
$files[$key] = $this->createUploadedFile($value); |
|||
} else { |
|||
$files[$key] = $this->getFiles($value); |
|||
} |
|||
} |
|||
|
|||
return $files; |
|||
} |
|||
|
|||
/** |
|||
* Creates a PSR-7 UploadedFile instance from a Symfony one. |
|||
* |
|||
* @param UploadedFile $symfonyUploadedFile |
|||
* |
|||
* @return UploadedFileInterface |
|||
*/ |
|||
private function createUploadedFile(UploadedFile $symfonyUploadedFile) |
|||
{ |
|||
return $this->uploadedFileFactory->createUploadedFile( |
|||
$this->streamFactory->createStreamFromFile( |
|||
$symfonyUploadedFile->getRealPath() |
|||
), |
|||
(int) $symfonyUploadedFile->getSize(), |
|||
$symfonyUploadedFile->getError(), |
|||
$symfonyUploadedFile->getClientOriginalName(), |
|||
$symfonyUploadedFile->getClientMimeType() |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function createResponse(Response $symfonyResponse) |
|||
{ |
|||
$response = $this->responseFactory->createResponse($symfonyResponse->getStatusCode(), Response::$statusTexts[$symfonyResponse->getStatusCode()] ?? ''); |
|||
|
|||
if ($symfonyResponse instanceof BinaryFileResponse) { |
|||
$stream = $this->streamFactory->createStreamFromFile( |
|||
$symfonyResponse->getFile()->getPathname() |
|||
); |
|||
} else { |
|||
$stream = $this->streamFactory->createStreamFromFile('php://temp', 'wb+'); |
|||
if ($symfonyResponse instanceof StreamedResponse) { |
|||
ob_start(function ($buffer) use ($stream) { |
|||
$stream->write($buffer); |
|||
|
|||
return ''; |
|||
}); |
|||
|
|||
$symfonyResponse->sendContent(); |
|||
ob_end_clean(); |
|||
} else { |
|||
$stream->write($symfonyResponse->getContent()); |
|||
} |
|||
} |
|||
|
|||
$response = $response->withBody($stream); |
|||
|
|||
$headers = $symfonyResponse->headers->all(); |
|||
$cookies = $symfonyResponse->headers->getCookies(); |
|||
if (!empty($cookies)) { |
|||
$headers['Set-Cookie'] = []; |
|||
|
|||
foreach ($cookies as $cookie) { |
|||
$headers['Set-Cookie'][] = $cookie->__toString(); |
|||
} |
|||
} |
|||
|
|||
foreach ($headers as $name => $value) { |
|||
$response = $response->withHeader($name, $value); |
|||
} |
|||
|
|||
$protocolVersion = $symfonyResponse->getProtocolVersion(); |
|||
$response = $response->withProtocolVersion($protocolVersion); |
|||
|
|||
return $response; |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage; |
|||
|
|||
use Psr\Http\Message\ResponseInterface; |
|||
use Psr\Http\Message\ServerRequestInterface; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
|
|||
/** |
|||
* Creates Symfony Request and Response instances from PSR-7 ones. |
|||
* |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
interface HttpFoundationFactoryInterface |
|||
{ |
|||
/** |
|||
* Creates a Symfony Request instance from a PSR-7 one. |
|||
* |
|||
* @param ServerRequestInterface $psrRequest |
|||
* |
|||
* @return Request |
|||
*/ |
|||
public function createRequest(ServerRequestInterface $psrRequest); |
|||
|
|||
/** |
|||
* Creates a Symfony Response instance from a PSR-7 one. |
|||
* |
|||
* @param ResponseInterface $psrResponse |
|||
* |
|||
* @return Response |
|||
*/ |
|||
public function createResponse(ResponseInterface $psrResponse); |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage; |
|||
|
|||
use Psr\Http\Message\ResponseInterface; |
|||
use Psr\Http\Message\ServerRequestInterface; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
|
|||
/** |
|||
* Creates PSR HTTP Request and Response instances from Symfony ones. |
|||
* |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
interface HttpMessageFactoryInterface |
|||
{ |
|||
/** |
|||
* Creates a PSR-7 Request instance from a Symfony one. |
|||
* |
|||
* @param Request $symfonyRequest |
|||
* |
|||
* @return ServerRequestInterface |
|||
*/ |
|||
public function createRequest(Request $symfonyRequest); |
|||
|
|||
/** |
|||
* Creates a PSR-7 Response instance from a Symfony one. |
|||
* |
|||
* @param Response $symfonyResponse |
|||
* |
|||
* @return ResponseInterface |
|||
*/ |
|||
public function createResponse(Response $symfonyResponse); |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2004-2016 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,20 @@ |
|||
PSR-7 Bridge |
|||
============ |
|||
|
|||
Provides integration for PSR7. |
|||
|
|||
Resources |
|||
--------- |
|||
|
|||
* [Documentation](https://symfony.com/doc/current/components/psr7.html) |
|||
* [SensioFrameworkExtraBundle](https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html#psr-7-support) |
|||
|
|||
Running the tests |
|||
----------------- |
|||
|
|||
If you want to run the unit tests, install dev dependencies before |
|||
running PHPUnit: |
|||
|
|||
$ cd path/to/Symfony/Bridge/PsrHttpMessage/ |
|||
$ composer.phar install |
|||
$ phpunit |
|||
@ -0,0 +1,229 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; |
|||
|
|||
use PHPUnit\Framework\TestCase; |
|||
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; |
|||
use Symfony\Component\HttpFoundation\BinaryFileResponse; |
|||
use Symfony\Component\HttpFoundation\Cookie; |
|||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
use Symfony\Component\HttpFoundation\StreamedResponse; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
* @author Antonio J. García Lagar <aj@garcialagar.es> |
|||
*/ |
|||
abstract class AbstractHttpMessageFactoryTest extends TestCase |
|||
{ |
|||
private $factory; |
|||
private $tmpDir; |
|||
|
|||
/** |
|||
* @return HttpMessageFactoryInterface |
|||
*/ |
|||
abstract protected function buildHttpMessageFactory(); |
|||
|
|||
public function setup() |
|||
{ |
|||
$this->factory = $this->buildHttpMessageFactory(); |
|||
$this->tmpDir = sys_get_temp_dir(); |
|||
} |
|||
|
|||
public function testCreateRequest() |
|||
{ |
|||
$stdClass = new \stdClass(); |
|||
$request = new Request( |
|||
[ |
|||
'bar' => ['baz' => '42'], |
|||
'foo' => '1', |
|||
], |
|||
[ |
|||
'twitter' => [ |
|||
'@dunglas' => 'Kévin Dunglas', |
|||
'@coopTilleuls' => 'Les-Tilleuls.coop', |
|||
], |
|||
'baz' => '2', |
|||
], |
|||
[ |
|||
'a1' => $stdClass, |
|||
'a2' => ['foo' => 'bar'], |
|||
], |
|||
[ |
|||
'c1' => 'foo', |
|||
'c2' => ['c3' => 'bar'], |
|||
], |
|||
[ |
|||
'f1' => $this->createUploadedFile('F1', 'f1.txt', 'text/plain', UPLOAD_ERR_OK), |
|||
'foo' => ['f2' => $this->createUploadedFile('F2', 'f2.txt', 'text/plain', UPLOAD_ERR_OK)], |
|||
], |
|||
[ |
|||
'REQUEST_METHOD' => 'POST', |
|||
'HTTP_HOST' => 'dunglas.fr', |
|||
'HTTP_X_SYMFONY' => '2.8', |
|||
'REQUEST_URI' => '/testCreateRequest?bar[baz]=42&foo=1', |
|||
'QUERY_STRING' => 'bar[baz]=42&foo=1', |
|||
], |
|||
'Content' |
|||
); |
|||
|
|||
$psrRequest = $this->factory->createRequest($request); |
|||
|
|||
$this->assertEquals('Content', $psrRequest->getBody()->__toString()); |
|||
|
|||
$queryParams = $psrRequest->getQueryParams(); |
|||
$this->assertEquals('1', $queryParams['foo']); |
|||
$this->assertEquals('42', $queryParams['bar']['baz']); |
|||
|
|||
$requestTarget = $psrRequest->getRequestTarget(); |
|||
$this->assertEquals('/testCreateRequest?bar[baz]=42&foo=1', urldecode($requestTarget)); |
|||
|
|||
$parsedBody = $psrRequest->getParsedBody(); |
|||
$this->assertEquals('Kévin Dunglas', $parsedBody['twitter']['@dunglas']); |
|||
$this->assertEquals('Les-Tilleuls.coop', $parsedBody['twitter']['@coopTilleuls']); |
|||
$this->assertEquals('2', $parsedBody['baz']); |
|||
|
|||
$attributes = $psrRequest->getAttributes(); |
|||
$this->assertEquals($stdClass, $attributes['a1']); |
|||
$this->assertEquals('bar', $attributes['a2']['foo']); |
|||
|
|||
$cookies = $psrRequest->getCookieParams(); |
|||
$this->assertEquals('foo', $cookies['c1']); |
|||
$this->assertEquals('bar', $cookies['c2']['c3']); |
|||
|
|||
$uploadedFiles = $psrRequest->getUploadedFiles(); |
|||
$this->assertEquals('F1', $uploadedFiles['f1']->getStream()->__toString()); |
|||
$this->assertEquals('f1.txt', $uploadedFiles['f1']->getClientFilename()); |
|||
$this->assertEquals('text/plain', $uploadedFiles['f1']->getClientMediaType()); |
|||
$this->assertEquals(UPLOAD_ERR_OK, $uploadedFiles['f1']->getError()); |
|||
|
|||
$this->assertEquals('F2', $uploadedFiles['foo']['f2']->getStream()->__toString()); |
|||
$this->assertEquals('f2.txt', $uploadedFiles['foo']['f2']->getClientFilename()); |
|||
$this->assertEquals('text/plain', $uploadedFiles['foo']['f2']->getClientMediaType()); |
|||
$this->assertEquals(UPLOAD_ERR_OK, $uploadedFiles['foo']['f2']->getError()); |
|||
|
|||
$serverParams = $psrRequest->getServerParams(); |
|||
$this->assertEquals('POST', $serverParams['REQUEST_METHOD']); |
|||
$this->assertEquals('2.8', $serverParams['HTTP_X_SYMFONY']); |
|||
$this->assertEquals('POST', $psrRequest->getMethod()); |
|||
$this->assertEquals(['2.8'], $psrRequest->getHeader('X-Symfony')); |
|||
} |
|||
|
|||
public function testGetContentCanBeCalledAfterRequestCreation() |
|||
{ |
|||
$header = ['HTTP_HOST' => 'dunglas.fr']; |
|||
$request = new Request([], [], [], [], [], $header, 'Content'); |
|||
|
|||
$psrRequest = $this->factory->createRequest($request); |
|||
|
|||
$this->assertEquals('Content', $psrRequest->getBody()->__toString()); |
|||
$this->assertEquals('Content', $request->getContent()); |
|||
} |
|||
|
|||
private function createUploadedFile($content, $originalName, $mimeType, $error) |
|||
{ |
|||
$path = tempnam($this->tmpDir, uniqid()); |
|||
file_put_contents($path, $content); |
|||
|
|||
if (class_exists('Symfony\Component\HttpFoundation\HeaderUtils')) { |
|||
// Symfony 4.1+ |
|||
return new UploadedFile($path, $originalName, $mimeType, $error, true); |
|||
} |
|||
|
|||
return new UploadedFile($path, $originalName, $mimeType, filesize($path), $error, true); |
|||
} |
|||
|
|||
public function testCreateResponse() |
|||
{ |
|||
$response = new Response( |
|||
'Response content.', |
|||
202, |
|||
['X-Symfony' => ['3.4']] |
|||
); |
|||
$response->headers->setCookie(new Cookie('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT'), '/', null, false, true, false, 'lax')); |
|||
|
|||
$psrResponse = $this->factory->createResponse($response); |
|||
$this->assertEquals('Response content.', $psrResponse->getBody()->__toString()); |
|||
$this->assertEquals(202, $psrResponse->getStatusCode()); |
|||
$this->assertEquals(['3.4'], $psrResponse->getHeader('X-Symfony')); |
|||
|
|||
$cookieHeader = $psrResponse->getHeader('Set-Cookie'); |
|||
$this->assertInternalType('array', $cookieHeader); |
|||
$this->assertCount(1, $cookieHeader); |
|||
$this->assertRegExp('{city=Lille; expires=Wed, 13-Jan-2021 22:23:01 GMT;( max-age=\d+;)? path=/; httponly}i', $cookieHeader[0]); |
|||
} |
|||
|
|||
public function testCreateResponseFromStreamed() |
|||
{ |
|||
$response = new StreamedResponse(function () { |
|||
echo "Line 1\n"; |
|||
flush(); |
|||
|
|||
echo "Line 2\n"; |
|||
flush(); |
|||
}); |
|||
|
|||
$psrResponse = $this->factory->createResponse($response); |
|||
|
|||
$this->assertEquals("Line 1\nLine 2\n", $psrResponse->getBody()->__toString()); |
|||
} |
|||
|
|||
public function testCreateResponseFromBinaryFile() |
|||
{ |
|||
$path = tempnam($this->tmpDir, uniqid()); |
|||
file_put_contents($path, 'Binary'); |
|||
|
|||
$response = new BinaryFileResponse($path); |
|||
|
|||
$psrResponse = $this->factory->createResponse($response); |
|||
|
|||
$this->assertEquals('Binary', $psrResponse->getBody()->__toString()); |
|||
} |
|||
|
|||
public function testUploadErrNoFile() |
|||
{ |
|||
if (class_exists('Symfony\Component\HttpFoundation\HeaderUtils')) { |
|||
// Symfony 4.1+ |
|||
$file = new UploadedFile('', '', null, UPLOAD_ERR_NO_FILE, true); |
|||
} else { |
|||
$file = new UploadedFile('', '', null, 0, UPLOAD_ERR_NO_FILE, true); |
|||
} |
|||
$this->assertEquals(0, $file->getSize()); |
|||
$this->assertEquals(UPLOAD_ERR_NO_FILE, $file->getError()); |
|||
$this->assertFalse($file->getSize(), 'SplFile::getSize() returns false on error'); |
|||
|
|||
$request = new Request( |
|||
[], |
|||
[], |
|||
[], |
|||
[], |
|||
[ |
|||
'f1' => $file, |
|||
'f2' => ['name' => null, 'type' => null, 'tmp_name' => null, 'error' => UPLOAD_ERR_NO_FILE, 'size' => 0], |
|||
], |
|||
[ |
|||
'REQUEST_METHOD' => 'POST', |
|||
'HTTP_HOST' => 'dunglas.fr', |
|||
'HTTP_X_SYMFONY' => '2.8', |
|||
], |
|||
'Content' |
|||
); |
|||
|
|||
$psrRequest = $this->factory->createRequest($request); |
|||
|
|||
$uploadedFiles = $psrRequest->getUploadedFiles(); |
|||
|
|||
$this->assertEquals(UPLOAD_ERR_NO_FILE, $uploadedFiles['f1']->getError()); |
|||
$this->assertEquals(UPLOAD_ERR_NO_FILE, $uploadedFiles['f2']->getError()); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; |
|||
|
|||
use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
* @author Antonio J. García Lagar <aj@garcialagar.es> |
|||
* |
|||
* @group legacy |
|||
*/ |
|||
class DiactorosFactoryTest extends AbstractHttpMessageFactoryTest |
|||
{ |
|||
protected function buildHttpMessageFactory() |
|||
{ |
|||
if (!class_exists('Zend\Diactoros\ServerRequestFactory')) { |
|||
$this->markTestSkipped('Zend Diactoros is not installed.'); |
|||
} |
|||
|
|||
return new DiactorosFactory(); |
|||
} |
|||
} |
|||
@ -0,0 +1,250 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; |
|||
|
|||
use PHPUnit\Framework\TestCase; |
|||
use Psr\Http\Message\UploadedFileInterface; |
|||
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; |
|||
use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\Response; |
|||
use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\ServerRequest; |
|||
use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\Stream; |
|||
use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\UploadedFile; |
|||
use Symfony\Bridge\PsrHttpMessage\Tests\Fixtures\Uri; |
|||
use Symfony\Component\HttpFoundation\Cookie; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class HttpFoundationFactoryTest extends TestCase |
|||
{ |
|||
/** @var HttpFoundationFactory */ |
|||
private $factory; |
|||
|
|||
/** @var string */ |
|||
private $tmpDir; |
|||
|
|||
public function setup() |
|||
{ |
|||
$this->factory = new HttpFoundationFactory(); |
|||
$this->tmpDir = sys_get_temp_dir(); |
|||
} |
|||
|
|||
public function testCreateRequest() |
|||
{ |
|||
$stdClass = new \stdClass(); |
|||
$serverRequest = new ServerRequest( |
|||
'1.1', |
|||
[ |
|||
'X-Dunglas-API-Platform' => '1.0', |
|||
'X-data' => ['a', 'b'], |
|||
], |
|||
new Stream('The body'), |
|||
'/about/kevin', |
|||
'GET', |
|||
'http://les-tilleuls.coop/about/kevin', |
|||
['country' => 'France'], |
|||
['city' => 'Lille'], |
|||
['url' => 'http://les-tilleuls.coop'], |
|||
[ |
|||
'doc1' => $this->createUploadedFile('Doc 1', UPLOAD_ERR_OK, 'doc1.txt', 'text/plain'), |
|||
'nested' => [ |
|||
'docs' => [ |
|||
$this->createUploadedFile('Doc 2', UPLOAD_ERR_OK, 'doc2.txt', 'text/plain'), |
|||
$this->createUploadedFile('Doc 3', UPLOAD_ERR_OK, 'doc3.txt', 'text/plain'), |
|||
], |
|||
], |
|||
], |
|||
['url' => 'http://dunglas.fr'], |
|||
['custom' => $stdClass] |
|||
); |
|||
|
|||
$symfonyRequest = $this->factory->createRequest($serverRequest); |
|||
$files = $symfonyRequest->files->all(); |
|||
|
|||
$this->assertEquals('http://les-tilleuls.coop', $symfonyRequest->query->get('url')); |
|||
$this->assertEquals('doc1.txt', $files['doc1']->getClientOriginalName()); |
|||
$this->assertEquals('doc2.txt', $files['nested']['docs'][0]->getClientOriginalName()); |
|||
$this->assertEquals('doc3.txt', $files['nested']['docs'][1]->getClientOriginalName()); |
|||
$this->assertEquals('http://dunglas.fr', $symfonyRequest->request->get('url')); |
|||
$this->assertEquals($stdClass, $symfonyRequest->attributes->get('custom')); |
|||
$this->assertEquals('Lille', $symfonyRequest->cookies->get('city')); |
|||
$this->assertEquals('France', $symfonyRequest->server->get('country')); |
|||
$this->assertEquals('The body', $symfonyRequest->getContent()); |
|||
$this->assertEquals('1.0', $symfonyRequest->headers->get('X-Dunglas-API-Platform')); |
|||
$this->assertEquals(['a', 'b'], $symfonyRequest->headers->get('X-data', null, false)); |
|||
} |
|||
|
|||
public function testCreateRequestWithNullParsedBody() |
|||
{ |
|||
$serverRequest = new ServerRequest( |
|||
'1.1', |
|||
[], |
|||
new Stream(), |
|||
'/', |
|||
'GET', |
|||
null, |
|||
[], |
|||
[], |
|||
[], |
|||
[], |
|||
null, |
|||
[] |
|||
); |
|||
|
|||
$this->assertCount(0, $this->factory->createRequest($serverRequest)->request); |
|||
} |
|||
|
|||
public function testCreateRequestWithObjectParsedBody() |
|||
{ |
|||
$serverRequest = new ServerRequest( |
|||
'1.1', |
|||
[], |
|||
new Stream(), |
|||
'/', |
|||
'GET', |
|||
null, |
|||
[], |
|||
[], |
|||
[], |
|||
[], |
|||
new \stdClass(), |
|||
[] |
|||
); |
|||
|
|||
$this->assertCount(0, $this->factory->createRequest($serverRequest)->request); |
|||
} |
|||
|
|||
public function testCreateRequestWithUri() |
|||
{ |
|||
$serverRequest = new ServerRequest( |
|||
'1.1', |
|||
[], |
|||
new Stream(), |
|||
'/', |
|||
'GET', |
|||
new Uri('http://les-tilleuls.coop/about/kevin'), |
|||
[], |
|||
[], |
|||
[], |
|||
[], |
|||
null, |
|||
[] |
|||
); |
|||
|
|||
$this->assertEquals('/about/kevin', $this->factory->createRequest($serverRequest)->getPathInfo()); |
|||
} |
|||
|
|||
public function testCreateUploadedFile() |
|||
{ |
|||
$uploadedFile = $this->createUploadedFile('An uploaded file.', UPLOAD_ERR_OK, 'myfile.txt', 'text/plain'); |
|||
$symfonyUploadedFile = $this->callCreateUploadedFile($uploadedFile); |
|||
$size = $symfonyUploadedFile->getSize(); |
|||
|
|||
$uniqid = uniqid(); |
|||
$symfonyUploadedFile->move($this->tmpDir, $uniqid); |
|||
|
|||
$this->assertEquals($uploadedFile->getSize(), $size); |
|||
$this->assertEquals(UPLOAD_ERR_OK, $symfonyUploadedFile->getError()); |
|||
$this->assertEquals('myfile.txt', $symfonyUploadedFile->getClientOriginalName()); |
|||
$this->assertEquals('txt', $symfonyUploadedFile->getClientOriginalExtension()); |
|||
$this->assertEquals('text/plain', $symfonyUploadedFile->getClientMimeType()); |
|||
$this->assertEquals('An uploaded file.', file_get_contents($this->tmpDir.'/'.$uniqid)); |
|||
} |
|||
|
|||
/** |
|||
* @expectedException \Symfony\Component\HttpFoundation\File\Exception\FileException |
|||
* @expectedExceptionMessage The file "e" could not be written on disk. |
|||
*/ |
|||
public function testCreateUploadedFileWithError() |
|||
{ |
|||
$uploadedFile = $this->createUploadedFile('Error.', UPLOAD_ERR_CANT_WRITE, 'e', 'text/plain'); |
|||
$symfonyUploadedFile = $this->callCreateUploadedFile($uploadedFile); |
|||
|
|||
$this->assertEquals(UPLOAD_ERR_CANT_WRITE, $symfonyUploadedFile->getError()); |
|||
|
|||
$symfonyUploadedFile->move($this->tmpDir, 'shouldFail.txt'); |
|||
} |
|||
|
|||
private function createUploadedFile($content, $error, $clientFileName, $clientMediaType) |
|||
{ |
|||
$filePath = tempnam($this->tmpDir, uniqid()); |
|||
file_put_contents($filePath, $content); |
|||
|
|||
return new UploadedFile($filePath, filesize($filePath), $error, $clientFileName, $clientMediaType); |
|||
} |
|||
|
|||
private function callCreateUploadedFile(UploadedFileInterface $uploadedFile) |
|||
{ |
|||
$reflection = new \ReflectionClass($this->factory); |
|||
$createUploadedFile = $reflection->getMethod('createUploadedFile'); |
|||
$createUploadedFile->setAccessible(true); |
|||
|
|||
return $createUploadedFile->invokeArgs($this->factory, [$uploadedFile]); |
|||
} |
|||
|
|||
public function testCreateResponse() |
|||
{ |
|||
$response = new Response( |
|||
'1.0', |
|||
[ |
|||
'X-Symfony' => ['2.8'], |
|||
'Set-Cookie' => [ |
|||
'theme=light', |
|||
'test', |
|||
'ABC=AeD; Domain=dunglas.fr; Path=/kevin; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; SameSite=Strict', |
|||
], |
|||
], |
|||
new Stream('The response body'), |
|||
200 |
|||
); |
|||
|
|||
$symfonyResponse = $this->factory->createResponse($response); |
|||
|
|||
$this->assertEquals('1.0', $symfonyResponse->getProtocolVersion()); |
|||
$this->assertEquals('2.8', $symfonyResponse->headers->get('X-Symfony')); |
|||
|
|||
$cookies = $symfonyResponse->headers->getCookies(); |
|||
$this->assertEquals('theme', $cookies[0]->getName()); |
|||
$this->assertEquals('light', $cookies[0]->getValue()); |
|||
$this->assertEquals(0, $cookies[0]->getExpiresTime()); |
|||
$this->assertNull($cookies[0]->getDomain()); |
|||
$this->assertEquals('/', $cookies[0]->getPath()); |
|||
$this->assertFalse($cookies[0]->isSecure()); |
|||
$this->assertFalse($cookies[0]->isHttpOnly()); |
|||
|
|||
$this->assertEquals('test', $cookies[1]->getName()); |
|||
$this->assertNull($cookies[1]->getValue()); |
|||
|
|||
$this->assertEquals('ABC', $cookies[2]->getName()); |
|||
$this->assertEquals('AeD', $cookies[2]->getValue()); |
|||
$this->assertEquals(strtotime('Wed, 13 Jan 2021 22:23:01 GMT'), $cookies[2]->getExpiresTime()); |
|||
$this->assertEquals('dunglas.fr', $cookies[2]->getDomain()); |
|||
$this->assertEquals('/kevin', $cookies[2]->getPath()); |
|||
$this->assertTrue($cookies[2]->isSecure()); |
|||
$this->assertTrue($cookies[2]->isHttpOnly()); |
|||
if (\defined('Symfony\Component\HttpFoundation\Cookie::SAMESITE_STRICT')) { |
|||
$this->assertEquals(Cookie::SAMESITE_STRICT, $cookies[2]->getSameSite()); |
|||
} |
|||
|
|||
$this->assertEquals('The response body', $symfonyResponse->getContent()); |
|||
$this->assertEquals(200, $symfonyResponse->getStatusCode()); |
|||
|
|||
$symfonyResponse = $this->factory->createResponse($response, true); |
|||
|
|||
ob_start(); |
|||
$symfonyResponse->sendContent(); |
|||
$sentContent = ob_get_clean(); |
|||
|
|||
$this->assertEquals('The response body', $sentContent); |
|||
$this->assertEquals(200, $symfonyResponse->getStatusCode()); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Factory; |
|||
|
|||
use Nyholm\Psr7\Factory\Psr17Factory; |
|||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
* @author Antonio J. García Lagar <aj@garcialagar.es> |
|||
*/ |
|||
class PsrHttpFactoryTest extends AbstractHttpMessageFactoryTest |
|||
{ |
|||
protected function buildHttpMessageFactory() |
|||
{ |
|||
$factory = new Psr17Factory(); |
|||
|
|||
return new PsrHttpFactory($factory, $factory, $factory, $factory); |
|||
} |
|||
} |
|||
@ -0,0 +1,93 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; |
|||
|
|||
use Psr\Http\Message\MessageInterface; |
|||
use Psr\Http\Message\StreamInterface; |
|||
|
|||
/** |
|||
* Message. |
|||
* |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class Message implements MessageInterface |
|||
{ |
|||
private $version = '1.1'; |
|||
private $headers = []; |
|||
private $body; |
|||
|
|||
public function __construct($version = '1.1', array $headers = [], StreamInterface $body = null) |
|||
{ |
|||
$this->version = $version; |
|||
$this->headers = $headers; |
|||
$this->body = null === $body ? new Stream() : $body; |
|||
} |
|||
|
|||
public function getProtocolVersion() |
|||
{ |
|||
return $this->version; |
|||
} |
|||
|
|||
public function withProtocolVersion($version) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getHeaders() |
|||
{ |
|||
return $this->headers; |
|||
} |
|||
|
|||
public function hasHeader($name) |
|||
{ |
|||
return isset($this->headers[$name]); |
|||
} |
|||
|
|||
public function getHeader($name) |
|||
{ |
|||
return $this->hasHeader($name) ? $this->headers[$name] : []; |
|||
} |
|||
|
|||
public function getHeaderLine($name) |
|||
{ |
|||
return $this->hasHeader($name) ? implode(',', $this->headers[$name]) : ''; |
|||
} |
|||
|
|||
public function withHeader($name, $value) |
|||
{ |
|||
$this->headers[$name] = (array) $value; |
|||
|
|||
return $this; |
|||
} |
|||
|
|||
public function withAddedHeader($name, $value) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withoutHeader($name) |
|||
{ |
|||
unset($this->headers[$name]); |
|||
|
|||
return $this; |
|||
} |
|||
|
|||
public function getBody() |
|||
{ |
|||
return $this->body; |
|||
} |
|||
|
|||
public function withBody(StreamInterface $body) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; |
|||
|
|||
use Psr\Http\Message\ResponseInterface; |
|||
use Psr\Http\Message\StreamInterface; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class Response extends Message implements ResponseInterface |
|||
{ |
|||
private $statusCode; |
|||
|
|||
public function __construct($version = '1.1', array $headers = [], StreamInterface $body = null, $statusCode = 200) |
|||
{ |
|||
parent::__construct($version, $headers, $body); |
|||
|
|||
$this->statusCode = $statusCode; |
|||
} |
|||
|
|||
public function getStatusCode() |
|||
{ |
|||
return $this->statusCode; |
|||
} |
|||
|
|||
public function withStatus($code, $reasonPhrase = '') |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getReasonPhrase() |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
} |
|||
@ -0,0 +1,141 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; |
|||
|
|||
use Psr\Http\Message\ServerRequestInterface; |
|||
use Psr\Http\Message\StreamInterface; |
|||
use Psr\Http\Message\UriInterface; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class ServerRequest extends Message implements ServerRequestInterface |
|||
{ |
|||
private $requestTarget; |
|||
private $method; |
|||
private $uri; |
|||
private $server; |
|||
private $cookies; |
|||
private $query; |
|||
private $uploadedFiles; |
|||
private $data; |
|||
private $attributes; |
|||
|
|||
public function __construct($version = '1.1', array $headers = [], StreamInterface $body = null, $requestTarget = '/', $method = 'GET', $uri = null, array $server = [], array $cookies = [], array $query = [], array $uploadedFiles = [], $data = null, array $attributes = []) |
|||
{ |
|||
parent::__construct($version, $headers, $body); |
|||
|
|||
$this->requestTarget = $requestTarget; |
|||
$this->method = $method; |
|||
$this->uri = $uri; |
|||
$this->server = $server; |
|||
$this->cookies = $cookies; |
|||
$this->query = $query; |
|||
$this->uploadedFiles = $uploadedFiles; |
|||
$this->data = $data; |
|||
$this->attributes = $attributes; |
|||
} |
|||
|
|||
public function getRequestTarget() |
|||
{ |
|||
return $this->requestTarget; |
|||
} |
|||
|
|||
public function withRequestTarget($requestTarget) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getMethod() |
|||
{ |
|||
return $this->method; |
|||
} |
|||
|
|||
public function withMethod($method) |
|||
{ |
|||
} |
|||
|
|||
public function getUri() |
|||
{ |
|||
return $this->uri; |
|||
} |
|||
|
|||
public function withUri(UriInterface $uri, $preserveHost = false) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getServerParams() |
|||
{ |
|||
return $this->server; |
|||
} |
|||
|
|||
public function getCookieParams() |
|||
{ |
|||
return $this->cookies; |
|||
} |
|||
|
|||
public function withCookieParams(array $cookies) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getQueryParams() |
|||
{ |
|||
return $this->query; |
|||
} |
|||
|
|||
public function withQueryParams(array $query) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getUploadedFiles() |
|||
{ |
|||
return $this->uploadedFiles; |
|||
} |
|||
|
|||
public function withUploadedFiles(array $uploadedFiles) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getParsedBody() |
|||
{ |
|||
return $this->data; |
|||
} |
|||
|
|||
public function withParsedBody($data) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function getAttributes() |
|||
{ |
|||
return $this->attributes; |
|||
} |
|||
|
|||
public function getAttribute($name, $default = null) |
|||
{ |
|||
return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; |
|||
} |
|||
|
|||
public function withAttribute($name, $value) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withoutAttribute($name) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; |
|||
|
|||
use Psr\Http\Message\StreamInterface; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class Stream implements StreamInterface |
|||
{ |
|||
private $stringContent; |
|||
private $eof = true; |
|||
|
|||
public function __construct($stringContent = '') |
|||
{ |
|||
$this->stringContent = $stringContent; |
|||
} |
|||
|
|||
public function __toString() |
|||
{ |
|||
return $this->stringContent; |
|||
} |
|||
|
|||
public function close() |
|||
{ |
|||
} |
|||
|
|||
public function detach() |
|||
{ |
|||
} |
|||
|
|||
public function getSize() |
|||
{ |
|||
} |
|||
|
|||
public function tell() |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
public function eof() |
|||
{ |
|||
return $this->eof; |
|||
} |
|||
|
|||
public function isSeekable() |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
public function seek($offset, $whence = SEEK_SET) |
|||
{ |
|||
} |
|||
|
|||
public function rewind() |
|||
{ |
|||
$this->eof = false; |
|||
} |
|||
|
|||
public function isWritable() |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
public function write($string) |
|||
{ |
|||
} |
|||
|
|||
public function isReadable() |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
public function read($length) |
|||
{ |
|||
$this->eof = true; |
|||
|
|||
return $this->stringContent; |
|||
} |
|||
|
|||
public function getContents() |
|||
{ |
|||
return $this->stringContent; |
|||
} |
|||
|
|||
public function getMetadata($key = null) |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; |
|||
|
|||
use Psr\Http\Message\UploadedFileInterface; |
|||
|
|||
/** |
|||
* @author Kévin Dunglas <dunglas@gmail.com> |
|||
*/ |
|||
class UploadedFile implements UploadedFileInterface |
|||
{ |
|||
private $filePath; |
|||
private $size; |
|||
private $error; |
|||
private $clientFileName; |
|||
private $clientMediaType; |
|||
|
|||
public function __construct($filePath, $size = null, $error = UPLOAD_ERR_OK, $clientFileName = null, $clientMediaType = null) |
|||
{ |
|||
$this->filePath = $filePath; |
|||
$this->size = $size; |
|||
$this->error = $error; |
|||
$this->clientFileName = $clientFileName; |
|||
$this->clientMediaType = $clientMediaType; |
|||
} |
|||
|
|||
public function getStream() |
|||
{ |
|||
throw new \RuntimeException('No stream is available.'); |
|||
} |
|||
|
|||
public function moveTo($targetPath) |
|||
{ |
|||
rename($this->filePath, $targetPath); |
|||
} |
|||
|
|||
public function getSize() |
|||
{ |
|||
return $this->size; |
|||
} |
|||
|
|||
public function getError() |
|||
{ |
|||
return $this->error; |
|||
} |
|||
|
|||
public function getClientFilename() |
|||
{ |
|||
return $this->clientFileName; |
|||
} |
|||
|
|||
public function getClientMediaType() |
|||
{ |
|||
return $this->clientMediaType; |
|||
} |
|||
} |
|||
@ -0,0 +1,135 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Fixtures; |
|||
|
|||
use Psr\Http\Message\UriInterface; |
|||
|
|||
/** |
|||
* @author Rougin Royce Gutib <rougingutib@gmail.com> |
|||
*/ |
|||
class Uri implements UriInterface |
|||
{ |
|||
private $scheme = ''; |
|||
private $userInfo = ''; |
|||
private $host = ''; |
|||
private $port; |
|||
private $path = ''; |
|||
private $query = ''; |
|||
private $fragment = ''; |
|||
private $uriString; |
|||
|
|||
public function __construct($uri = '') |
|||
{ |
|||
$parts = parse_url($uri); |
|||
|
|||
$this->scheme = isset($parts['scheme']) ? $parts['scheme'] : ''; |
|||
$this->userInfo = isset($parts['user']) ? $parts['user'] : ''; |
|||
$this->host = isset($parts['host']) ? $parts['host'] : ''; |
|||
$this->port = isset($parts['port']) ? $parts['port'] : null; |
|||
$this->path = isset($parts['path']) ? $parts['path'] : ''; |
|||
$this->query = isset($parts['query']) ? $parts['query'] : ''; |
|||
$this->fragment = isset($parts['fragment']) ? $parts['fragment'] : ''; |
|||
$this->uriString = $uri; |
|||
} |
|||
|
|||
public function getScheme() |
|||
{ |
|||
return $this->scheme; |
|||
} |
|||
|
|||
public function getAuthority() |
|||
{ |
|||
if (empty($this->host)) { |
|||
return ''; |
|||
} |
|||
|
|||
$authority = $this->host; |
|||
|
|||
if (!empty($this->userInfo)) { |
|||
$authority = $this->userInfo.'@'.$authority; |
|||
} |
|||
|
|||
$authority .= ':'.$this->port; |
|||
|
|||
return $authority; |
|||
} |
|||
|
|||
public function getUserInfo() |
|||
{ |
|||
return $this->userInfo; |
|||
} |
|||
|
|||
public function getHost() |
|||
{ |
|||
return $this->host; |
|||
} |
|||
|
|||
public function getPort() |
|||
{ |
|||
return $this->port; |
|||
} |
|||
|
|||
public function getPath() |
|||
{ |
|||
return $this->path; |
|||
} |
|||
|
|||
public function getQuery() |
|||
{ |
|||
return $this->query; |
|||
} |
|||
|
|||
public function getFragment() |
|||
{ |
|||
return $this->fragment; |
|||
} |
|||
|
|||
public function withScheme($scheme) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withUserInfo($user, $password = null) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withHost($host) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withPort($port) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withPath($path) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withQuery($query) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function withFragment($fragment) |
|||
{ |
|||
throw new \BadMethodCallException('Not implemented.'); |
|||
} |
|||
|
|||
public function __toString() |
|||
{ |
|||
return $this->uriString; |
|||
} |
|||
} |
|||
@ -0,0 +1,239 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Bridge\PsrHttpMessage\Tests\Functional; |
|||
|
|||
use Nyholm\Psr7\Factory\Psr17Factory; |
|||
use Nyholm\Psr7\Response as Psr7Response; |
|||
use Nyholm\Psr7\ServerRequest as Psr7Request; |
|||
use Nyholm\Psr7\Stream as Psr7Stream; |
|||
use PHPUnit\Framework\TestCase; |
|||
use Psr\Http\Message\ResponseInterface; |
|||
use Psr\Http\Message\ServerRequestInterface; |
|||
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; |
|||
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory; |
|||
use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface; |
|||
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; |
|||
use Symfony\Component\HttpFoundation\Cookie; |
|||
use Symfony\Component\HttpFoundation\File\UploadedFile; |
|||
use Symfony\Component\HttpFoundation\Request; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
|
|||
/** |
|||
* Test to convert a request/response back and forth to make sure we do not loose data. |
|||
* |
|||
* @author Tobias Nyholm <tobias.nyholm@gmail.com> |
|||
*/ |
|||
class CovertTest extends TestCase |
|||
{ |
|||
private $tmpDir; |
|||
|
|||
public function setup() |
|||
{ |
|||
if (!class_exists('Nyholm\Psr7\ServerRequest')) { |
|||
$this->markTestSkipped('nyholm/psr7 is not installed.'); |
|||
} |
|||
|
|||
$this->tmpDir = sys_get_temp_dir(); |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider requestProvider |
|||
* |
|||
* @param Request|ServerRequestInterface $request |
|||
* @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $firstFactory |
|||
* @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $secondFactory |
|||
*/ |
|||
public function testConvertRequestMultipleTimes($request, $firstFactory, $secondFactory) |
|||
{ |
|||
$temporaryRequest = $firstFactory->createRequest($request); |
|||
$finalRequest = $secondFactory->createRequest($temporaryRequest); |
|||
|
|||
if ($finalRequest instanceof Request) { |
|||
$this->assertEquals($request->getBasePath(), $finalRequest->getBasePath()); |
|||
$this->assertEquals($request->getBaseUrl(), $finalRequest->getBaseUrl()); |
|||
$this->assertEquals($request->getContent(), $finalRequest->getContent()); |
|||
$this->assertEquals($request->getEncodings(), $finalRequest->getEncodings()); |
|||
$this->assertEquals($request->getETags(), $finalRequest->getETags()); |
|||
$this->assertEquals($request->getHost(), $finalRequest->getHost()); |
|||
$this->assertEquals($request->getHttpHost(), $finalRequest->getHttpHost()); |
|||
$this->assertEquals($request->getMethod(), $finalRequest->getMethod()); |
|||
$this->assertEquals($request->getPassword(), $finalRequest->getPassword()); |
|||
$this->assertEquals($request->getPathInfo(), $finalRequest->getPathInfo()); |
|||
$this->assertEquals($request->getPort(), $finalRequest->getPort()); |
|||
$this->assertEquals($request->getProtocolVersion(), $finalRequest->getProtocolVersion()); |
|||
$this->assertEquals($request->getQueryString(), $finalRequest->getQueryString()); |
|||
$this->assertEquals($request->getRequestUri(), $finalRequest->getRequestUri()); |
|||
$this->assertEquals($request->getScheme(), $finalRequest->getScheme()); |
|||
$this->assertEquals($request->getSchemeAndHttpHost(), $finalRequest->getSchemeAndHttpHost()); |
|||
$this->assertEquals($request->getScriptName(), $finalRequest->getScriptName()); |
|||
$this->assertEquals($request->getUri(), $finalRequest->getUri()); |
|||
$this->assertEquals($request->getUser(), $finalRequest->getUser()); |
|||
$this->assertEquals($request->getUserInfo(), $finalRequest->getUserInfo()); |
|||
} elseif ($finalRequest instanceof ServerRequestInterface) { |
|||
$strToLower = function ($arr) { |
|||
foreach ($arr as $key => $value) { |
|||
yield strtolower($key) => $value; |
|||
} |
|||
}; |
|||
$this->assertEquals($request->getAttributes(), $finalRequest->getAttributes()); |
|||
$this->assertEquals($request->getCookieParams(), $finalRequest->getCookieParams()); |
|||
$this->assertEquals((array) $request->getParsedBody(), (array) $finalRequest->getParsedBody()); |
|||
$this->assertEquals($request->getQueryParams(), $finalRequest->getQueryParams()); |
|||
// PSR7 does not define a "withServerParams" so this is impossible to implement without knowing the PSR7 implementation. |
|||
//$this->assertEquals($request->getServerParams(), $finalRequest->getServerParams()); |
|||
$this->assertEquals($request->getUploadedFiles(), $finalRequest->getUploadedFiles()); |
|||
$this->assertEquals($request->getMethod(), $finalRequest->getMethod()); |
|||
$this->assertEquals($request->getRequestTarget(), $finalRequest->getRequestTarget()); |
|||
$this->assertEquals((string) $request->getUri(), (string) $finalRequest->getUri()); |
|||
$this->assertEquals((string) $request->getBody(), (string) $finalRequest->getBody()); |
|||
$this->assertEquals($strToLower($request->getHeaders()), $strToLower($finalRequest->getHeaders())); |
|||
$this->assertEquals($request->getProtocolVersion(), $finalRequest->getProtocolVersion()); |
|||
} else { |
|||
$this->fail('$finalRequest must be an instance of PSR7 or a HTTPFoundation request'); |
|||
} |
|||
} |
|||
|
|||
public function requestProvider() |
|||
{ |
|||
$sfRequest = new Request( |
|||
[ |
|||
'foo' => '1', |
|||
'bar' => ['baz' => '42'], |
|||
], |
|||
[ |
|||
'twitter' => [ |
|||
'@dunglas' => 'Kévin Dunglas', |
|||
'@coopTilleuls' => 'Les-Tilleuls.coop', |
|||
], |
|||
'baz' => '2', |
|||
], |
|||
[ |
|||
'a2' => ['foo' => 'bar'], |
|||
], |
|||
[ |
|||
'c1' => 'foo', |
|||
'c2' => ['c3' => 'bar'], |
|||
], |
|||
[ |
|||
'f1' => $this->createUploadedFile('F1', 'f1.txt', 'text/plain', UPLOAD_ERR_OK), |
|||
'foo' => ['f2' => $this->createUploadedFile('F2', 'f2.txt', 'text/plain', UPLOAD_ERR_OK)], |
|||
], |
|||
[ |
|||
'REQUEST_METHOD' => 'POST', |
|||
'HTTP_HOST' => 'dunglas.fr', |
|||
'SERVER_NAME' => 'dunglas.fr', |
|||
'SERVER_PORT' => null, |
|||
'HTTP_X_SYMFONY' => '2.8', |
|||
'REQUEST_URI' => '/testCreateRequest?bar[baz]=42&foo=1', |
|||
'QUERY_STRING' => 'foo=1&bar[baz]=42', |
|||
], |
|||
'Content' |
|||
); |
|||
|
|||
$psr7Request = (new Psr7Request('POST', 'http://tnyholm.se/foo/?bar=biz')) |
|||
->withQueryParams(['bar' => 'biz']); |
|||
|
|||
$nyholmFactory = new Psr17Factory(); |
|||
$psr17Factory = new PsrHttpFactory($nyholmFactory, $nyholmFactory, $nyholmFactory, $nyholmFactory); |
|||
$symfonyFactory = new HttpFoundationFactory(); |
|||
|
|||
return [ |
|||
[$sfRequest, $psr17Factory, $symfonyFactory], |
|||
[$psr7Request, $symfonyFactory, $psr17Factory], |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* @dataProvider responseProvider |
|||
* |
|||
* @param Response|ResponseInterface $response |
|||
* @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $firstFactory |
|||
* @param HttpFoundationFactoryInterface|HttpMessageFactoryInterface $secondFactory |
|||
*/ |
|||
public function testConvertResponseMultipleTimes($response, $firstFactory, $secondFactory) |
|||
{ |
|||
$temporaryResponse = $firstFactory->createResponse($response); |
|||
$finalResponse = $secondFactory->createResponse($temporaryResponse); |
|||
|
|||
if ($finalResponse instanceof Response) { |
|||
$this->assertEquals($response->getAge(), $finalResponse->getAge()); |
|||
$this->assertEquals($response->getCharset(), $finalResponse->getCharset()); |
|||
$this->assertEquals($response->getContent(), $finalResponse->getContent()); |
|||
$this->assertEquals($response->getDate(), $finalResponse->getDate()); |
|||
$this->assertEquals($response->getEtag(), $finalResponse->getEtag()); |
|||
$this->assertEquals($response->getExpires(), $finalResponse->getExpires()); |
|||
$this->assertEquals($response->getLastModified(), $finalResponse->getLastModified()); |
|||
$this->assertEquals($response->getMaxAge(), $finalResponse->getMaxAge()); |
|||
$this->assertEquals($response->getProtocolVersion(), $finalResponse->getProtocolVersion()); |
|||
$this->assertEquals($response->getStatusCode(), $finalResponse->getStatusCode()); |
|||
$this->assertEquals($response->getTtl(), $finalResponse->getTtl()); |
|||
} elseif ($finalResponse instanceof ResponseInterface) { |
|||
$strToLower = function ($arr) { |
|||
foreach ($arr as $key => $value) { |
|||
yield strtolower($key) => $value; |
|||
} |
|||
}; |
|||
$this->assertEquals($response->getStatusCode(), $finalResponse->getStatusCode()); |
|||
$this->assertEquals($response->getReasonPhrase(), $finalResponse->getReasonPhrase()); |
|||
$this->assertEquals((string) $response->getBody(), (string) $finalResponse->getBody()); |
|||
$this->assertEquals($strToLower($response->getHeaders()), $strToLower($finalResponse->getHeaders())); |
|||
$this->assertEquals($response->getProtocolVersion(), $finalResponse->getProtocolVersion()); |
|||
} else { |
|||
$this->fail('$finalResponse must be an instance of PSR7 or a HTTPFoundation response'); |
|||
} |
|||
} |
|||
|
|||
public function responseProvider() |
|||
{ |
|||
$sfResponse = new Response( |
|||
'Response content.', |
|||
202, |
|||
['x-symfony' => ['3.4']] |
|||
); |
|||
|
|||
if (method_exists(Cookie::class, 'create')) { |
|||
$cookie = Cookie::create('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT')); |
|||
} else { |
|||
$cookie = new Cookie('city', 'Lille', new \DateTime('Wed, 13 Jan 2021 22:23:01 GMT')); |
|||
} |
|||
|
|||
$sfResponse->headers->setCookie($cookie); |
|||
$body = Psr7Stream::create(); |
|||
$status = 302; |
|||
$headers = [ |
|||
'location' => ['http://example.com/'], |
|||
]; |
|||
$zendResponse = new Psr7Response($status, $headers, $body); |
|||
|
|||
$nyholmFactory = new Psr17Factory(); |
|||
$psr17Factory = new PsrHttpFactory($nyholmFactory, $nyholmFactory, $nyholmFactory, $nyholmFactory); |
|||
$symfonyFactory = new HttpFoundationFactory(); |
|||
|
|||
return [ |
|||
[$sfResponse, $psr17Factory, $symfonyFactory], |
|||
[$zendResponse, $symfonyFactory, $psr17Factory], |
|||
]; |
|||
} |
|||
|
|||
private function createUploadedFile($content, $originalName, $mimeType, $error) |
|||
{ |
|||
$path = tempnam($this->tmpDir, uniqid()); |
|||
file_put_contents($path, $content); |
|||
|
|||
if (class_exists('Symfony\Component\HttpFoundation\HeaderUtils')) { |
|||
// Symfony 4.1+ |
|||
return new UploadedFile($path, $originalName, $mimeType, $error, true); |
|||
} |
|||
|
|||
return new UploadedFile($path, $originalName, $mimeType, filesize($path), $error, true); |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
{ |
|||
"name": "symfony/psr-http-message-bridge", |
|||
"type": "symfony-bridge", |
|||
"description": "PSR HTTP message bridge", |
|||
"keywords": ["http", "psr-7", "psr-17", "http-message"], |
|||
"homepage": "http://symfony.com", |
|||
"license": "MIT", |
|||
"authors": [ |
|||
{ |
|||
"name": "Fabien Potencier", |
|||
"email": "fabien@symfony.com" |
|||
}, |
|||
{ |
|||
"name": "Symfony Community", |
|||
"homepage": "http://symfony.com/contributors" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": "^7.1", |
|||
"psr/http-message": "^1.0", |
|||
"symfony/http-foundation": "^3.4 || ^4.0" |
|||
}, |
|||
"require-dev": { |
|||
"symfony/phpunit-bridge": "^3.4.20 || ^4.0", |
|||
"nyholm/psr7": "^1.1", |
|||
"zendframework/zend-diactoros": "^1.4.1 || ^2.0" |
|||
}, |
|||
"suggest": { |
|||
"nyholm/psr7": "For a super lightweight PSR-7/17 implementation" |
|||
}, |
|||
"autoload": { |
|||
"psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" }, |
|||
"exclude-from-classmap": [ |
|||
"/Tests/" |
|||
] |
|||
}, |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.2-dev" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
|
|||
<phpunit backupGlobals="false" |
|||
backupStaticAttributes="false" |
|||
colors="true" |
|||
convertErrorsToExceptions="true" |
|||
convertNoticesToExceptions="true" |
|||
convertWarningsToExceptions="true" |
|||
processIsolation="false" |
|||
stopOnFailure="false" |
|||
syntaxCheck="false" |
|||
bootstrap="vendor/autoload.php" |
|||
> |
|||
<testsuites> |
|||
<testsuite name="Symfony PSR-7 HTTP message Bridge Test Suite"> |
|||
<directory>./Tests/</directory> |
|||
</testsuite> |
|||
</testsuites> |
|||
|
|||
<filter> |
|||
<whitelist> |
|||
<directory>./</directory> |
|||
<exclude> |
|||
<directory>./Resources</directory> |
|||
<directory>./Tests</directory> |
|||
<directory>./vendor</directory> |
|||
</exclude> |
|||
</whitelist> |
|||
</filter> |
|||
</phpunit> |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2018-2019 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,9 @@ |
|||
Symfony Service Contracts |
|||
========================= |
|||
|
|||
A set of abstractions extracted out of the Symfony components. |
|||
|
|||
Can be used to build on semantics that the Symfony components proved useful - and |
|||
that already have battle tested implementations. |
|||
|
|||
See https://github.com/symfony/contracts/blob/master/README.md for more information. |
|||
@ -0,0 +1,30 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\Service; |
|||
|
|||
/** |
|||
* Provides a way to reset an object to its initial state. |
|||
* |
|||
* When calling the "reset()" method on an object, it should be put back to its |
|||
* initial state. This usually means clearing any internal buffers and forwarding |
|||
* the call to internal dependencies. All properties of the object should be put |
|||
* back to the same state it had when it was first ready to use. |
|||
* |
|||
* This method could be called, for example, to recycle objects that are used as |
|||
* services, so that they can be used to handle several requests in the same |
|||
* process loop (note that we advise making your services stateless instead of |
|||
* implementing this interface when possible.) |
|||
*/ |
|||
interface ResetInterface |
|||
{ |
|||
public function reset(); |
|||
} |
|||
@ -0,0 +1,122 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\Service; |
|||
|
|||
use Psr\Container\ContainerExceptionInterface; |
|||
use Psr\Container\NotFoundExceptionInterface; |
|||
|
|||
/** |
|||
* A trait to help implement ServiceProviderInterface. |
|||
* |
|||
* @author Robin Chalas <robin.chalas@gmail.com> |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
*/ |
|||
trait ServiceLocatorTrait |
|||
{ |
|||
private $factories; |
|||
private $loading = []; |
|||
private $providedTypes; |
|||
|
|||
/** |
|||
* @param callable[] $factories |
|||
*/ |
|||
public function __construct(array $factories) |
|||
{ |
|||
$this->factories = $factories; |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function has($id) |
|||
{ |
|||
return isset($this->factories[$id]); |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function get($id) |
|||
{ |
|||
if (!isset($this->factories[$id])) { |
|||
throw $this->createNotFoundException($id); |
|||
} |
|||
|
|||
if (isset($this->loading[$id])) { |
|||
$ids = array_values($this->loading); |
|||
$ids = \array_slice($this->loading, array_search($id, $ids)); |
|||
$ids[] = $id; |
|||
|
|||
throw $this->createCircularReferenceException($id, $ids); |
|||
} |
|||
|
|||
$this->loading[$id] = $id; |
|||
try { |
|||
return $this->factories[$id]($this); |
|||
} finally { |
|||
unset($this->loading[$id]); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* {@inheritdoc} |
|||
*/ |
|||
public function getProvidedServices(): array |
|||
{ |
|||
if (null === $this->providedTypes) { |
|||
$this->providedTypes = []; |
|||
|
|||
foreach ($this->factories as $name => $factory) { |
|||
if (!\is_callable($factory)) { |
|||
$this->providedTypes[$name] = '?'; |
|||
} else { |
|||
$type = (new \ReflectionFunction($factory))->getReturnType(); |
|||
|
|||
$this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').$type->getName() : '?'; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return $this->providedTypes; |
|||
} |
|||
|
|||
private function createNotFoundException(string $id): NotFoundExceptionInterface |
|||
{ |
|||
if (!$alternatives = array_keys($this->factories)) { |
|||
$message = 'is empty...'; |
|||
} else { |
|||
$last = array_pop($alternatives); |
|||
if ($alternatives) { |
|||
$message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); |
|||
} else { |
|||
$message = sprintf('only knows about the "%s" service.', $last); |
|||
} |
|||
} |
|||
|
|||
if ($this->loading) { |
|||
$message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); |
|||
} else { |
|||
$message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); |
|||
} |
|||
|
|||
return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { |
|||
}; |
|||
} |
|||
|
|||
private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface |
|||
{ |
|||
return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\Service; |
|||
|
|||
use Psr\Container\ContainerInterface; |
|||
|
|||
/** |
|||
* A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. |
|||
* |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* @author Mateusz Sip <mateusz.sip@gmail.com> |
|||
*/ |
|||
interface ServiceProviderInterface extends ContainerInterface |
|||
{ |
|||
/** |
|||
* Returns an associative array of service types keyed by the identifiers provided by the current container. |
|||
* |
|||
* Examples: |
|||
* |
|||
* * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface |
|||
* * ['foo' => '?'] means the container provides service name "foo" of unspecified type |
|||
* * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null |
|||
* |
|||
* @return string[] The provided service types, keyed by service names |
|||
*/ |
|||
public function getProvidedServices(): array; |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\Service; |
|||
|
|||
/** |
|||
* A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. |
|||
* |
|||
* The getSubscribedServices method returns an array of service types required by such instances, |
|||
* optionally keyed by the service names used internally. Service types that start with an interrogation |
|||
* mark "?" are optional, while the other ones are mandatory service dependencies. |
|||
* |
|||
* The injected service locators SHOULD NOT allow access to any other services not specified by the method. |
|||
* |
|||
* It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. |
|||
* This interface does not dictate any injection method for these service locators, although constructor |
|||
* injection is recommended. |
|||
* |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
*/ |
|||
interface ServiceSubscriberInterface |
|||
{ |
|||
/** |
|||
* Returns an array of service types required by such instances, optionally keyed by the service names used internally. |
|||
* |
|||
* For mandatory dependencies: |
|||
* |
|||
* * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name |
|||
* internally to fetch a service which must implement Psr\Log\LoggerInterface. |
|||
* * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name |
|||
* internally to fetch an iterable of Psr\Log\LoggerInterface instances. |
|||
* * ['Psr\Log\LoggerInterface'] is a shortcut for |
|||
* * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] |
|||
* |
|||
* otherwise: |
|||
* |
|||
* * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency |
|||
* * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency |
|||
* * ['?Psr\Log\LoggerInterface'] is a shortcut for |
|||
* * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] |
|||
* |
|||
* @return array The required service types, optionally keyed by service names |
|||
*/ |
|||
public static function getSubscribedServices(); |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\Service; |
|||
|
|||
use Psr\Container\ContainerInterface; |
|||
|
|||
/** |
|||
* Implementation of ServiceSubscriberInterface that determines subscribed services from |
|||
* private method return types. Service ids are available as "ClassName::methodName". |
|||
* |
|||
* @author Kevin Bond <kevinbond@gmail.com> |
|||
*/ |
|||
trait ServiceSubscriberTrait |
|||
{ |
|||
/** @var ContainerInterface */ |
|||
private $container; |
|||
|
|||
public static function getSubscribedServices(): array |
|||
{ |
|||
static $services; |
|||
|
|||
if (null !== $services) { |
|||
return $services; |
|||
} |
|||
|
|||
$services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : []; |
|||
|
|||
foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { |
|||
if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { |
|||
continue; |
|||
} |
|||
|
|||
if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { |
|||
$services[self::class.'::'.$method->name] = '?'.$returnType->getName(); |
|||
} |
|||
} |
|||
|
|||
return $services; |
|||
} |
|||
|
|||
/** |
|||
* @required |
|||
*/ |
|||
public function setContainer(ContainerInterface $container) |
|||
{ |
|||
$this->container = $container; |
|||
|
|||
if (\is_callable(['parent', __FUNCTION__])) { |
|||
return parent::setContainer($container); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Contracts\Service\Test; |
|||
|
|||
use PHPUnit\Framework\TestCase; |
|||
use Psr\Container\ContainerInterface; |
|||
use Symfony\Contracts\Service\ServiceLocatorTrait; |
|||
|
|||
class ServiceLocatorTest extends TestCase |
|||
{ |
|||
public function getServiceLocator(array $factories) |
|||
{ |
|||
return new class($factories) implements ContainerInterface { |
|||
use ServiceLocatorTrait; |
|||
}; |
|||
} |
|||
|
|||
public function testHas() |
|||
{ |
|||
$locator = $this->getServiceLocator([ |
|||
'foo' => function () { return 'bar'; }, |
|||
'bar' => function () { return 'baz'; }, |
|||
function () { return 'dummy'; }, |
|||
]); |
|||
|
|||
$this->assertTrue($locator->has('foo')); |
|||
$this->assertTrue($locator->has('bar')); |
|||
$this->assertFalse($locator->has('dummy')); |
|||
} |
|||
|
|||
public function testGet() |
|||
{ |
|||
$locator = $this->getServiceLocator([ |
|||
'foo' => function () { return 'bar'; }, |
|||
'bar' => function () { return 'baz'; }, |
|||
]); |
|||
|
|||
$this->assertSame('bar', $locator->get('foo')); |
|||
$this->assertSame('baz', $locator->get('bar')); |
|||
} |
|||
|
|||
public function testGetDoesNotMemoize() |
|||
{ |
|||
$i = 0; |
|||
$locator = $this->getServiceLocator([ |
|||
'foo' => function () use (&$i) { |
|||
++$i; |
|||
|
|||
return 'bar'; |
|||
}, |
|||
]); |
|||
|
|||
$this->assertSame('bar', $locator->get('foo')); |
|||
$this->assertSame('bar', $locator->get('foo')); |
|||
$this->assertSame(2, $i); |
|||
} |
|||
|
|||
public function testThrowsOnUndefinedInternalService() |
|||
{ |
|||
if (!$this->getExpectedException()) { |
|||
$this->expectException('Psr\Container\NotFoundExceptionInterface'); |
|||
$this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); |
|||
} |
|||
$locator = $this->getServiceLocator([ |
|||
'foo' => function () use (&$locator) { return $locator->get('bar'); }, |
|||
]); |
|||
|
|||
$locator->get('foo'); |
|||
} |
|||
|
|||
public function testThrowsOnCircularReference() |
|||
{ |
|||
$this->expectException('Psr\Container\ContainerExceptionInterface'); |
|||
$this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); |
|||
$locator = $this->getServiceLocator([ |
|||
'foo' => function () use (&$locator) { return $locator->get('bar'); }, |
|||
'bar' => function () use (&$locator) { return $locator->get('baz'); }, |
|||
'baz' => function () use (&$locator) { return $locator->get('bar'); }, |
|||
]); |
|||
|
|||
$locator->get('foo'); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
{ |
|||
"name": "symfony/service-contracts", |
|||
"type": "library", |
|||
"description": "Generic abstractions related to writing services", |
|||
"keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], |
|||
"homepage": "https://symfony.com", |
|||
"license": "MIT", |
|||
"authors": [ |
|||
{ |
|||
"name": "Nicolas Grekas", |
|||
"email": "p@tchwork.com" |
|||
}, |
|||
{ |
|||
"name": "Symfony Community", |
|||
"homepage": "https://symfony.com/contributors" |
|||
} |
|||
], |
|||
"require": { |
|||
"php": "^7.1.3", |
|||
"psr/container": "^1.0" |
|||
}, |
|||
"suggest": { |
|||
"symfony/service-implementation": "" |
|||
}, |
|||
"autoload": { |
|||
"psr-4": { "Symfony\\Contracts\\Service\\": "" } |
|||
}, |
|||
"minimum-stability": "dev", |
|||
"extra": { |
|||
"branch-alias": { |
|||
"dev-master": "1.1-dev" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
composer.lock |
|||
phpunit.xml |
|||
vendor/ |
|||
@ -0,0 +1,7 @@ |
|||
CHANGELOG |
|||
========= |
|||
|
|||
4.2.0 |
|||
----- |
|||
|
|||
* added the component |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Exception; |
|||
|
|||
class ClassNotFoundException extends \Exception implements ExceptionInterface |
|||
{ |
|||
public function __construct(string $class, \Throwable $previous = null) |
|||
{ |
|||
parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Exception; |
|||
|
|||
interface ExceptionInterface extends \Throwable |
|||
{ |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Exception; |
|||
|
|||
class NotInstantiableTypeException extends \Exception implements ExceptionInterface |
|||
{ |
|||
public function __construct(string $type) |
|||
{ |
|||
parent::__construct(sprintf('Type "%s" is not instantiable.', $type)); |
|||
} |
|||
} |
|||
@ -0,0 +1,94 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter; |
|||
|
|||
use Symfony\Component\VarExporter\Exception\ExceptionInterface; |
|||
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; |
|||
use Symfony\Component\VarExporter\Internal\Hydrator; |
|||
use Symfony\Component\VarExporter\Internal\Registry; |
|||
|
|||
/** |
|||
* A utility class to create objects without calling their constructor. |
|||
* |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
*/ |
|||
final class Instantiator |
|||
{ |
|||
/** |
|||
* Creates an object and sets its properties without calling its constructor nor any other methods. |
|||
* |
|||
* For example: |
|||
* |
|||
* // creates an empty instance of Foo |
|||
* Instantiator::instantiate(Foo::class); |
|||
* |
|||
* // creates a Foo instance and sets one of its properties |
|||
* Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]); |
|||
* |
|||
* // creates a Foo instance and sets a private property defined on its parent Bar class |
|||
* Instantiator::instantiate(Foo::class, [], [ |
|||
* Bar::class => ['privateBarProperty' => $propertyValue], |
|||
* ]); |
|||
* |
|||
* Instances of ArrayObject, ArrayIterator and SplObjectHash can be created |
|||
* by using the special "\0" property name to define their internal value: |
|||
* |
|||
* // creates an SplObjectHash where $info1 is attached to $obj1, etc. |
|||
* Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]); |
|||
* |
|||
* // creates an ArrayObject populated with $inputArray |
|||
* Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]); |
|||
* |
|||
* @param string $class The class of the instance to create |
|||
* @param array $properties The properties to set on the instance |
|||
* @param array $privateProperties The private properties to set on the instance, |
|||
* keyed by their declaring class |
|||
* |
|||
* @return object The created instance |
|||
* |
|||
* @throws ExceptionInterface When the instance cannot be created |
|||
*/ |
|||
public static function instantiate(string $class, array $properties = [], array $privateProperties = []) |
|||
{ |
|||
$reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); |
|||
|
|||
if (Registry::$cloneable[$class]) { |
|||
$wrappedInstance = [clone Registry::$prototypes[$class]]; |
|||
} elseif (Registry::$instantiableWithoutConstructor[$class]) { |
|||
$wrappedInstance = [$reflector->newInstanceWithoutConstructor()]; |
|||
} elseif (null === Registry::$prototypes[$class]) { |
|||
throw new NotInstantiableTypeException($class); |
|||
} elseif ($reflector->implementsInterface('Serializable') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize'))) { |
|||
$wrappedInstance = [unserialize('C:'.\strlen($class).':"'.$class.'":0:{}')]; |
|||
} else { |
|||
$wrappedInstance = [unserialize('O:'.\strlen($class).':"'.$class.'":0:{}')]; |
|||
} |
|||
|
|||
if ($properties) { |
|||
$privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties; |
|||
} |
|||
|
|||
foreach ($privateProperties as $class => $properties) { |
|||
if (!$properties) { |
|||
continue; |
|||
} |
|||
foreach ($properties as $name => $value) { |
|||
// because they're also used for "unserialization", hydrators |
|||
// deal with array of instances, so we need to wrap values |
|||
$properties[$name] = [$value]; |
|||
} |
|||
(Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance); |
|||
} |
|||
|
|||
return $wrappedInstance[0]; |
|||
} |
|||
} |
|||
@ -0,0 +1,406 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Internal; |
|||
|
|||
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; |
|||
|
|||
/** |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
class Exporter |
|||
{ |
|||
/** |
|||
* Prepares an array of values for VarExporter. |
|||
* |
|||
* For performance this method is public and has no type-hints. |
|||
* |
|||
* @param array &$values |
|||
* @param \SplObjectStorage $objectsPool |
|||
* @param array &$refsPool |
|||
* @param int &$objectsCount |
|||
* @param bool &$valuesAreStatic |
|||
* |
|||
* @return int |
|||
* |
|||
* @throws NotInstantiableTypeException When a value cannot be serialized |
|||
*/ |
|||
public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic) |
|||
{ |
|||
$refs = $values; |
|||
foreach ($values as $k => $value) { |
|||
if (\is_resource($value)) { |
|||
throw new NotInstantiableTypeException(get_resource_type($value).' resource'); |
|||
} |
|||
$refs[$k] = $objectsPool; |
|||
|
|||
if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) { |
|||
$values[$k] = &$value; // Break hard references to make $values completely |
|||
unset($value); // independent from the original structure |
|||
$refs[$k] = $value = $values[$k]; |
|||
if ($value instanceof Reference && 0 > $value->id) { |
|||
$valuesAreStatic = false; |
|||
++$value->count; |
|||
continue; |
|||
} |
|||
$refsPool[] = [&$refs[$k], $value, &$value]; |
|||
$refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value); |
|||
} |
|||
|
|||
if (\is_array($value)) { |
|||
if ($value) { |
|||
$value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); |
|||
} |
|||
goto handle_value; |
|||
} elseif (!\is_object($value) && !$value instanceof \__PHP_Incomplete_Class) { |
|||
goto handle_value; |
|||
} |
|||
|
|||
$valueIsStatic = false; |
|||
if (isset($objectsPool[$value])) { |
|||
++$objectsCount; |
|||
$value = new Reference($objectsPool[$value][0]); |
|||
goto handle_value; |
|||
} |
|||
|
|||
$class = \get_class($value); |
|||
$reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); |
|||
|
|||
if ($reflector->hasMethod('__serialize')) { |
|||
if (!$reflector->getMethod('__serialize')->isPublic()) { |
|||
throw new \Error(sprintf('Call to %s method %s::__serialize()', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class)); |
|||
} |
|||
|
|||
if (!\is_array($properties = $value->__serialize())) { |
|||
throw new \Typerror($class.'::__serialize() must return an array'); |
|||
} |
|||
|
|||
goto prepare_value; |
|||
} |
|||
|
|||
$properties = []; |
|||
$sleep = null; |
|||
$arrayValue = (array) $value; |
|||
$proto = Registry::$prototypes[$class]; |
|||
|
|||
if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) { |
|||
// ArrayIterator and ArrayObject need special care because their "flags" |
|||
// option changes the behavior of the (array) casting operator. |
|||
$properties = self::getArrayObjectProperties($value, $arrayValue, $proto); |
|||
|
|||
// populates Registry::$prototypes[$class] with a new instance |
|||
Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]); |
|||
} elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) { |
|||
// By implementing Serializable, SplObjectStorage breaks |
|||
// internal references; let's deal with it on our own. |
|||
foreach (clone $value as $v) { |
|||
$properties[] = $v; |
|||
$properties[] = $value[$v]; |
|||
} |
|||
$properties = ['SplObjectStorage' => ["\0" => $properties]]; |
|||
} elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class) { |
|||
++$objectsCount; |
|||
$objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0]; |
|||
$value = new Reference($id); |
|||
goto handle_value; |
|||
} |
|||
|
|||
if (method_exists($class, '__sleep')) { |
|||
if (!\is_array($sleep = $value->__sleep())) { |
|||
trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', E_USER_NOTICE); |
|||
$value = null; |
|||
goto handle_value; |
|||
} |
|||
foreach ($sleep as $name) { |
|||
if (property_exists($value, $name) && !$reflector->hasProperty($name)) { |
|||
$arrayValue[$name] = $value->$name; |
|||
} |
|||
} |
|||
$sleep = array_flip($sleep); |
|||
} |
|||
|
|||
$proto = (array) $proto; |
|||
|
|||
foreach ($arrayValue as $name => $v) { |
|||
$i = 0; |
|||
$n = (string) $name; |
|||
if ('' === $n || "\0" !== $n[0]) { |
|||
$c = 'stdClass'; |
|||
} elseif ('*' === $n[1]) { |
|||
$n = substr($n, 3); |
|||
$c = $reflector->getProperty($n)->class; |
|||
if ('Error' === $c) { |
|||
$c = 'TypeError'; |
|||
} elseif ('Exception' === $c) { |
|||
$c = 'ErrorException'; |
|||
} |
|||
} else { |
|||
$i = strpos($n, "\0", 2); |
|||
$c = substr($n, 1, $i - 1); |
|||
$n = substr($n, 1 + $i); |
|||
} |
|||
if (null !== $sleep) { |
|||
if (!isset($sleep[$n]) || ($i && $c !== $class)) { |
|||
continue; |
|||
} |
|||
$sleep[$n] = false; |
|||
} |
|||
if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) { |
|||
$properties[$c][$n] = $v; |
|||
} |
|||
} |
|||
if ($sleep) { |
|||
foreach ($sleep as $n => $v) { |
|||
if (false !== $v) { |
|||
trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), E_USER_NOTICE); |
|||
} |
|||
} |
|||
} |
|||
|
|||
prepare_value: |
|||
$objectsPool[$value] = [$id = \count($objectsPool)]; |
|||
$properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); |
|||
++$objectsCount; |
|||
$objectsPool[$value] = [$id, $class, $properties, method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0)]; |
|||
|
|||
$value = new Reference($id); |
|||
|
|||
handle_value: |
|||
if ($isRef) { |
|||
unset($value); // Break the hard reference created above |
|||
} elseif (!$valueIsStatic) { |
|||
$values[$k] = $value; |
|||
} |
|||
$valuesAreStatic = $valueIsStatic && $valuesAreStatic; |
|||
} |
|||
|
|||
return $values; |
|||
} |
|||
|
|||
public static function export($value, $indent = '') |
|||
{ |
|||
switch (true) { |
|||
case \is_int($value) || \is_float($value): return var_export($value, true); |
|||
case [] === $value: return '[]'; |
|||
case false === $value: return 'false'; |
|||
case true === $value: return 'true'; |
|||
case null === $value: return 'null'; |
|||
case '' === $value: return "''"; |
|||
} |
|||
|
|||
if ($value instanceof Reference) { |
|||
if (0 <= $value->id) { |
|||
return '$o['.$value->id.']'; |
|||
} |
|||
if (!$value->count) { |
|||
return self::export($value->value, $indent); |
|||
} |
|||
$value = -$value->id; |
|||
|
|||
return '&$r['.$value.']'; |
|||
} |
|||
$subIndent = $indent.' '; |
|||
|
|||
if (\is_string($value)) { |
|||
$code = var_export($value, true); |
|||
|
|||
if (false !== strpos($value, "\n") || false !== strpos($value, "\r")) { |
|||
$code = strtr($code, [ |
|||
"\r\n" => "'.\"\\r\\n\"\n".$subIndent.".'", |
|||
"\r" => "'.\"\\r\"\n".$subIndent.".'", |
|||
"\n" => "'.\"\\n\"\n".$subIndent.".'", |
|||
]); |
|||
} |
|||
|
|||
if (false !== strpos($value, "\0")) { |
|||
$code = str_replace('\' . "\0" . \'', '\'."\0".\'', $code); |
|||
$code = str_replace('".\'\'."', '', $code); |
|||
} |
|||
|
|||
if (false !== strpos($code, "''.")) { |
|||
$code = str_replace("''.", '', $code); |
|||
} |
|||
|
|||
if (".''" === substr($code, -3)) { |
|||
$code = rtrim(substr($code, 0, -3)); |
|||
} |
|||
|
|||
return $code; |
|||
} |
|||
|
|||
if (\is_array($value)) { |
|||
$j = -1; |
|||
$code = ''; |
|||
foreach ($value as $k => $v) { |
|||
$code .= $subIndent; |
|||
if (!\is_int($k) || 1 !== $k - $j) { |
|||
$code .= self::export($k, $subIndent).' => '; |
|||
} |
|||
if (\is_int($k) && $k > $j) { |
|||
$j = $k; |
|||
} |
|||
$code .= self::export($v, $subIndent).",\n"; |
|||
} |
|||
|
|||
return "[\n".$code.$indent.']'; |
|||
} |
|||
|
|||
if ($value instanceof Values) { |
|||
$code = $subIndent."\$r = [],\n"; |
|||
foreach ($value->values as $k => $v) { |
|||
$code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n"; |
|||
} |
|||
|
|||
return "[\n".$code.$indent.']'; |
|||
} |
|||
|
|||
if ($value instanceof Registry) { |
|||
return self::exportRegistry($value, $indent, $subIndent); |
|||
} |
|||
|
|||
if ($value instanceof Hydrator) { |
|||
return self::exportHydrator($value, $indent, $subIndent); |
|||
} |
|||
|
|||
throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', \is_object($value) ? \get_class($value) : \gettype($value))); |
|||
} |
|||
|
|||
private static function exportRegistry(Registry $value, string $indent, string $subIndent): string |
|||
{ |
|||
$code = ''; |
|||
$serializables = []; |
|||
$seen = []; |
|||
$prototypesAccess = 0; |
|||
$factoriesAccess = 0; |
|||
$r = '\\'.Registry::class; |
|||
$j = -1; |
|||
|
|||
foreach ($value as $k => $class) { |
|||
if (':' === ($class[1] ?? null)) { |
|||
$serializables[$k] = $class; |
|||
continue; |
|||
} |
|||
if (!Registry::$instantiableWithoutConstructor[$class]) { |
|||
if (is_subclass_of($class, 'Serializable') && !method_exists($class, '__unserialize')) { |
|||
$serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}'; |
|||
} else { |
|||
$serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}'; |
|||
} |
|||
if (is_subclass_of($class, 'Throwable')) { |
|||
$eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0"; |
|||
$serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4); |
|||
} |
|||
continue; |
|||
} |
|||
$code .= $subIndent.(1 !== $k - $j ? $k.' => ' : ''); |
|||
$j = $k; |
|||
$eol = ",\n"; |
|||
$c = '['.self::export($class).']'; |
|||
|
|||
if ($seen[$class] ?? false) { |
|||
if (Registry::$cloneable[$class]) { |
|||
++$prototypesAccess; |
|||
$code .= 'clone $p'.$c; |
|||
} else { |
|||
++$factoriesAccess; |
|||
$code .= '$f'.$c.'()'; |
|||
} |
|||
} else { |
|||
$seen[$class] = true; |
|||
if (Registry::$cloneable[$class]) { |
|||
$code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p'; |
|||
} else { |
|||
$code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f'; |
|||
$eol = '()'.$eol; |
|||
} |
|||
$code .= '('.substr($c, 1, -1).'))'; |
|||
} |
|||
$code .= $eol; |
|||
} |
|||
|
|||
if (1 === $prototypesAccess) { |
|||
$code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code); |
|||
} |
|||
if (1 === $factoriesAccess) { |
|||
$code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code); |
|||
} |
|||
if ('' !== $code) { |
|||
$code = "\n".$code.$indent; |
|||
} |
|||
|
|||
if ($serializables) { |
|||
$code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')'; |
|||
} else { |
|||
$code = '['.$code.']'; |
|||
} |
|||
|
|||
return '$o = '.$code; |
|||
} |
|||
|
|||
private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string |
|||
{ |
|||
$code = ''; |
|||
foreach ($value->properties as $class => $properties) { |
|||
$code .= $subIndent.' '.self::export($class).' => '.self::export($properties, $subIndent.' ').",\n"; |
|||
} |
|||
|
|||
$code = [ |
|||
self::export($value->registry, $subIndent), |
|||
self::export($value->values, $subIndent), |
|||
'' !== $code ? "[\n".$code.$subIndent.']' : '[]', |
|||
self::export($value->value, $subIndent), |
|||
self::export($value->wakeups, $subIndent), |
|||
]; |
|||
|
|||
return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')'; |
|||
} |
|||
|
|||
/** |
|||
* @param \ArrayIterator|\ArrayObject $value |
|||
* @param \ArrayIterator|\ArrayObject $proto |
|||
*/ |
|||
private static function getArrayObjectProperties($value, array &$arrayValue, $proto): array |
|||
{ |
|||
$reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject'; |
|||
$reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector); |
|||
|
|||
$properties = [ |
|||
$arrayValue, |
|||
$reflector->getMethod('getFlags')->invoke($value), |
|||
$value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator', |
|||
]; |
|||
|
|||
$reflector = $reflector->getMethod('setFlags'); |
|||
$reflector->invoke($proto, \ArrayObject::STD_PROP_LIST); |
|||
|
|||
if ($properties[1] & \ArrayObject::STD_PROP_LIST) { |
|||
$reflector->invoke($value, 0); |
|||
$properties[0] = (array) $value; |
|||
} else { |
|||
$reflector->invoke($value, \ArrayObject::STD_PROP_LIST); |
|||
$arrayValue = (array) $value; |
|||
} |
|||
$reflector->invoke($value, $properties[1]); |
|||
|
|||
if ([[], 0, 'ArrayIterator'] === $properties) { |
|||
$properties = []; |
|||
} else { |
|||
if ('ArrayIterator' === $properties[2]) { |
|||
unset($properties[2]); |
|||
} |
|||
$properties = [$reflector->class => ["\0" => $properties]]; |
|||
} |
|||
|
|||
return $properties; |
|||
} |
|||
} |
|||
@ -0,0 +1,151 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Internal; |
|||
|
|||
use Symfony\Component\VarExporter\Exception\ClassNotFoundException; |
|||
|
|||
/** |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
class Hydrator |
|||
{ |
|||
public static $hydrators = []; |
|||
|
|||
public $registry; |
|||
public $values; |
|||
public $properties; |
|||
public $value; |
|||
public $wakeups; |
|||
|
|||
public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups) |
|||
{ |
|||
$this->registry = $registry; |
|||
$this->values = $values; |
|||
$this->properties = $properties; |
|||
$this->value = $value; |
|||
$this->wakeups = $wakeups; |
|||
} |
|||
|
|||
public static function hydrate($objects, $values, $properties, $value, $wakeups) |
|||
{ |
|||
foreach ($properties as $class => $vars) { |
|||
(self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects); |
|||
} |
|||
foreach ($wakeups as $k => $v) { |
|||
if (\is_array($v)) { |
|||
$objects[-$k]->__unserialize($v); |
|||
} else { |
|||
$objects[$v]->__wakeup(); |
|||
} |
|||
} |
|||
|
|||
return $value; |
|||
} |
|||
|
|||
public static function getHydrator($class) |
|||
{ |
|||
if ('stdClass' === $class) { |
|||
return self::$hydrators[$class] = static function ($properties, $objects) { |
|||
foreach ($properties as $name => $values) { |
|||
foreach ($values as $i => $v) { |
|||
$objects[$i]->$name = $v; |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
|
|||
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) { |
|||
throw new ClassNotFoundException($class); |
|||
} |
|||
$classReflector = new \ReflectionClass($class); |
|||
|
|||
if (!$classReflector->isInternal()) { |
|||
return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class); |
|||
} |
|||
|
|||
if ($classReflector->name !== $class) { |
|||
return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name); |
|||
} |
|||
|
|||
switch ($class) { |
|||
case 'ArrayIterator': |
|||
case 'ArrayObject': |
|||
$constructor = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']); |
|||
|
|||
return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) { |
|||
foreach ($properties as $name => $values) { |
|||
if ("\0" !== $name) { |
|||
foreach ($values as $i => $v) { |
|||
$objects[$i]->$name = $v; |
|||
} |
|||
} |
|||
} |
|||
foreach ($properties["\0"] ?? [] as $i => $v) { |
|||
$constructor($objects[$i], $v); |
|||
} |
|||
}; |
|||
|
|||
case 'ErrorException': |
|||
return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException { |
|||
}); |
|||
|
|||
case 'TypeError': |
|||
return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error { |
|||
}); |
|||
|
|||
case 'SplObjectStorage': |
|||
return self::$hydrators[$class] = static function ($properties, $objects) { |
|||
foreach ($properties as $name => $values) { |
|||
if ("\0" === $name) { |
|||
foreach ($values as $i => $v) { |
|||
for ($j = 0; $j < \count($v); ++$j) { |
|||
$objects[$i]->attach($v[$j], $v[++$j]); |
|||
} |
|||
} |
|||
continue; |
|||
} |
|||
foreach ($values as $i => $v) { |
|||
$objects[$i]->$name = $v; |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
|
|||
$propertySetters = []; |
|||
foreach ($classReflector->getProperties() as $propertyReflector) { |
|||
if (!$propertyReflector->isStatic()) { |
|||
$propertyReflector->setAccessible(true); |
|||
$propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']); |
|||
} |
|||
} |
|||
|
|||
if (!$propertySetters) { |
|||
return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'); |
|||
} |
|||
|
|||
return self::$hydrators[$class] = static function ($properties, $objects) use ($propertySetters) { |
|||
foreach ($properties as $name => $values) { |
|||
if ($setValue = $propertySetters[$name] ?? null) { |
|||
foreach ($values as $i => $v) { |
|||
$setValue($objects[$i], $v); |
|||
} |
|||
continue; |
|||
} |
|||
foreach ($values as $i => $v) { |
|||
$objects[$i]->$name = $v; |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Internal; |
|||
|
|||
/** |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
class Reference |
|||
{ |
|||
public $id; |
|||
public $value; |
|||
public $count = 0; |
|||
|
|||
public function __construct(int $id, $value = null) |
|||
{ |
|||
$this->id = $id; |
|||
$this->value = $value; |
|||
} |
|||
} |
|||
@ -0,0 +1,136 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Internal; |
|||
|
|||
use Symfony\Component\VarExporter\Exception\ClassNotFoundException; |
|||
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; |
|||
|
|||
/** |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
class Registry |
|||
{ |
|||
public static $reflectors = []; |
|||
public static $prototypes = []; |
|||
public static $factories = []; |
|||
public static $cloneable = []; |
|||
public static $instantiableWithoutConstructor = []; |
|||
|
|||
public function __construct(array $classes) |
|||
{ |
|||
foreach ($classes as $i => $class) { |
|||
$this->$i = $class; |
|||
} |
|||
} |
|||
|
|||
public static function unserialize($objects, $serializables) |
|||
{ |
|||
$unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector'); |
|||
|
|||
try { |
|||
foreach ($serializables as $k => $v) { |
|||
$objects[$k] = unserialize($v); |
|||
} |
|||
} finally { |
|||
ini_set('unserialize_callback_func', $unserializeCallback); |
|||
} |
|||
|
|||
return $objects; |
|||
} |
|||
|
|||
public static function p($class) |
|||
{ |
|||
self::getClassReflector($class, true, true); |
|||
|
|||
return self::$prototypes[$class]; |
|||
} |
|||
|
|||
public static function f($class) |
|||
{ |
|||
$reflector = self::$reflectors[$class] ?? self::getClassReflector($class, true, false); |
|||
|
|||
return self::$factories[$class] = \Closure::fromCallable([$reflector, 'newInstanceWithoutConstructor']); |
|||
} |
|||
|
|||
public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null) |
|||
{ |
|||
if (!($isClass = class_exists($class)) && !interface_exists($class, false) && !trait_exists($class, false)) { |
|||
throw new ClassNotFoundException($class); |
|||
} |
|||
$reflector = new \ReflectionClass($class); |
|||
|
|||
if ($instantiableWithoutConstructor) { |
|||
$proto = $reflector->newInstanceWithoutConstructor(); |
|||
} elseif (!$isClass || $reflector->isAbstract()) { |
|||
throw new NotInstantiableTypeException($class); |
|||
} elseif ($reflector->name !== $class) { |
|||
$reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, false, $cloneable); |
|||
self::$cloneable[$class] = self::$cloneable[$name]; |
|||
self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name]; |
|||
self::$prototypes[$class] = self::$prototypes[$name]; |
|||
|
|||
return self::$reflectors[$class] = $reflector; |
|||
} else { |
|||
try { |
|||
$proto = $reflector->newInstanceWithoutConstructor(); |
|||
$instantiableWithoutConstructor = true; |
|||
} catch (\ReflectionException $e) { |
|||
$proto = $reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize') ? 'C:' : 'O:'; |
|||
if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) { |
|||
$proto = null; |
|||
} elseif (false === $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}')) { |
|||
throw new NotInstantiableTypeException($class); |
|||
} |
|||
} |
|||
if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !method_exists($class, '__sleep') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__serialize'))) { |
|||
try { |
|||
serialize($proto); |
|||
} catch (\Exception $e) { |
|||
throw new NotInstantiableTypeException($class, $e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (null === $cloneable) { |
|||
if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !method_exists($proto, '__wakeup') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize')))) { |
|||
throw new NotInstantiableTypeException($class); |
|||
} |
|||
|
|||
$cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone'); |
|||
} |
|||
|
|||
self::$cloneable[$class] = $cloneable; |
|||
self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor; |
|||
self::$prototypes[$class] = $proto; |
|||
|
|||
if ($proto instanceof \Throwable) { |
|||
static $setTrace; |
|||
|
|||
if (null === $setTrace) { |
|||
$setTrace = [ |
|||
new \ReflectionProperty(\Error::class, 'trace'), |
|||
new \ReflectionProperty(\Exception::class, 'trace'), |
|||
]; |
|||
$setTrace[0]->setAccessible(true); |
|||
$setTrace[1]->setAccessible(true); |
|||
$setTrace[0] = \Closure::fromCallable([$setTrace[0], 'setValue']); |
|||
$setTrace[1] = \Closure::fromCallable([$setTrace[1], 'setValue']); |
|||
} |
|||
|
|||
$setTrace[$proto instanceof \Exception]($proto, []); |
|||
} |
|||
|
|||
return self::$reflectors[$class] = $reflector; |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
/* |
|||
* This file is part of the Symfony package. |
|||
* |
|||
* (c) Fabien Potencier <fabien@symfony.com> |
|||
* |
|||
* For the full copyright and license information, please view the LICENSE |
|||
* file that was distributed with this source code. |
|||
*/ |
|||
|
|||
namespace Symfony\Component\VarExporter\Internal; |
|||
|
|||
/** |
|||
* @author Nicolas Grekas <p@tchwork.com> |
|||
* |
|||
* @internal |
|||
*/ |
|||
class Values |
|||
{ |
|||
public $values; |
|||
|
|||
public function __construct(array $values) |
|||
{ |
|||
$this->values = $values; |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
Copyright (c) 2018-2019 Fabien Potencier |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is furnished |
|||
to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
|||
@ -0,0 +1,38 @@ |
|||
VarExporter Component |
|||
===================== |
|||
|
|||
The VarExporter component allows exporting any serializable PHP data structure to |
|||
plain PHP code. While doing so, it preserves all the semantics associated with |
|||
the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`, |
|||
`__serialize`, `__unserialize`). |
|||
|
|||
It also provides an instantiator that allows creating and populating objects |
|||
without calling their constructor nor any other methods. |
|||
|
|||
The reason to use this component *vs* `serialize()` or |
|||
[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to |
|||
OPcache, the resulting code is significantly faster and more memory efficient |
|||
than using `unserialize()` or `igbinary_unserialize()`. |
|||
|
|||
Unlike `var_export()`, this works on any serializable PHP value. |
|||
|
|||
It also provides a few improvements over `var_export()`/`serialize()`: |
|||
|
|||
* the output is PSR-2 compatible; |
|||
* the output can be re-indented without messing up with `\r` or `\n` in the data |
|||
* missing classes throw a `ClassNotFoundException` instead of being unserialized to |
|||
`PHP_Incomplete_Class` objects; |
|||
* references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator` |
|||
instances are preserved; |
|||
* `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes |
|||
throw an exception when being serialized (their unserialized version is broken |
|||
anyway, see https://bugs.php.net/76737). |
|||
|
|||
Resources |
|||
--------- |
|||
|
|||
* [Documentation](https://symfony.com/doc/current/components/var_exporter.html) |
|||
* [Contributing](https://symfony.com/doc/current/contributing/index.html) |
|||
* [Report issues](https://github.com/symfony/symfony/issues) and |
|||
[send Pull Requests](https://github.com/symfony/symfony/pulls) |
|||
in the [main Symfony repository](https://github.com/symfony/symfony) |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\ConcreteClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\ConcreteClass')), |
|||
], |
|||
null, |
|||
[ |
|||
'Symfony\\Component\\VarExporter\\Tests\\AbstractClass' => [ |
|||
'foo' => [ |
|||
123, |
|||
], |
|||
'bar' => [ |
|||
234, |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['ArrayIterator'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('ArrayIterator')), |
|||
], |
|||
null, |
|||
[ |
|||
'ArrayIterator' => [ |
|||
"\0" => [ |
|||
[ |
|||
[ |
|||
123, |
|||
], |
|||
1, |
|||
], |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['ArrayIterator'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('ArrayIterator')), |
|||
], |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[ |
|||
[ |
|||
1, |
|||
[ |
|||
123, |
|||
], |
|||
[], |
|||
], |
|||
] |
|||
); |
|||
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\MyArrayObject'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyArrayObject')), |
|||
], |
|||
null, |
|||
[ |
|||
'ArrayObject' => [ |
|||
"\0" => [ |
|||
[ |
|||
[ |
|||
234, |
|||
], |
|||
1, |
|||
], |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,21 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\MyArrayObject'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyArrayObject')), |
|||
], |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[ |
|||
[ |
|||
1, |
|||
[ |
|||
234, |
|||
], |
|||
[ |
|||
"\0".'Symfony\\Component\\VarExporter\\Tests\\MyArrayObject'."\0".'unused' => 123, |
|||
], |
|||
], |
|||
] |
|||
); |
|||
@ -0,0 +1,29 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (($p = &\Symfony\Component\VarExporter\Internal\Registry::$prototypes)['ArrayObject'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('ArrayObject')), |
|||
clone $p['ArrayObject'], |
|||
], |
|||
null, |
|||
[ |
|||
'ArrayObject' => [ |
|||
"\0" => [ |
|||
[ |
|||
[ |
|||
1, |
|||
$o[0], |
|||
], |
|||
0, |
|||
], |
|||
], |
|||
], |
|||
'stdClass' => [ |
|||
'foo' => [ |
|||
$o[1], |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,28 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (($p = &\Symfony\Component\VarExporter\Internal\Registry::$prototypes)['ArrayObject'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('ArrayObject')), |
|||
clone $p['ArrayObject'], |
|||
], |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[ |
|||
[ |
|||
0, |
|||
[ |
|||
1, |
|||
$o[0], |
|||
], |
|||
[ |
|||
'foo' => $o[1], |
|||
], |
|||
], |
|||
-1 => [ |
|||
0, |
|||
[], |
|||
[], |
|||
], |
|||
] |
|||
); |
|||
@ -0,0 +1,3 @@ |
|||
<?php |
|||
|
|||
return true; |
|||
@ -0,0 +1,15 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
(($f = &\Symfony\Component\VarExporter\Internal\Registry::$factories)['Symfony\\Component\\VarExporter\\Tests\\MyCloneable'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\MyCloneable'))(), |
|||
($f['Symfony\\Component\\VarExporter\\Tests\\MyNotCloneable'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\MyNotCloneable'))(), |
|||
], |
|||
null, |
|||
[], |
|||
[ |
|||
$o[0], |
|||
$o[1], |
|||
], |
|||
[] |
|||
); |
|||
@ -0,0 +1,25 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['DateTime'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('DateTime')), |
|||
], |
|||
null, |
|||
[ |
|||
'stdClass' => [ |
|||
'date' => [ |
|||
'1970-01-01 00:00:00.000000', |
|||
], |
|||
'timezone_type' => [ |
|||
1, |
|||
], |
|||
'timezone' => [ |
|||
'+00:00', |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[ |
|||
1 => 0, |
|||
] |
|||
); |
|||
@ -0,0 +1,30 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
(\Symfony\Component\VarExporter\Internal\Registry::$factories['Error'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Error'))(), |
|||
], |
|||
null, |
|||
[ |
|||
'TypeError' => [ |
|||
'file' => [ |
|||
\dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', |
|||
], |
|||
'line' => [ |
|||
234, |
|||
], |
|||
], |
|||
'Error' => [ |
|||
'trace' => [ |
|||
[ |
|||
'file' => \dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', |
|||
'line' => 123, |
|||
], |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[ |
|||
1 => 0, |
|||
] |
|||
); |
|||
@ -0,0 +1,7 @@ |
|||
<?php |
|||
|
|||
return [ |
|||
[ |
|||
123, |
|||
], |
|||
]; |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ |
|||
'C:54:"Symfony\\Component\\VarExporter\\Tests\\FinalArrayIterator":49:{a:2:{i:0;i:123;i:1;s:21:"x:i:0;a:0:{};m:a:0:{}";}}', |
|||
]), |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\FinalArrayIterator'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\FinalArrayIterator')), |
|||
], |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[ |
|||
[ |
|||
0, |
|||
[], |
|||
[], |
|||
], |
|||
] |
|||
); |
|||
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ |
|||
'O:46:"Symfony\\Component\\VarExporter\\Tests\\FinalError":1:{s:12:"'."\0".'Error'."\0".'trace";a:0:{}}', |
|||
]), |
|||
null, |
|||
[ |
|||
'TypeError' => [ |
|||
'file' => [ |
|||
\dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', |
|||
], |
|||
'line' => [ |
|||
123, |
|||
], |
|||
], |
|||
'Error' => [ |
|||
'trace' => [ |
|||
[], |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[ |
|||
1 => 0, |
|||
] |
|||
); |
|||
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
(\Symfony\Component\VarExporter\Internal\Registry::$factories['Symfony\\Component\\VarExporter\\Tests\\FinalError'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\FinalError'))(), |
|||
], |
|||
null, |
|||
[ |
|||
'TypeError' => [ |
|||
'file' => [ |
|||
\dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', |
|||
], |
|||
'line' => [ |
|||
123, |
|||
], |
|||
], |
|||
'Error' => [ |
|||
'trace' => [ |
|||
[], |
|||
], |
|||
], |
|||
], |
|||
$o[0], |
|||
[ |
|||
1 => 0, |
|||
] |
|||
); |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
(\Symfony\Component\VarExporter\Internal\Registry::$factories['Symfony\\Component\\VarExporter\\Tests\\FinalStdClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\FinalStdClass'))(), |
|||
], |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ |
|||
'C:51:"Symfony\\Component\\VarExporter\\Tests\\FooSerializable":20:{a:1:{i:0;s:3:"bar";}}', |
|||
]), |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[] |
|||
); |
|||
@ -0,0 +1,16 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [], |
|||
[ |
|||
$r = [], |
|||
$r[1] = [ |
|||
&$r[1], |
|||
], |
|||
], |
|||
[], |
|||
[ |
|||
&$r[1], |
|||
], |
|||
[] |
|||
); |
|||
@ -0,0 +1,18 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = [ |
|||
clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['stdClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('stdClass')), |
|||
], |
|||
[ |
|||
$r = [], |
|||
$r[1] = $o[0], |
|||
], |
|||
[], |
|||
[ |
|||
&$r[1], |
|||
&$r[1], |
|||
$o[0], |
|||
], |
|||
[] |
|||
); |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( |
|||
$o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ |
|||
'O:20:"SomeNotExistingClass":0:{}', |
|||
]), |
|||
null, |
|||
[], |
|||
$o[0], |
|||
[] |
|||
); |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue