This commit is contained in:
Jaybe
2025-03-05 14:10:06 +09:00
commit 7a77932344
1905 changed files with 122510 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
._DAV
+12
View File
@@ -0,0 +1,12 @@
RewriteEngine on
#Now, rewrite to HTTPS:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(?:jpe?g|gif|bmp|png|tiff|css|js)$ index.php [L,NC] # direct to index.php except these
#RewriteRule ^(.*)$ index.php?request=$1 [L,QSA]
+305
View File
@@ -0,0 +1,305 @@
@import url(//static.hotblood.co.kr/libs/fonts/nanumgothic/nanumgothic.css);
@import url(//fonts.googleapis.com/css?family=Montserrat:900);
html,body,form,div,h1,h2,input{margin:0; padding:0;}
a,*:visited,*:link,*:focus,button{text-decoration:none; color:inherit; outline:none; border:0; transition:all 0.3s ease; -webkit-transition:all 0.9s ease;}
body {margin:0; background-color:#333; font-size:16px; font-family:'Nanum Gothic','맑은고딕',MG,sans-serif;}
ul, ol, li {margin:0; padding:0; list-style:none; font-size:100%;}
table{border-collapse:separate; border-spacing:0;}
input{vertical-align:middle;}
img{vertical-align:middle;}
label{display:inline-block;}
label img{pointer-events:none;}
.blind{position:absolute; top:0; left:-1000px; width:0; height:0; font-size:0; line-height:0;}
.alignCenter{text-align:center;}
.alignLeft{text-align:left;}
.alignRight{text-align:right;}
.mt3{margin-top:3px !important;}
.mt5{margin-top:5px !important;}
.mt10{margin-top:10px !important;}
.mt15{margin-top:15px !important;}
.mt20{margin-top:20px !important;}
.mt25{margin-top:25px !important;}
.mt30{margin-top:30px !important;}
.mb3{margin-bottom:3px !important;}
.mb5{margin-bottom:5px !important;}
.mb10{margin-bottom:10px !important;}
.mb15{margin-bottom:15px !important;}
.mb20{margin-bottom:20px !important;}
.mb25{margin-bottom:25px !important;}
.mb30{margin-bottom:30px !important;}
.pt3{padding-top:3px !important;}
.pt5{padding-top:5px !important;}
.pt10{padding-top:10px !important;}
.pt15{padding-top:15px !important;}
.pt20{padding-top:20px !important;}
.pt25{padding-top:25px !important;}
.pt30{padding-top:30px !important;}
.pb3{padding-bottom:3px !important;}
.pb5{padding-bottom:5px !important;}
.pb10{padding-bottom:10px !important;}
.pb15{padding-bottom:15px !important;}
.pb20{padding-bottom:20px !important;}
.pb25{padding-bottom:25px !important;}
.pb30{padding-bottom:30px !important;}
.clear{clear:both;}
/* Alert */
.alert{position:relative; box-sizing:border-box; width:100%; height:100vh; background-color:#fff; text-align:center; overflow:hidden;}
.alert .alert-container{position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);}
.alert .message{background-color:#1a1a1a; color:#fff; border-radius:15px; padding:80px 20px; margin-top:-50px; word-break:keep-all; box-shadow:3px 3px 7px rgba(0,0,0,.8);}
.alert h1 {
font-family: 'Montserrat', sans-serif;
font-size: 750%;
font-weight: 900;
margin: 0px;
color: #000;
text-transform: uppercase;
letter-spacing: -6px;
margin-left:12px;
}
.alert h1>span {text-shadow:-4px 1px 0px #fff;}
.alert .btn-group{padding-top:10px;}
.alert .btn-group .btn{background-color:#fff; border-radius:5px; padding:10px 20px;}
.alert .btn-group .btn_back{color:#fff; background-color:#333;}
.alert .btn-group .btn_confirm{color:#fff; background-color:#26a6f8;}
/* Block Message */
.block_msg{position:fixed; top:0; display:flex; align-items:center; justify-content:center; font-size:200%; width:100%; height:100vh; color:#000; background-color:rgba(255, 73, 73, 0.8); text-align:center; z-index:900;}
.block_msg.hide{display:none;}
/* Thanks Page */
.thanks{position:relative; box-sizing:border-box; width:100%; height:100vh; background-color:#F5F5F5; text-align:center; border-top:5px solid #0585C4; overflow:hidden;}
.thanks .thanks-container{position:absolute; top:50%; left:50%; width:100%; max-width:500px; transform:translate(-50%,-50%);}
.thanks .message{color:#000; font-size:200%; line-height:1.4;}
.thanks .btn-group{padding-top:30px;}
.thanks .btn-group .btn{font-size:140%; background-color:#fff; border-radius:5px; padding:20px 100px;}
.thanks .btn-group .btn_confirm{color:#fff; background-color:#0585C4;}
/*
* Event Page
*/
/* Comments */
.comments{box-sizing:border-box; width:100%; background-color:#fff; border:15px solid #000; padding:5px;}
.comments .box{box-sizing:border-box; height:150px; overflow:hidden;}
.comments .box .cnt{display:block; font-size:100%; font-weight:bold; border-bottom:1px solid #c0c0c0; padding:5px 0 5px 5px;}
.comments .box .list{width:95%; margin:0px auto;}
.comments .box .list li{padding:4px 0; border-bottom:1px solid #eee;}
.comments .box .list li:after{display:block; content:""; clear:both;}
.comments .box .list li span{box-sizing:border-box; display:inline-block; font-size:106%; line-height:1.2; text-align:center; vertical-align:middle;}
.comments .box .list li span:nth-of-type(1){width:18%;}
.comments .box .list li span:nth-of-type(2){width:14%;}
.comments .box .list li span:nth-of-type(3){width:28%;}
.comments .box .list li span:nth-of-type(4){width:22%;}
.comments .box .list li span:nth-of-type(5){width:18%;}
.comments .box .list li span b{display:inline-block; min-width:50%; border:1px solid #000; color:#fff; font-weight:normal; padding:5px 10px; font-size:70%;}
.comments .box .list li span b.ing{background-color:#fff; color:#000;}
.comments .box .list li span b.done{background-color:#3b3939;}
/* replys */
.replys{box-sizing:border-box; width:100%; background-color:#fff; border:15px solid #000;}
.replys .input-area{width:100%; background-color:#d0d0d0;}
.replys .input-area table{width:95%; margin:0 auto; padding:10px 0 10px;}
.replys .input-area table tr td:nth-of-type(1){width:80%;}
.replys .input-area table tr td:nth-of-type(2){width:20%;}
.replys .input-area table tr td input.reply_input{width:100%; height:55px; box-shadow:1px 0 1px 1px #a3a3a3 inset; border:none; font-size:110%; background-color:#fff; padding-left:10px;}
.replys .input-area table tr td input[type="image"]{width:100%;}
.replys .box{box-sizing:border-box; height:150px; overflow:hidden; text-align:center; padding-top:2%;}
.replys .box .cnt{display:block; font-size:100%; font-weight:bold; border-bottom:1px solid #c0c0c0; padding:5px 0 5px 5px;}
.replys .box .list{width:95%; margin:0px auto;}
.replys .box .list li{padding:4px 0; border-bottom:1px solid #eee;}
.replys .box .list li:after{display:block; content:""; clear:both;}
.replys .box .list li span{box-sizing:border-box; display:inline-block; font-size:106%; line-height:1.2; text-align:center; vertical-align:middle;}
.replys .box .list li span:nth-of-type(1){width:28%; font-weight: bolder; letter-spacing:-1px;}
.replys .box .list li span:nth-of-type(2){width:68%; text-align:left;}
/* Ajax Comments */
.subscribe{background-color:#fff; padding:3% 5%;}
.subscribe .content{padding:4% 0; border-bottom:1px dashed #ccc;}
.subscribe .content:last-child{border:0 none;}
.subscribe .content div{padding:1% 0;}
.subscribe .btn_moreSubscribe{display:block; width:100%; text-align:center; padding:5px 0;}
/* Checkbox */
@-moz-keyframes borderscale {50% {box-shadow: 0 0 0 2px #999;}}
@-webkit-keyframes borderscale {50% {box-shadow: 0 0 0 2px #999;}}
@keyframes borderscale {50% {box-shadow: 0 0 0 2px #999;}}
.form input {-webkit-appearance:none; -webkit-border-radius:0;}
.form input[type="checkbox"],
.form input[type="radio"] {border:0; clip:rect(0 0 0 0); height:1px; margin:-1px; overflow:hidden; padding:0; position:absolute; width:1px;}
.form input[type="checkbox"]:hover + span:before,
.form input[type="checkbox"]:focus + span:before,
.form input[type="radio"]:hover + span:before,
.form input[type="radio"]:focus + span:before {border-color:#999;}
.form input[type="checkbox"]:active + span:before,
.form input[type="radio"]:active + span:before {transition-duration:0; filter:brightness(0.2);}
.form input[type="checkbox"] + span,
.form input[type="radio"] + span {position:relative; padding:0 4px 0 22px; font-weight:normal; margin:3px 0;}
.form input[type="checkbox"] + span:before,
.form input[type="checkbox"] + span:after,
.form input[type="radio"] + span:before,
.form input[type="radio"] + span:after {box-sizing:content-box; position:absolute; content:''; display:block; left:0;}
.form input[type="checkbox"] + span:before,
.form input[type="radio"] + span:before {top:50%; width:14px; height:14px; border:2px solid #d9d9d9; text-align:center; transform:translateY(-50%);}
.form input[type="checkbox"] + span:after,
.form input[type="radio"] + span:after {background-color:#000; /*#00bad2;*/ top:50%; left:6px; width:8px; height:8px; line-height:1.4px; margin-top:-4px; transform:scale(0); transform-origin:50%; transition:transform 200ms ease-out;}
.form input[type="radio"]:checked + span:after {transform:scale(1);}
.form input[type="radio"] + span:before {border-radius:50%;}
.form input[type="checkbox"] + span:after,
.form input[type="radio"] + span:after {background-color:transparent; top:50%; left:0; width:20px; height:10px; margin-top:-5px; border-style:solid; border-color:#000; border-width:0 0 3px 3px; -moz-transform:rotate(-45deg) scale(0); -ms-transform:rotate(-45deg) scale(0); -webkit-transform:rotate(-45deg) scale(0); transform:rotate(-45deg) scale(0); -moz-transition:none; -o-transition:none; -webkit-transition:none; transition:none;} input[type="checkbox"]:checked + span:before,
.form input[type="radio"]:checked + span:before {-moz-animation:borderscale 200ms ease-in; -webkit-animation:borderscale 200ms ease-in; animation:borderscale 200ms ease-in;}
.form input[type="checkbox"]:checked + span:after,
.form input[type="radio"]:checked + span:after {content:''; -moz-transform:rotate(-45deg) scale(1) translate(29%, -43%); -ms-transform:rotate(-45deg) scale(1) translate(29%, -43%); -webkit-transform:rotate(-45deg) scale(1) translate(29%, -43%); transform:rotate(-45deg) scale(1) translate(29%, -43%); -moz-transition:-moz-transform 200ms ease-out; -o-transition:-o-transform 200ms ease-out; -webkit-transition:-webkit-transform 200ms ease-out; transition:transform 200ms ease-out;}
#wrap{position:relative; width:818px; font-size:100%; margin:0 auto;}
#wrap .formContents{position:relative;}
.container{width:100%;}
.img-area{position:relative; display:block;}
.img-area img{display:inline-block; width:100%; margin:0 0 -1px 0; text-align:center; vertical-align:top;}
.container video{display:block; width:100%;}
/* 폼양식 */
.form{background-color:#fff;}
.form .table_box{width:70%; padding:7px 0; margin:0 auto;}
.form .table_box table{border-collapse:collapse; table-layout:fixed; width:100%; margin:7px auto;}
.form .table_box table th,
.form .table_box table td{position:relative; height:43px; background-color:#fff; padding:7px 3px;}
.form .table_box table th{width:151px; text-align:right;}
.form .table_box table th img{height:100%;}
.form .table_box table td{text-align:left;}
.form .table_box table tr.auth{display:none;}
.form .table_box table tr.auth .auth_time{position:absolute; bottom:10px; right:23%; font-size:70%; color:#00f;}
.form .inp{box-sizing:border-box; width:100%; height:100%; font-size:16px; border:0 none; background-color:transparent; resize:none;}
.form .inp.short{width:50%;}
.form .inp.add_btn{width:80%;}
.form .btn{width:19%; height:100%; font-size:90%; font-weight:bold; background-color:transparent; border:1px solid #a3a3a3; vertical-align:middle; margin-left:1%; padding:0; cursor:pointer;}
.form .agBox{display:block; width:90%; font-size:70%; text-align:center; margin:0 auto 7px;}
.form .agBox a{font-weight:bold;}
.form .agBox.gooddoc{text-align:left; width:70%;}
.form .agBox.gooddoc label{padding-bottom:8px;}
/* tableBorder : 테이블 테두리 */
.form .table_box.tableBorder table{border-collapse:separate; border:1px solid #a3a3a3; padding:10px;}
/* tableRadius : 테이블 테두리 곡면 */
.form .table_box.tableRadius table{border-collapse:separate; border-radius:15px;}
/* rowUnderline : 각행 밑줄 */
.form .table_box.rowUnderline table th,
.form .table_box.rowUnderline table td{border:1px solid #a3a3a3; border-width:0 0 1px 0;}
/* rowBorder : 각행 테두리 */
.form .table_box.rowBorder table{border-collapse:separate; border-spacing:0 10px;}
.form .table_box.rowBorder table th,
.form .table_box.rowBorder table td{border:1px solid #a3a3a3; padding:7px 10px;}
.form .table_box.rowBorder tr td:nth-of-type(1){border-width:1px 0 1px 0;}
.form .table_box.rowBorder table th{border-width:1px 0 1px 1px;}
.form .table_box.rowBorder table td{border-width:1px 1px 1px 0;}
.form .table_box.rowBorder tr td:last-child{border-width:1px 1px 1px 0 !important;}
/* rowRadius : 각행 테두리 곡면 */
.form .table_box.rowRadius tr th:first-child{border-radius:15px 0 0 15px;}
.form .table_box.rowRadius tr td:last-child{border-radius:0 15px 15px 0;}
.form .table_box.rowBorder.rowRadius tr:last-child th:first-child{border-radius:15px 0 0 15px;}
.form .table_box.rowBorder.rowRadius tr:last-child td:last-child{border-radius:0 15px 15px 0;}
/* rowMerge : 테이블 간격 붙이기 */
.form .table_box.rowMerge table{border-spacing:0 !important;}
.form .table_box.rowMerge table tr:first-child th{border-bottom-left-radius:0; border-bottom-right-radius:0;}
.form .table_box.rowMerge table tr:first-child td{border-bottom-right-radius:0;}
.form .table_box.rowMerge table tr:nth-of-type(n+2) th,
.form .table_box.rowMerge table tr:nth-of-type(n+2) td{border-top-width:0 !important; border-radius:0;}
.form .table_box.rowMerge table tr:last-child th{border-top-left-radius:0; border-top-right-radius:0;}
.form .table_box.rowMerge table tr:last-child td{border-top-right-radius:0;}
.form .table_box.rowMerge.rowRadius tr:last-child th:first-child{border-radius:0 0 0 15px !important;}
.form .table_box.rowMerge.rowRadius tr:last-child td:last-child{border-radius:0 0 15px 0 !important;}
/* inpBorder : 입력박스 테두리 */
.form .table_box.inpBorder table td .inp{border:1px solid #a3a3a3; padding:0 10px;}
/* inpUnderline :입력박스 밑줄 */
.form .table_box.inpUnderline table td .inp{border:1px solid #a3a3a3; border-width:0 0 1px;}
/* inpRadius : 입력박스 테두리 곡면 */
.form .table_box.inpRadius table td .inp{border-radius:15px;}
/* noHaveLabel : 입력박스 단독 */
.form .table_box.noHaveLabel table td:first-child{border-width:1px !important; text-align:center;}
.form .table_box.noHaveLabel table td input{text-align:center; line-height:1.4;}
.form .table_box.noHaveLabel table td textarea{text-align:center; line-height:1.4;}
.form .table_box.noHaveLabel.rowRadius tr td:first-child{border-top-left-radius:15px !important; border-bottom-left-radius:15px !important;}
.form .table_box.rowMerge.rowRadius.noHaveLabel table tr:first-child td:first-child{border-top-left-radius:15px; border-bottom-left-radius:0 !important;}
.form .table_box.rowMerge.rowRadius.noHaveLabel table tr:last-child td:first-child{border-bottom-left-radius:15px !important;}
.form .table_box.rowMerge.rowRadius.noHaveLabel table tr:last-child td:last-child{border-bottom-right-radius:15px !important;}
.form .table_box.rowMerge.rowRadius.noHaveLabel table tr:nth-of-type(n+2) td{border-radius:0 !important;}
.form .table_box.rowMerge.rowRadius.noHaveLabel .inp::placeholder {font-size:120%;}
/* cellSplit : noHaveLabel 상태에서 셀 간격 띄움 */
.form .table_box.cellSplit table{border-spacing: 20px 10px;}
.form .table_box.cellSplit table td{border-radius: 15px !important;}
/* 개인정보 처리방침 */
.form .agreement{display:none; box-sizing:border-box; width:95%; border:1px solid #a3a3a3; border-radius:3px; padding:5px; margin:15px auto; background-color:#fff;}
.form .agreement{display:none; box-sizing:border-box; width:95%; background-color:#fff; border:1px solid #a3a3a3; border-radius:3px; padding:5px; margin:15px auto;}
/* popup : 개인정보 팝업 */
.form .agreement.popup{position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);}
.form .agreement .button{float:right; font-size:75%; border:1px solid #000; border-radius:0px; background-color:#efefef; padding:4px 8px; margin:3px;}
.form .agreement h3{font-size:80%; margin:0; padding:0 0 1%;}
.form .agreement ol li{line-height:1.2; font-size:75%;}
.form .agreement ol li.desc{line-height:2;}
.form .mkt_agreement{display:none; box-sizing:border-box; width:95%; border:1px solid #a3a3a3; border-radius:3px; padding:5px; margin:15px auto; background-color:#fff;}
.form .mkt_agreement ol li{line-height:1.2; font-size:75%;}
.form .submit{text-align:center; padding:7px 0;}
.form .submit input[type="image"]{}
/* 부가설명 */
.form .description{width:98%; text-align:center; margin:0 auto; padding:0;}
.form .description p{font-weight:bold; font-size:108%; margin:0 auto; padding:0.5% 0;}
.form .description span{font-size:78%; margin:0 auto; padding:0.5% 0;}
.form .description .ad_txt{font-size:78%; margin:0 auto; padding:0.5% 0;}
/* 굿닥 땡큐페이지 */
.gooddoc-thanks{}
.gooddoc-thanks img{width:100%;}
.gooddoc-thanks .gdt-bg{background:url("//static.hotblood.co.kr/event/gooddoc/thanks/bg_01.jpg"); background-size:100%; width:100%;}
.gooddoc-thanks .gdt-bg table{width:90%; margin:0 auto;}
.gooddoc-thanks .gdt-bg table td img{width:95%;}
@media screen and (max-width: 818px){
#wrap{width:100%;}
.form .agBox{font-size:90%; letter-spacing:-1px;}
}
@media screen and (max-width: 640px){
body{font-size:14px;}
.form input[type="checkbox"] + span:before,
.form input[type="radio"] + span:before {width:10px; height:10px;}
.form input[type="checkbox"] + span,
.form input[type="radio"] + span{padding-left:17px;}
.form input[type="checkbox"] + span:after,
.form input[type="radio"] + span:after{width:15px; height:7px;}
.form .submit input[type="image"]{width:90%;}
.form .table_box{width:90%;}
.form .table_box table th,
.form .table_box table td{height:30px;}
.form .table_box table th{width:105px;}
.form .description p{font-weight:normal; padding:1% 0;}
.form .description span{font-size:90%; padding:1% 0;}
.form .description .ad_txt{font-size:90%; padding:1% 0;}
.comments .box{font-size:87%; letter-spacing:-1px;}
.replys .box{font-size:87%; height:100px;}
.replys .input-area table tr td input.reply_input{height:33px;}
}
@media screen and (max-width: 500px){
.form .agBox.gooddoc{width:90%;}
}
@media screen and (max-width: 415px){
.replys .input-area table tr td input.reply_input{height:29px;}
.form .description p{font-size:98%;}
.form .agBox{font-size:88%;}
}
@media screen and (max-width: 375px){
body{font-size:12px;}
.replys .input-area table tr td input.reply_input{height:24px;}
}
@media screen and (max-width: 320px){
body{font-size:10px;}
}
+251
View File
File diff suppressed because one or more lines are too long
+1577
View File
File diff suppressed because it is too large Load Diff
+158
View File
@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Error::404</title>
<!-- Google font -->
<link href="https://fonts.googleapis.com/css?family=Cabin:400,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Montserrat:900" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
}
#notfound {
position: relative;
height: 100vh;
}
#notfound .notfound {
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.notfound {
max-width: 520px;
width: 100%;
line-height: 1.4;
text-align: center;
}
.notfound .notfound-404 {
position: relative;
height: 240px;
}
.notfound .notfound-404 h1 {
font-family: 'Montserrat', sans-serif;
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-size: 252px;
font-weight: 900;
margin: 0px;
color: #262626;
text-transform: uppercase;
letter-spacing: -40px;
margin-left: -20px;
}
.notfound .notfound-404 h1>span {
text-shadow: -8px 0px 0px #fff;
}
.notfound .notfound-404 h3 {
font-family: 'Cabin', sans-serif;
position: relative;
font-size: 16px;
font-weight: 700;
text-transform: uppercase;
color: #262626;
margin: 0px;
letter-spacing: 3px;
padding-left: 6px;
}
.notfound h2 {
font-family: 'Cabin', sans-serif;
font-size: 20px;
font-weight: 400;
text-transform: uppercase;
color: #000;
margin-top: 0px;
margin-bottom: 25px;
}
@media only screen and (max-width: 767px) {
.notfound .notfound-404 {
height: 200px;
}
.notfound .notfound-404 h1 {
font-size: 200px;
}
}
@media only screen and (max-width: 480px) {
.notfound .notfound-404 {
height: 162px;
}
.notfound .notfound-404 h1 {
font-size: 162px;
height: 150px;
line-height: 162px;
}
.notfound h2 {
font-size: 16px;
}
}
</style>
</head>
<body>
<?php
if(!isset($error)) {
$error = ['title' => "", 'description' => "", 'error'=>""];
}
if(!$error['title']) {
$error['title'] = "Oops! Page not found";
}
if(!$error['subtitle']) {
$error['subtitle'] = "we are sorry, but the page you requested was not found";
}
?>
<div id="notfound">
<div class="notfound">
<div class="notfound-404">
<h3><?=$error['title']?></h3>
<h1><span>4</span><span>0</span><span>4</span></h1>
</div>
<h2><?=$error['subtitle']?></h2>
<?php if(isset($error['description'])) {?><p class="description"><?=$error['description']?></p><?php } ?>
<?php if(isset($error['error'])) {?>
<!--<p class="description"><?=$error['error']?></p>-->
<?php } ?>
</div>
</div>
</body><!-- This templates was made by Colorlib (https://colorlib.com) -->
</html>
+1
View File
@@ -0,0 +1 @@
/home/hotevent/public_html/event
+7
View File
@@ -0,0 +1,7 @@
<style>
</style>
<div id="wrap">
<div class="container">
<div class="img-area"><img src="//static.hotblood.co.kr/<?echo $_GET['data'];?>"></div>
</div>
</div>
+9
View File
@@ -0,0 +1,9 @@
<div class="alert">
<div class="alert-container">
<h1><span>A</span><span>L</span><span>E</span><span>R</span><span>T</span></h1>
<div class="message"><p><?php echo $msg;?></p></div>
<p class="btn-group">
<a href="#" class="btn btn_back">뒤로가기</a>
</p>
</div>
</div>
+98
View File
@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php if ($this->landing['device_width']) { ?>
<meta name="viewport" content="width=<?= $this->landing['device_width'] ?>, user-scalable=no, target-densitydpi=device-dpi" />
<?php } else { ?>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui, viewport-fit=cover" />
<?php } ?>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" /><!-- IE최신 -->
<?php if($this->landing['hide_meta'] != 1) { ?>
<!-- Facebook OpenGraph -->
<meta property="og:title" content="<?php echo $this->landing['title']; ?>" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://<?php echo $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ?>" />
<?php /* ?><meta property="og:site_name" content="<?php echo $this->landing['name']; ?>" /><?php 야호맨 때문에 숨김 */ ?>
<meta property="og:description" content="<?php echo $this->landing['subtitle']; ?>" />
<meta property="og:locale:alternate" content="ko_KR" />
<meta name="subject" content="<?php echo $this->landing['title']; ?>" />
<meta name="description" content="<?php echo $this->landing['subtitle']; ?>">
<meta name="content-language" content="kr" />
<?php } ?>
<title></title>
<script src="//static.hotblood.co.kr/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//static.hotblood.co.kr/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="<?php echo EVENT_URL; ?>/common.js?ver=<?php echo date('YmdHi'); ?>"></script>
<script src="<?php echo EVENT_URL; ?>/static/js/hangul.js"></script>
<link type="text/css" href="//static.hotblood.co.kr/libs/jqueryui/1.12.1/jquery-ui.min.css" rel="stylesheet" />
<link type="text/css" href="//static.hotblood.co.kr/libs/animate/4.1.0/animate.min.css" rel="stylesheet" />
<link type="text/css" href="<?php echo EVENT_URL; ?>/common.css?ver=<?php echo date('YmdHi'); ?>" rel="stylesheet" />
<script>
window.hbEvent = window.hbEvent || [];
$(function() {
var information = {
<?php /* ?>
'advertiser' : '<?php echo addslashes($this->landing['name'] ?? '');?>',
'agent' : '<?php echo addslashes($this->landing['agent'] ?? '');?>',
<?php 야호맨 때문에 숨김 */?>
'media' : '<?php echo addslashes($this->landing['media'] ?? '');?>',
'no' : '<?php echo addslashes($this->landing['seq'] ?? '');?>',
'site' : '<?php echo addslashes($_GET['site'] ?? '');?>',
'title' : '<?php echo addslashes($this->landing['title'] ?? '');?>',
'action' : '<?php echo addslashes($this->method ?? '');?>',
}
hbEvent.push(information);
});
</script>
<!-- Google Tag Manager -->
<script>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src =
'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-NM28J73');
</script>
<!-- End Google Tag Manager -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-7V2Y5GXTTR"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-7V2Y5GXTTR', {
<?php /* ?>
'advertiser' : '<?php echo addslashes($this->landing['name'] ?? '');?>',
'agent' : '<?php echo addslashes($this->landing['agent'] ?? '');?>',
<?php 야호맨 때문에 숨김 */?>
'media' : '<?php echo addslashes($this->landing['media'] ?? '');?>',
'event_no' : '<?php echo addslashes($this->landing['seq'] ?? '');?>',
'site' : '<?php echo addslashes($_GET['site'] ?? '');?>',
'title' : '<?php echo addslashes($this->landing['title'] ?? '');?>',
'action' : '<?php echo addslashes($this->method ?? '');?>',
'linker': {
'accept_incoming': true
}
});
</script>
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NM28J73" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<h1 class="alignCenter blind"><?php echo $this->landing['subtitle'] ?? ''; ?></h1>
+26
View File
@@ -0,0 +1,26 @@
<style>
body{background-color:#18173F;}
.result_landing{width:100%; max-width:<?php echo $data['maxWidth']+10;?>px; margin:0 auto;}
.result_landing .img_box{width:100%; margin:0 auto;}
.result_landing .img_box .img:first-child{padding:0 5px;}
.result_landing .img_box .img-sizer,
.result_landing .img_box .img{box-sizing:border-box; display:block; width:100%; background-color:transparent; padding:40px 5px 0;}
.result_landing .img_box .img.grid{width:100%;}
.result_landing .img_box .img.grid2{width:50%;}
.result_landing .img_box .img.noPadding{padding:0 5px;}
.result_landing .img_box .img a{display:block; width:100%;}
.result_landing .img_box .img img{width:100%;}
@media screen and (max-width: 890px){
.result_landing .img_box .img{padding:15px 5px 0;}
}
</style>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<div class="result_landing">
<div class="img_box">
<?php foreach($data['data'] as $row) { ?>
<div id="landing-<?php echo $row['no'];?>" class="img<?php if($row['image_info']['width']<$data['maxWidth']) echo ' grid2';?><?php if(!$row['link']) echo ' noPadding';?>">
<?php if($row['link']) {?><a href="../go/<?php echo $row['category'];?>/<?php echo $row['no'];?>"><?php }?><img src="<?php echo $row['image'];?>"><?php if($row['link']) {?></a><?php }?>
</div>
<?php } ?>
</div>
</div>
+2
View File
@@ -0,0 +1,2 @@
</body>
</html>
+10
View File
@@ -0,0 +1,10 @@
<div class="thanks">
<div class="thanks-container">
<h1 class="blind">이벤트 등록 완료</h1>
<div class="message">
<p><img src="//static.hotblood.co.kr/event/thanks/ico_thx.png"></p>
<p>등록해주셔서 감사합니다!<br/>개별적으로 연락드리겠습니다.</p>
</div>
<p class="btn-group"><a href="../../<?php echo $this->hash_no;?>/result" class="btn btn_confirm">확인</a></p>
</div>
</div>
+74
View File
@@ -0,0 +1,74 @@
<?php
include "./dbinfo.php";
$url = parse_url(strtolower($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']));
$url['path'] = str_replace("/index.php","",$url['path']); // AllowOverride None 때문에 htaccess 사용이 불가능 할 수 있음
$paths = explode('/', $url['path']);
$event_domains = ['sstrong.co.kr']; //Hotevent 경유하지 않는 event 자체 도메인. (외부도메인이 경로(/event/{no})가 아닌 event와 동일)
if(!preg_match('/^(local\.)?event\.hotblood\.co\.kr/', $url['path']) && !in_array($_SERVER['HTTP_HOST'], $event_domains))
$paths = array_slice($paths, 1);
//$paths = array_slice($paths, 1);
$uid = '';
if(preg_match('/^([A-Z]{2})?[0-9]+$/i', $paths[1])) {
$uid = $paths[1];
$method = @$paths[2];
} else {
$method = $paths[1];
}
if(!$method) $method = 'view';
if(in_array($method, ['makehash'])) {
$no = makeHash($paths[2]);
echo "<a href='/{$no}'>{$no}</a>";
exit;
}
if(in_array($method, ['kakao'])) {
include "./lib/kakao/link.php";
exit;
}
if(in_array($method, ['oauth'])) {
$provider = @$paths[2];
include "./lib/hybridauth3/auth.php";
exit;
}
if(in_array($method, ['kakaocallback'])) {
$provider = @$paths[2];
include "./lib/kakaoshare/callback.php";
exit;
}
if(in_array($method, ['eventleads'])) {
include "./lib/eventlead/EventLead.php";
$eventLead = new EventLead();
$eventLead->sendLeads();
exit;
}
if(in_array($method, ['addmemo'])) {
include "./zenith/updateMemo.php";
$updateMemo = new UpdateMemo();
exit;
}
if($method) { //저장된 메소드가 함수 일 경우 실행
include "core.php";
$event = new HotbloodEvent($paths);
$event->{$method}();
}
function makeHash($uid) {
$ab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$s_id = str_split($uid);
$make_hash = [0,0];
for($i=0; $i<count($s_id); $i++) $make_hash[0] += $s_id[$i]*($i+$s_id[count($s_id)-1]);
for($i=0; $i<count($s_id); $i++) $make_hash[1] += $s_id[$i]*($i+$s_id[0]);
$make_hash = array_map(function($v) use($ab){$chksum = ($v % 26); return $ab[$chksum];}, $make_hash);
$hash = implode("", $make_hash);
$result = $hash.$uid;
return $result;
}
?>
+6
View File
@@ -0,0 +1,6 @@
{
"require": {
"aws/aws-sdk-php": "^3.171",
"aws/aws-php-sns-message-validator": "^1.6"
}
}
+689
View File
@@ -0,0 +1,689 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0f2ad143337dc699335ffd17662b0f15",
"packages": [
{
"name": "aws/aws-php-sns-message-validator",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-php-sns-message-validator.git",
"reference": "ba6810807ac8936317021ccc14cdb1297d525ae1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-php-sns-message-validator/zipball/ba6810807ac8936317021ccc14cdb1297d525ae1",
"reference": "ba6810807ac8936317021ccc14cdb1297d525ae1",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"php": ">=5.4",
"psr/http-message": "^1.0"
},
"require-dev": {
"guzzlehttp/psr7": "^1.4",
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Aws\\Sns\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Amazon Web Services",
"homepage": "http://aws.amazon.com"
}
],
"description": "Amazon SNS message validation for PHP",
"homepage": "http://aws.amazon.com/sdkforphp",
"keywords": [
"SNS",
"amazon",
"aws",
"cloud",
"message",
"sdk",
"webhooks"
],
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sns-message-validator/issues",
"source": "https://github.com/aws/aws-php-sns-message-validator/tree/master"
},
"time": "2019-11-08T16:44:11+00:00"
},
{
"name": "aws/aws-sdk-php",
"version": "3.171.10",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "ba12cbba6b7ae8f2aab741e5ac47e8bb30d3eac7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ba12cbba6b7ae8f2aab741e5ac47e8bb30d3eac7",
"reference": "ba12cbba6b7ae8f2aab741e5ac47e8bb30d3eac7",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-pcre": "*",
"ext-simplexml": "*",
"guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.4.1",
"mtdowling/jmespath.php": "^2.5",
"php": ">=5.5"
},
"require-dev": {
"andrewsville/php-token-reflection": "^1.4",
"aws/aws-php-sns-message-validator": "~1.0",
"behat/behat": "~3.0",
"doctrine/cache": "~1.4",
"ext-dom": "*",
"ext-openssl": "*",
"ext-pcntl": "*",
"ext-sockets": "*",
"nette/neon": "^2.3",
"paragonie/random_compat": ">= 2",
"phpunit/phpunit": "^4.8.35|^5.4.3",
"psr/cache": "^1.0",
"psr/simple-cache": "^1.0",
"sebastian/comparator": "^1.2.3"
},
"suggest": {
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
"doctrine/cache": "To use the DoctrineCacheAdapter",
"ext-curl": "To send requests using cURL",
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
"ext-sockets": "To use client-side monitoring"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Aws\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Amazon Web Services",
"homepage": "http://aws.amazon.com"
}
],
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
"homepage": "http://aws.amazon.com/sdkforphp",
"keywords": [
"amazon",
"aws",
"cloud",
"dynamodb",
"ec2",
"glacier",
"s3",
"sdk"
],
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.171.10"
},
"time": "2020-12-31T19:13:37+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.2.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/0aa74dfb41ae110835923ef10a9d803a22d50e79",
"reference": "0aa74dfb41ae110835923ef10a9d803a22d50e79",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.4",
"guzzlehttp/psr7": "^1.7",
"php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"ext-curl": "*",
"php-http/client-integration-tests": "^3.0",
"phpunit/phpunit": "^8.5.5 || ^9.3.5",
"psr/log": "^1.1"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.1-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://sagikazarmark.hu"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.2.0"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://github.com/alexeyshockov",
"type": "github"
},
{
"url": "https://github.com/gmponos",
"type": "github"
}
],
"time": "2020-10-10T11:47:56+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "60d379c243457e073cff02bc323a2a86cb355631"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/60d379c243457e073cff02bc323a2a86cb355631",
"reference": "60d379c243457e073cff02bc323a2a86cb355631",
"shasum": ""
},
"require": {
"php": ">=5.5"
},
"require-dev": {
"symfony/phpunit-bridge": "^4.4 || ^5.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.4.0"
},
"time": "2020-09-30T07:37:28+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3",
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0",
"ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"ext-zlib": "*",
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.7-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Schultze",
"homepage": "https://github.com/Tobion"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.7.0"
},
"time": "2020-09-30T07:37:11+00:00"
},
{
"name": "mtdowling/jmespath.php",
"version": "2.6.0",
"source": {
"type": "git",
"url": "https://github.com/jmespath/jmespath.php.git",
"reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/42dae2cbd13154083ca6d70099692fef8ca84bfb",
"reference": "42dae2cbd13154083ca6d70099692fef8ca84bfb",
"shasum": ""
},
"require": {
"php": "^5.4 || ^7.0 || ^8.0",
"symfony/polyfill-mbstring": "^1.17"
},
"require-dev": {
"composer/xdebug-handler": "^1.4",
"phpunit/phpunit": "^4.8.36 || ^7.5.15"
},
"bin": [
"bin/jp.php"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
}
},
"autoload": {
"psr-4": {
"JmesPath\\": "src/"
},
"files": [
"src/JmesPath.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Declaratively specify how to extract elements from a JSON document",
"keywords": [
"json",
"jsonpath"
],
"support": {
"issues": "https://github.com/jmespath/jmespath.php/issues",
"source": "https://github.com/jmespath/jmespath.php/tree/2.6.0"
},
"time": "2020-07-31T21:01:56+00:00"
},
{
"name": "psr/http-client",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
"homepage": "https://github.com/php-fig/http-client",
"keywords": [
"http",
"http-client",
"psr",
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/master"
},
"time": "2020-06-29T06:28:15+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
},
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph Khattar",
"email": "ralph.khattar@gmail.com"
}
],
"description": "A polyfill for getallheaders.",
"support": {
"issues": "https://github.com/ralouphie/getallheaders/issues",
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.20.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "39d483bdf39be819deabf04ec872eb0b2410b531"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531",
"reference": "39d483bdf39be819deabf04ec872eb0b2410b531",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.20-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.20.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-23T14:02:19+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.0.0"
}
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit07c369a782c685010d127e34671ba325::getLoader();
@@ -0,0 +1,21 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature-request
assignees: ''
---
### Is this related to a problem?
A clear and concise description of the issue, e.g. I'm always frustrated when...
### Feature description
Describe what you want to happen.
### Describe alternatives you've considered
Any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,29 @@
---
name: General issue
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Please fill out the sections below to help us address your issue.
### Version of AWS SDK for PHP?
### Version of Amazon SNS Message Validator for PHP?
### Version of PHP (`php -v`)?
### What issue did you see?
### Steps to reproduce
If you have a runnable example, please include it as a snippet or link to a repository/gist for larger code examples.
### Additional context
Any additional information relevant to the issue. Examples include any framework you may be using (e.g. Laravel, Wordpress) in conjunction with the AWS SDK for PHP, or PHP/environment config settings if the issue is related to memory or performance.
@@ -0,0 +1,6 @@
*Issue #, if available:*
*Description of changes:*
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
@@ -0,0 +1,10 @@
phpunit.xml
Makefile
/.idea/
/*.iml
atlassian-ide-plugin.xml
.DS_Store
.swp
.build
composer.lock
vendor/
@@ -0,0 +1,27 @@
dist: trusty
language: php
php:
- 5.4
- 5.5
- 5.6
- 7.0
- 7.1
- 7.2
- 7.3
- hhvm
- nightly
matrix:
allow_failures:
- php: hhvm
- php: nightly
sudo: false
dist: trusty
install:
- travis_retry composer update --no-interaction --prefer-dist
script: vendor/bin/phpunit
@@ -0,0 +1,4 @@
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.
@@ -0,0 +1,61 @@
# Contributing Guidelines
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
documentation, we greatly value feedback and contributions from our community.
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
information to effectively respond to your bug report or contribution.
## Reporting Bugs/Feature Requests
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
When filing an issue, please check [existing open](https://github.com/aws/aws-php-sns-message-validator/issues), or [recently closed](https://github.com/aws/aws-php-sns-message-validator/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
* A reproducible test case or series of steps
* The version of our code being used
* Any modifications you've made relevant to the bug
* Anything unusual about your environment or deployment
## Contributing via Pull Requests
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
1. You are working against the latest source on the *master* branch.
2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
To send us a pull request, please:
1. Fork the repository.
2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
3. Ensure local tests pass.
4. Commit to your fork using clear commit messages.
5. Send us a pull request, answering any default questions in the pull request interface.
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
## Finding contributions to work on
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/aws-php-sns-message-validator/labels/help%20wanted) issues is a great place to start.
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.
## Security issue notifications
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
## Licensing
See the [LICENSE](https://github.com/aws/aws-php-sns-message-validator/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
@@ -0,0 +1,141 @@
# Apache License
Version 2.0, January 2004
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
## 1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1
through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the
License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled
by, or are under common control with that entity. For the purposes of this definition, "control" means
(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract
or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software
source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form,
including but not limited to compiled object code, generated documentation, and conversions to other media
types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License,
as indicated by a copyright notice that is included in or attached to the work (an example is provided in the
Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from)
the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent,
as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not
include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work
and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any
modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to
Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to
submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
electronic, verbal, or written communication sent to the Licensor or its representatives, including but not
limited to communication on electronic mailing lists, source code control systems, and issue tracking systems
that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been
received by Licensor and subsequently incorporated within the Work.
## 2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
## 3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent
license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such
license applies only to those patent claims licensable by such Contributor that are necessarily infringed by
their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim
or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
constitutes direct or contributory patent infringement, then any patent licenses granted to You under this
License for that Work shall terminate as of the date such litigation is filed.
## 4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You meet the following conditions:
1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
2. You must cause any modified files to carry prominent notices stating that You changed the files; and
3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent,
trademark, and attribution notices from the Source form of the Work, excluding those notices that do
not pertain to any part of the Derivative Works; and
4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that
You distribute must include a readable copy of the attribution notices contained within such NOTICE
file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed as part of the Derivative Works; within
the Source form or documentation, if provided along with the Derivative Works; or, within a display
generated by the Derivative Works, if and wherever such third-party notices normally appear. The
contents of the NOTICE file are for informational purposes only and do not modify the License. You may
add Your own attribution notices within Derivative Works that You distribute, alongside or as an
addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be
construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license
terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative
Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the
conditions stated in this License.
## 5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by
You to the Licensor shall be under the terms and conditions of this License, without any additional terms or
conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate
license agreement you may have executed with Licensor regarding such Contributions.
## 6. Trademarks.
This License does not grant permission to use the trade names, trademarks, service marks, or product names of
the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
## 7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor
provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
## 8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless
required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any
Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential
damages of any character arising as a result of this License or out of the use or inability to use the Work
(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has been advised of the possibility
of such damages.
## 9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for,
acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole
responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold
each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
@@ -0,0 +1,158 @@
# Amazon SNS Message Validator for PHP
[![@awsforphp on Twitter](http://img.shields.io/badge/twitter-%40awsforphp-blue.svg?style=flat)](https://twitter.com/awsforphp)
[![Total Downloads](https://img.shields.io/packagist/dt/aws/aws-php-sns-message-validator.svg?style=flat)](https://packagist.org/packages/aws/aws-php-sns-message-validator)
[![Build Status](https://img.shields.io/travis/aws/aws-php-sns-message-validator.svg?style=flat)](https://travis-ci.org/aws/aws-php-sns-message-validator)
[![Apache 2 License](https://img.shields.io/packagist/l/aws/aws-php-sns-message-validator.svg?style=flat)](http://aws.amazon.com/apache-2-0/)
The **Amazon SNS Message Validator for PHP** library allows you to validate that
incoming HTTP(S) POST messages are valid Amazon SNS notifications. This library
is standalone and does not depend on the AWS SDK for PHP or Guzzle; however, it
does require PHP 5.4+ and that the OpenSSL PHP extension is installed.
## Basic Usage
To validate a message, you can instantiate a `Message` object from the POST
data using the `Message::fromRawPostData`. This reads the raw POST data from
the [`php://input` stream][php-input], decodes the JSON data, and validates
the message's type and structure.
Next, you must create an instance of `MessageValidator`, and then use either
the `isValid()` or `validate()`, methods to validate the message. The
message validator checks the `SigningCertURL`, `SignatureVersion`, and
`Signature` to make sure they are valid and consistent with the message data.
```php
<?php
require 'vendor/autoload.php';
use Aws\Sns\Message;
use Aws\Sns\MessageValidator;
$message = Message::fromRawPostData();
// Validate the message
$validator = new MessageValidator();
if ($validator->isValid($message)) {
// do something with the message
}
```
## Installation
The SNS Message Validator can be installed via [Composer][].
$ composer require aws/aws-php-sns-message-validator
## About Amazon SNS
[Amazon Simple Notification Service (Amazon SNS)][sns] is a fast, fully-managed,
push messaging service. Amazon SNS can deliver messages to email, mobile devices
(i.e., SMS; iOS, Android and FireOS push notifications), Amazon SQS queues,and
— of course — HTTP/HTTPS endpoints.
With Amazon SNS, you can setup topics to publish custom messages to subscribed
endpoints. However, SNS messages are used by many of the other AWS services to
communicate information asynchronously about your AWS resources. Some examples
include:
* Configuring Amazon Glacier to notify you when a retrieval job is complete.
* Configuring AWS CloudTrail to notify you when a new log file has been written.
* Configuring Amazon Elastic Transcoder to notify you when a transcoding job
changes status (e.g., from "Progressing" to "Complete")
Though you can certainly subscribe your email address to receive SNS messages
from service events like these, your inbox would fill up rather quickly. There
is great power, however, in being able to subscribe an HTTP/HTTPS endpoint to
receive the messages. This allows you to program webhooks for your applications
to easily respond to various events.
## Handling Messages
### Confirming a Subscription to a Topic
In order to handle a `SubscriptionConfirmation` message, you must use the
`SubscribeURL` value in the incoming message:
```php
use Aws\Sns\Message;
use Aws\Sns\MessageValidator;
use Aws\Sns\Exception\InvalidSnsMessageException;
// Instantiate the Message and Validator
$message = Message::fromRawPostData();
$validator = new MessageValidator();
// Validate the message and log errors if invalid.
try {
$validator->validate($message);
} catch (InvalidSnsMessageException $e) {
// Pretend we're not here if the message is invalid.
http_response_code(404);
error_log('SNS Message Validation Error: ' . $e->getMessage());
die();
}
// Check the type of the message and handle the subscription.
if ($message['Type'] === 'SubscriptionConfirmation') {
// Confirm the subscription by sending a GET request to the SubscribeURL
file_get_contents($message['SubscribeURL']);
}
```
### Receiving a Notification
To receive a notification, use the same code as the preceding example, but
check for the `Notification` message type.
```php
if ($message['Type'] === 'Notification') {
// Do whatever you want with the message body and data.
echo $message['MessageId'] . ': ' . $message['Message'] . "\n";
}
```
The message body will be a string, and will hold whatever data was published
to the SNS topic.
### Unsubscribing
Unsubscribing looks the same as subscribing, except the message type will be
`UnsubscribeConfirmation`.
```php
if ($message['Type'] === 'UnsubscribeConfirmation') {
// Unsubscribed in error? You can resubscribe by visiting the endpoint
// provided as the message's SubscribeURL field.
file_get_contents($message['SubscribeURL']);
}
```
## Testing Locally
One challenge of using webhooks in a web application is testing the integration
with the service. Testing integrations with SNS notifications can be fairly easy
using tools like [ngrok][] and [PHP's built-in webserver][php-server]. One of
our blog posts, [*Testing Webhooks Locally for Amazon SNS*][blogpost], illustrates
a good technique for testing.
> **NOTE:** The code samples in the blog post are specific to the message
> validator in Version 2 of the SDK, but can be easily adapted to using this
> version.
### Special Thank You
A special thanks goes out to [Julian Vidal][] who helped create the [initial
implementation][] in Version 2 of the [AWS SDK for PHP][].
[php-input]: http://php.net/manual/en/wrappers.php.php#wrappers.php.input
[composer]: https://getcomposer.org/
[source code]: https://github.com/aws/aws-php-sns-message-validator/archive/master.zip
[sns]: http://aws.amazon.com/sns/
[ngrok]: https://ngrok.com/
[php-server]: http://www.php.net/manual/en/features.commandline.webserver.php
[blogpost]: http://blogs.aws.amazon.com/php/post/Tx2CO24DVG9CAK0/Testing-Webhooks-Locally-for-Amazon-SNS
[Julian Vidal]: https://github.com/poisa
[initial implementation]: https://github.com/aws/aws-sdk-php/tree/2.8/src/Aws/Sns/MessageValidator
[AWS SDK for PHP]: https://github.com/aws/aws-sdk-php
@@ -0,0 +1,37 @@
{
"name": "aws/aws-php-sns-message-validator",
"homepage": "http://aws.amazon.com/sdkforphp",
"description": "Amazon SNS message validation for PHP",
"keywords": ["aws","amazon","sdk","sns","message","webhooks","cloud"],
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "Amazon Web Services",
"homepage": "http://aws.amazon.com"
}
],
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sns-message-validator/issues"
},
"require": {
"php": ">=5.4",
"ext-openssl": "*",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.3",
"guzzlehttp/psr7": "^1.4"
},
"autoload": {
"psr-4": { "Aws\\Sns\\": "src/" }
},
"autoload-dev": {
"psr-4": { "Aws\\Sns\\": "tests/" }
},
"scripts": {
"test": "phpunit"
}
}
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./vendor/autoload.php">
<testsuites>
<testsuite name="AWS SNS Message Validator Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
</phpunit>
@@ -0,0 +1,9 @@
<?php
namespace Aws\Sns\Exception;
/**
* Runtime exception thrown by the SNS Message Validator.
*/
class InvalidSnsMessageException extends \RuntimeException
{
}
@@ -0,0 +1,156 @@
<?php
namespace Aws\Sns;
use Psr\Http\Message\RequestInterface;
/**
* Represents an SNS message received over http(s).
*/
class Message implements \ArrayAccess, \IteratorAggregate
{
private static $requiredKeys = [
'Message',
'MessageId',
'Timestamp',
'TopicArn',
'Type',
'Signature',
['SigningCertURL', 'SigningCertUrl'],
'SignatureVersion',
];
private static $subscribeKeys = [
['SubscribeURL', 'SubscribeUrl'],
'Token'
];
/** @var array The message data */
private $data;
/**
* Creates a Message object from the raw POST data
*
* @return Message
* @throws \RuntimeException If the POST data is absent, or not a valid JSON document
*/
public static function fromRawPostData()
{
// Make sure the SNS-provided header exists.
if (!isset($_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE'])) {
throw new \RuntimeException('SNS message type header not provided.');
}
// Read the raw POST data and JSON-decode it into a message.
return self::fromJsonString(file_get_contents('php://input'));
}
/**
* Creates a Message object from a PSR-7 Request or ServerRequest object.
*
* @param RequestInterface $request
* @return Message
*/
public static function fromPsrRequest(RequestInterface $request)
{
return self::fromJsonString($request->getBody());
}
/**
* Creates a Message object from a JSON-decodable string.
*
* @param string $requestBody
* @return Message
*/
public static function fromJsonString($requestBody)
{
$data = json_decode($requestBody, true);
if (JSON_ERROR_NONE !== json_last_error() || !is_array($data)) {
throw new \RuntimeException('Invalid POST data.');
}
return new Message($data);
}
/**
* Creates a Message object from an array of raw message data.
*
* @param array $data The message data.
*
* @throws \InvalidArgumentException If a valid type is not provided or
* there are other required keys missing.
*/
public function __construct(array $data)
{
// Ensure that all the required keys for the message's type are present.
$this->validateRequiredKeys($data, self::$requiredKeys);
if ($data['Type'] === 'SubscriptionConfirmation'
|| $data['Type'] === 'UnsubscribeConfirmation'
) {
$this->validateRequiredKeys($data, self::$subscribeKeys);
}
$this->data = $data;
}
public function getIterator()
{
return new \ArrayIterator($this->data);
}
public function offsetExists($key)
{
return isset($this->data[$key]);
}
public function offsetGet($key)
{
return isset($this->data[$key]) ? $this->data[$key] : null;
}
public function offsetSet($key, $value)
{
$this->data[$key] = $value;
}
public function offsetUnset($key)
{
unset($this->data[$key]);
}
/**
* Get all the message data as a plain array.
*
* @return array
*/
public function toArray()
{
return $this->data;
}
private function validateRequiredKeys(array $data, array $keys)
{
foreach ($keys as $key) {
$keyIsArray = is_array($key);
if (!$keyIsArray) {
$found = isset($data[$key]);
} else {
$found = false;
foreach ($key as $keyOption) {
if (isset($data[$keyOption])) {
$found = true;
break;
}
}
}
if (!$found) {
if ($keyIsArray) {
$key = $key[0];
}
throw new \InvalidArgumentException(
"\"{$key}\" is required to verify the SNS Message."
);
}
}
}
}
@@ -0,0 +1,192 @@
<?php
namespace Aws\Sns;
use Aws\Sns\Exception\InvalidSnsMessageException;
/**
* Uses openssl to verify SNS messages to ensure that they were sent by AWS.
*/
class MessageValidator
{
const SIGNATURE_VERSION_1 = '1';
/**
* @var callable Callable used to download the certificate content.
*/
private $certClient;
/** @var string */
private $hostPattern;
/**
* @var string A pattern that will match all regional SNS endpoints, e.g.:
* - sns.<region>.amazonaws.com (AWS)
* - sns.us-gov-west-1.amazonaws.com (AWS GovCloud)
* - sns.cn-north-1.amazonaws.com.cn (AWS China)
*/
private static $defaultHostPattern
= '/^sns\.[a-zA-Z0-9\-]{3,}\.amazonaws\.com(\.cn)?$/';
private static function isLambdaStyle(Message $message)
{
return isset($message['SigningCertUrl']);
}
private static function convertLambdaMessage(Message $lambdaMessage)
{
$keyReplacements = [
'SigningCertUrl' => 'SigningCertURL',
'SubscribeUrl' => 'SubscribeURL',
'UnsubscribeUrl' => 'UnsubscribeURL',
];
$message = clone $lambdaMessage;
foreach ($keyReplacements as $lambdaKey => $canonicalKey) {
if (isset($message[$lambdaKey])) {
$message[$canonicalKey] = $message[$lambdaKey];
unset($message[$lambdaKey]);
}
}
return $message;
}
/**
* Constructs the Message Validator object and ensures that openssl is
* installed.
*
* @param callable $certClient Callable used to download the certificate.
* Should have the following function signature:
* `function (string $certUrl) : string|false $certContent`
* @param string $hostNamePattern
*/
public function __construct(
callable $certClient = null,
$hostNamePattern = ''
) {
$this->certClient = $certClient ?: function($certUrl) {
return @ file_get_contents($certUrl);
};
$this->hostPattern = $hostNamePattern ?: self::$defaultHostPattern;
}
/**
* Validates a message from SNS to ensure that it was delivered by AWS.
*
* @param Message $message Message to validate.
*
* @throws InvalidSnsMessageException If the cert cannot be retrieved or its
* source verified, or the message
* signature is invalid.
*/
public function validate(Message $message)
{
if (self::isLambdaStyle($message)) {
$message = self::convertLambdaMessage($message);
}
// Get the certificate.
$this->validateUrl($message['SigningCertURL']);
$certificate = call_user_func($this->certClient, $message['SigningCertURL']);
if ($certificate === false) {
throw new InvalidSnsMessageException(
"Cannot get the certificate from \"{$message['SigningCertURL']}\"."
);
}
// Extract the public key.
$key = openssl_get_publickey($certificate);
if (!$key) {
throw new InvalidSnsMessageException(
'Cannot get the public key from the certificate.'
);
}
// Verify the signature of the message.
$content = $this->getStringToSign($message);
$signature = base64_decode($message['Signature']);
if (openssl_verify($content, $signature, $key, OPENSSL_ALGO_SHA1) != 1) {
throw new InvalidSnsMessageException(
'The message signature is invalid.'
);
}
}
/**
* Determines if a message is valid and that is was delivered by AWS. This
* method does not throw exceptions and returns a simple boolean value.
*
* @param Message $message The message to validate
*
* @return bool
*/
public function isValid(Message $message)
{
try {
$this->validate($message);
return true;
} catch (InvalidSnsMessageException $e) {
return false;
}
}
/**
* Builds string-to-sign according to the SNS message spec.
*
* @param Message $message Message for which to build the string-to-sign.
*
* @return string
* @link http://docs.aws.amazon.com/sns/latest/gsg/SendMessageToHttp.verify.signature.html
*/
public function getStringToSign(Message $message)
{
static $signableKeys = [
'Message',
'MessageId',
'Subject',
'SubscribeURL',
'Timestamp',
'Token',
'TopicArn',
'Type',
];
if ($message['SignatureVersion'] !== self::SIGNATURE_VERSION_1) {
throw new InvalidSnsMessageException(
"The SignatureVersion \"{$message['SignatureVersion']}\" is not supported."
);
}
$stringToSign = '';
foreach ($signableKeys as $key) {
if (isset($message[$key])) {
$stringToSign .= "{$key}\n{$message[$key]}\n";
}
}
return $stringToSign;
}
/**
* Ensures that the URL of the certificate is one belonging to AWS, and not
* just something from the amazonaws domain, which could include S3 buckets.
*
* @param string $url Certificate URL
*
* @throws InvalidSnsMessageException if the cert url is invalid.
*/
private function validateUrl($url)
{
$parsed = parse_url($url);
if (empty($parsed['scheme'])
|| empty($parsed['host'])
|| $parsed['scheme'] !== 'https'
|| substr($url, -4) !== '.pem'
|| !preg_match($this->hostPattern, $parsed['host'])
) {
throw new InvalidSnsMessageException(
'The certificate is located on an invalid domain.'
);
}
}
}
@@ -0,0 +1,148 @@
<?php
namespace Aws\Sns;
/**
* @covers Aws\Sns\MessageValidator
* @covers Aws\Sns\Message
*/
class FunctionalValidationsTest extends \PHPUnit_Framework_TestCase
{
private static $certificate =
'-----BEGIN CERTIFICATE-----
MIIF5DCCBMygAwIBAgIQMlyV8Y5saUjyFgu3K5kFwTANBgkqhkiG9w0BAQsFADB+
MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd
BgNVBAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVj
IENsYXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MB4XDTE2MDcyNzAwMDAwMFoX
DTE3MDgyMjIzNTk1OVowazELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0
b24xEDAOBgNVBAcMB1NlYXR0bGUxGTAXBgNVBAoMEEFtYXpvbi5jb20sIEluYy4x
GjAYBgNVBAMMEXNucy5hbWF6b25hd3MuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAmYrVPHC2QSE/OR8w9UfnjdPqEoAfOxhwJna/2W+/C+vTrMzd
4R9E3kfA3arf43LZFTSQ23Ed3Tao8srh/iK7DFv87bR+5uPnEO4fcHXDiJ1n3WMU
kjo+BEKXwSdR4AfIRUrJB2hk3mhXJoGkYJp3WBZ2ieoYBqwxpxuFRtNQW4ttqNwt
q4mONfxg0840e1kY+xFQa7ya8zg9FGaVgeLiN+e/gv5YYdrk8JG4P6kbzil9bETm
Xm+PXoxWy6cMAT3Coz1NNkPGQrKfNfGZSdPGh1d/89IwRh+eNUEIJ8PdnhzcvgN7
RQ5zs70V6u7StvrNukYftMwY0hIELlMUHYqRbQIDAQABo4ICbzCCAmswHAYDVR0R
BBUwE4IRc25zLmFtYXpvbmF3cy5jb20wCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMC
BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMGEGA1UdIARaMFgwVgYG
Z4EMAQICMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8vZC5zeW1jYi5jb20vY3BzMCUG
CCsGAQUFBwICMBkMF2h0dHBzOi8vZC5zeW1jYi5jb20vcnBhMB8GA1UdIwQYMBaA
FF9gz2GQVd+EQxSKYCqy9Xr0QxjvMCsGA1UdHwQkMCIwIKAeoByGGmh0dHA6Ly9z
cy5zeW1jYi5jb20vc3MuY3JsMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT
aHR0cDovL3NzLnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL3NzLnN5bWNi
LmNvbS9zcy5jcnQwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdgDd6x0reg1PpiCL
ga2BaHB+Lo6dAdVciI09EcTNtuy+zAAAAVYpz1FWAAAEAwBHMEUCIFYpMqHzT/IG
WKgBt6SwXJhfYmj3JKtAJWq5dabI7TuKAiEAqYyWQUjlFuKkIwEhx8x1I+WJz+hp
npW7Na0CzyUvZWMAdwCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAA
AVYpz1H+AAAEAwBIMEYCIQCY+492bMMCU3kRQPDQ27TRv5x+YuVkg+6ULi1Ddyea
KgIhANIVUCbM918/jMu0xc2cvrfov6SNAgPIjRLDGmDkLdJ1MA0GCSqGSIb3DQEB
CwUAA4IBAQBpQS/LverJ6gD2vuESrRi1COa4ABSLf584sL1yHLTNtf1GCUfZUgO+
CKacKGHcqxALOUi3m4PPQmuiNa20i6ttu7Q6+aj9zbq3VfJYwISFP1jLGjkiFtR2
ufBiIuB2T6dbZeYJ7Yg9DDTwwEgxHMjlT/DLyKPPPRFa0I/l3PmXMZh8iJNuxGiY
qOSxwAm9QMCaBJj+64HLyw4ZwO4rTgAxqtI/muZC3vw1nGoL7fer2X6MdW6PtYD/
ysixQTQtyDdNpB6yOGYFJv+Sf/0AcZST1a7HwfHt14JD+0I180FhGV1qFtx7KRUE
6Kw4sQp+ZMgtgzM8l3fDTMEgqpLSQH+2
-----END CERTIFICATE-----';
public function getHttpFixtures()
{
return [
[
[
'Type' => "Notification",
'MessageId' => "9438aee6-d476-5e20-ba25-ff24bf09d6ce",
'TopicArn' => "arn:aws:sns:us-west-2:604091128280:testing1",
'Subject' => "A subject",
'Message' => "A message",
'Timestamp' => "2017-06-20T00:15:59.380Z",
'SignatureVersion' => "1",
'Signature' => "WT7qMHW+jPdj/brSAX7M1jbP5OoPjn9pYmGQqrWeQgbMyVvz3D2sV72ldhCxQLqj/3TLtcTyErVqzT3AfQ8Vk55Rzxd1xnBufJ+0vIyH98b82pKOqRHOqlB72la5nY9/GF/p71BXmIChQpfv/CEZumexgLWnweJsqSMe82I6/eMmrhVZdKpBvz4Sqj+wNQW+0eYEc9bdZmEKuYIvrvTGm1MWkXmqUGuCGj5o3vFFn1GTtM895B3MyMgaSeDHI08CVfs9y1nLcrxwMvqpkHZmIwTi1jzSipYMRD8FVF6Wvq0Scy+FoYSnOWHpEsELI0SGddSqYgli9ROYiqi3DQhvHw==",
'SigningCertURL' => "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem",
'UnsubscribeURL' => "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:b061e4fd-c468-458d-9736-91c8c0c18e29",
]
],
[
[
'Type' => "Notification",
'MessageId' => "7317aaf2-e97a-5cf3-8123-fb3a48fabd2a",
'TopicArn' => "arn:aws:sns:us-west-2:604091128280:testing1",
'Message' => "A subject-less message",
'Timestamp' => "2017-06-24T17:20:00.581Z",
'SignatureVersion' => "1",
'Signature' => "Lvtgxo8P2C3XUKT8fC7sfMRhxoK6dn/ed9B1DClmJ9GNuFF73G27lhKUsKWrLReawa+v7C1UY49qQb+lSMsBiTV0Hx7L2OKJjzll4fx+G09h2P8OK43Jk6/W05+xU0uvch6Ktp3XrBcI6KNyGFio5GAR2rCBHjdh8MsEYAWRtaVCBqJTLqnHscivOJD8u/m807wDbDhh9cQ5WnvjerUjtrDAfQJN5vHLjEPbL1owtu2FzC3rOHUL9j4TGOdZi2jhUYv8jwzNnJ05bhbtKd6HxKcTcv1JCp/4NLPa8LWYnbLRvWooDQdF2hr56EF6EKDzTtAWagoNYztwSvosQXNK+Q==",
'SigningCertURL' => "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem",
'UnsubscribeURL' => "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:f0dd49ac-c33d-471e-812d-1f0e5116c711",
]
],
];
}
public function getLambdaFixtures()
{
return [
[
[
'Type' => 'Notification',
'MessageId' => '9438aee6-d476-5e20-ba25-ff24bf09d6ce',
'TopicArn' => 'arn:aws:sns:us-west-2:604091128280:testing1',
'Subject' => 'A subject',
'Message' => 'A message',
'Timestamp' => '2017-06-20T00:15:59.380Z',
'SignatureVersion' => '1',
'Signature' => 'WT7qMHW+jPdj/brSAX7M1jbP5OoPjn9pYmGQqrWeQgbMyVvz3D2sV72ldhCxQLqj/3TLtcTyErVqzT3AfQ8Vk55Rzxd1xnBufJ+0vIyH98b82pKOqRHOqlB72la5nY9/GF/p71BXmIChQpfv/CEZumexgLWnweJsqSMe82I6/eMmrhVZdKpBvz4Sqj+wNQW+0eYEc9bdZmEKuYIvrvTGm1MWkXmqUGuCGj5o3vFFn1GTtM895B3MyMgaSeDHI08CVfs9y1nLcrxwMvqpkHZmIwTi1jzSipYMRD8FVF6Wvq0Scy+FoYSnOWHpEsELI0SGddSqYgli9ROYiqi3DQhvHw==',
'SigningCertUrl' => 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem',
'UnsubscribeUrl' => 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:7118d01a-202e-4a65-a372-f46b0994bdae',
]
],
[
[
'Type' => 'Notification',
'MessageId' => '7317aaf2-e97a-5cf3-8123-fb3a48fabd2a',
'TopicArn' => 'arn:aws:sns:us-west-2:604091128280:testing1',
'Subject' => null,
'Message' => 'A subject-less message',
'Timestamp' => '2017-06-24T17:20:00.581Z',
'SignatureVersion' => '1',
'Signature' => 'Lvtgxo8P2C3XUKT8fC7sfMRhxoK6dn/ed9B1DClmJ9GNuFF73G27lhKUsKWrLReawa+v7C1UY49qQb+lSMsBiTV0Hx7L2OKJjzll4fx+G09h2P8OK43Jk6/W05+xU0uvch6Ktp3XrBcI6KNyGFio5GAR2rCBHjdh8MsEYAWRtaVCBqJTLqnHscivOJD8u/m807wDbDhh9cQ5WnvjerUjtrDAfQJN5vHLjEPbL1owtu2FzC3rOHUL9j4TGOdZi2jhUYv8jwzNnJ05bhbtKd6HxKcTcv1JCp/4NLPa8LWYnbLRvWooDQdF2hr56EF6EKDzTtAWagoNYztwSvosQXNK+Q==',
'SigningCertUrl' => 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem',
'UnsubscribeUrl' => 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:7118d01a-202e-4a65-a372-f46b0994bdae',
]
],
];
}
private function getMockCertServerClient()
{
return function () {
return self::$certificate;
};
}
/**
* @dataProvider getHttpFixtures
*
* @param array $messageData
*/
public function testValidatesHttpFixtures($messageData)
{
$validator = new MessageValidator($this->getMockCertServerClient());
$message = new Message($messageData);
$this->assertTrue($validator->isValid($message));
$this->assertNotEmpty($message['SigningCertURL']);
}
/**
* @dataProvider getLambdaFixtures
*
* @param array $messageData
*/
public function testValidatesLambdaFixtures($messageData)
{
$validator = new MessageValidator($this->getMockCertServerClient());
$message = new Message($messageData);
$this->assertTrue($validator->isValid($message));
$this->assertNotEmpty($message['SigningCertUrl']);
}
}
@@ -0,0 +1,183 @@
<?php
namespace Aws\Sns;
use GuzzleHttp\Psr7\Request;
/**
* @covers \Aws\Sns\Message
*/
class MessageTest extends \PHPUnit_Framework_TestCase
{
public $messageData = array(
'Message' => 'a',
'MessageId' => 'b',
'Timestamp' => 'c',
'TopicArn' => 'd',
'Type' => 'e',
'Subject' => 'f',
'Signature' => 'g',
'SignatureVersion' => '1',
'SigningCertURL' => 'h',
'SubscribeURL' => 'i',
'Token' => 'j',
);
public function testGetters()
{
$message = new Message($this->messageData);
$this->assertInternalType('array', $message->toArray());
foreach ($this->messageData as $key => $expectedValue) {
$this->assertTrue(isset($message[$key]));
$this->assertEquals($expectedValue, $message[$key]);
}
}
public function testIterable()
{
$message = new Message($this->messageData);
$this->assertInstanceOf('Traversable', $message);
foreach ($message as $key => $value) {
$this->assertTrue(isset($this->messageData[$key]));
$this->assertEquals($value, $this->messageData[$key]);
}
}
/**
* @dataProvider messageTypeProvider
*
* @param string $messageType
*/
public function testConstructorSucceedsWithGoodData($messageType)
{
$this->assertInstanceOf('Aws\Sns\Message', new Message(
['Type' => $messageType] + $this->messageData
));
}
public function messageTypeProvider()
{
return [
['Notification'],
['SubscriptionConfirmation'],
['UnsubscribeConfirmation'],
];
}
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorFailsWithNoType()
{
$data = $this->messageData;
unset($data['Type']);
new Message($data);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorFailsWithMissingData()
{
new Message(['Type' => 'Notification']);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRequiresTokenAndSubscribeUrlForSubscribeMessage()
{
new Message(
['Type' => 'SubscriptionConfirmation'] + array_diff_key(
$this->messageData,
array_flip(['Token', 'SubscribeURL'])
)
);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testRequiresTokenAndSubscribeUrlForUnsubscribeMessage()
{
new Message(
['Type' => 'UnsubscribeConfirmation'] + array_diff_key(
$this->messageData,
array_flip(['Token', 'SubscribeURL'])
)
);
}
public function testCanCreateFromRawPost()
{
$_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE'] = 'Notification';
// Prep php://input with mocked data
MockPhpStream::setStartingData(json_encode($this->messageData));
stream_wrapper_unregister('php');
stream_wrapper_register('php', __NAMESPACE__ . '\MockPhpStream');
$message = Message::fromRawPostData();
$this->assertInstanceOf('Aws\Sns\Message', $message);
stream_wrapper_restore("php");
unset($_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE']);
}
/**
* @expectedException \RuntimeException
*/
public function testCreateFromRawPostFailsWithMissingHeader()
{
Message::fromRawPostData();
}
/**
* @expectedException \RuntimeException
*/
public function testCreateFromRawPostFailsWithMissingData()
{
$_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE'] = 'Notification';
Message::fromRawPostData();
unset($_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE']);
}
public function testCanCreateFromPsr7Request()
{
$request = new Request(
'POST',
'/',
[],
json_encode($this->messageData)
);
$message = Message::fromPsrRequest($request);
$this->assertInstanceOf('Aws\Sns\Message', $message);
}
/**
* @expectedException \RuntimeException
*/
public function testCreateFromPsr7RequestFailsWithMissingData()
{
$request = new Request(
'POST',
'/',
[],
'Not valid JSON'
);
Message::fromPsrRequest($request);
}
public function testArrayAccess()
{
$message = new Message($this->messageData);
$this->assertInstanceOf('ArrayAccess', $message);
$message['foo'] = 'bar';
$this->assertTrue(isset($message['foo']));
$this->assertTrue($message['foo'] === 'bar');
unset($message['foo']);
$this->assertFalse(isset($message['foo']));
}
}
@@ -0,0 +1,209 @@
<?php
namespace Aws\Sns;
/**
* @covers Aws\Sns\MessageValidator
*/
class MessageValidatorTest extends \PHPUnit_Framework_TestCase
{
const VALID_CERT_URL = 'https://sns.foo.amazonaws.com/bar.pem';
private static $pKey;
private static $certificate;
public static function setUpBeforeClass()
{
self::$pKey = openssl_pkey_new();
$csr = openssl_csr_new([], self::$pKey);
$x509 = openssl_csr_sign($csr, null, self::$pKey, 1);
openssl_x509_export($x509, self::$certificate);
openssl_x509_free($x509);
}
public static function tearDownAfterClass()
{
openssl_pkey_free(self::$pKey);
}
public function testIsValidReturnsFalseOnFailedValidation()
{
$validator = new MessageValidator($this->getMockHttpClient());
$message = $this->getTestMessage([
'SignatureVersion' => '2',
]);
$this->assertFalse($validator->isValid($message));
}
/**
* @expectedException \Aws\Sns\Exception\InvalidSnsMessageException
* @expectedExceptionMessage The SignatureVersion "2" is not supported.
*/
public function testValidateFailsWhenSignatureVersionIsInvalid()
{
$validator = new MessageValidator($this->getMockCertServerClient());
$message = $this->getTestMessage([
'SignatureVersion' => '2',
]);
$validator->validate($message);
}
/**
* @expectedException \Aws\Sns\Exception\InvalidSnsMessageException
* @expectedExceptionMessage The certificate is located on an invalid domain.
*/
public function testValidateFailsWhenCertUrlInvalid()
{
$validator = new MessageValidator();
$message = $this->getTestMessage([
'SigningCertURL' => 'https://foo.amazonaws.com/bar.pem',
]);
$validator->validate($message);
}
/**
* @expectedException \Aws\Sns\Exception\InvalidSnsMessageException
* @expectedExceptionMessage The certificate is located on an invalid domain.
*/
public function testValidateFailsWhenCertUrlNotAPemFile()
{
$validator = new MessageValidator();
$message = $this->getTestMessage([
'SigningCertURL' => 'https://foo.amazonaws.com/bar',
]);
$validator->validate($message);
}
public function testValidatesAgainstCustomDomains()
{
$validator = new MessageValidator(
function () {
return self::$certificate;
},
'/^(foo|bar).example.com$/'
);
$message = $this->getTestMessage([
'SigningCertURL' => 'https://foo.example.com/baz.pem',
]);
$message['Signature'] = $this->getSignature($validator->getStringToSign($message));
$this->assertTrue($validator->isValid($message));
}
/**
* @expectedException \Aws\Sns\Exception\InvalidSnsMessageException
* @expectedExceptionMessageRegExp /Cannot get the certificate from ".+"./
*/
public function testValidateFailsWhenCannotGetCertificate()
{
$validator = new MessageValidator($this->getMockHttpClient(false));
$message = $this->getTestMessage();
$validator->validate($message);
}
/**
* @expectedException \Aws\Sns\Exception\InvalidSnsMessageException
* @expectedExceptionMessage Cannot get the public key from the certificate.
*/
public function testValidateFailsWhenCannotDeterminePublicKey()
{
$validator = new MessageValidator($this->getMockHttpClient());
$message = $this->getTestMessage();
$validator->validate($message);
}
/**
* @expectedException \Aws\Sns\Exception\InvalidSnsMessageException
* @expectedExceptionMessage The message signature is invalid.
*/
public function testValidateFailsWhenMessageIsInvalid()
{
$validator = new MessageValidator($this->getMockCertServerClient());
$message = $this->getTestMessage([
'Signature' => $this->getSignature('foo'),
]);
$validator->validate($message);
}
public function testValidateSucceedsWhenMessageIsValid()
{
$validator = new MessageValidator($this->getMockCertServerClient());
$message = $this->getTestMessage();
// Get the signature for a real message
$message['Signature'] = $this->getSignature($validator->getStringToSign($message));
// The message should validate
$this->assertTrue($validator->isValid($message));
}
public function testBuildsStringToSignCorrectly()
{
$validator = new MessageValidator();
$stringToSign = <<< STRINGTOSIGN
Message
foo
MessageId
bar
Timestamp
1435697129
TopicArn
baz
Type
Notification
STRINGTOSIGN;
$this->assertEquals(
$stringToSign,
$validator->getStringToSign($this->getTestMessage())
);
}
/**
* @param array $customData
*
* @return Message
*/
private function getTestMessage(array $customData = [])
{
return new Message($customData + [
'Message' => 'foo',
'MessageId' => 'bar',
'Timestamp' => time(),
'TopicArn' => 'baz',
'Type' => 'Notification',
'SigningCertURL' => self::VALID_CERT_URL,
'Signature' => true,
'SignatureVersion' => '1',
]);
}
private function getMockHttpClient($responseBody = '')
{
return function () use ($responseBody) {
return $responseBody;
};
}
private function getMockCertServerClient()
{
return function ($url) {
if ($url !== self::VALID_CERT_URL) {
return '';
}
return self::$certificate;
};
}
private function getSignature($stringToSign)
{
openssl_sign($stringToSign, $signature, self::$pKey);
return base64_encode($signature);
}
}
function time()
{
return 1435697129;
}
@@ -0,0 +1,60 @@
<?php
namespace Aws\Sns;
class MockPhpStream
{
private static $startingData = '';
private $index;
private $length;
private $data;
public static function setStartingData($data)
{
self::$startingData = $data;
}
public function __construct()
{
$this->data = self::$startingData;
$this->index = 0;
$this->length = strlen(self::$startingData);
}
public function stream_open($path, $mode, $options, &$opened_path)
{
return true;
}
public function stream_close()
{
}
public function stream_stat()
{
return array();
}
public function stream_flush()
{
return true;
}
public function stream_read($count)
{
$length = min($count, $this->length - $this->index);
$data = substr($this->data, $this->index);
$this->index = $this->index + $length;
return $data;
}
public function stream_eof()
{
return ($this->index >= $this->length);
}
public function stream_write($data)
{
return 0;
}
}
+4
View File
@@ -0,0 +1,4 @@
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.
+141
View File
@@ -0,0 +1,141 @@
# Apache License
Version 2.0, January 2004
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
## 1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1
through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the
License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled
by, or are under common control with that entity. For the purposes of this definition, "control" means
(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract
or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software
source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form,
including but not limited to compiled object code, generated documentation, and conversions to other media
types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License,
as indicated by a copyright notice that is included in or attached to the work (an example is provided in the
Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from)
the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent,
as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not
include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work
and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any
modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to
Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to
submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
electronic, verbal, or written communication sent to the Licensor or its representatives, including but not
limited to communication on electronic mailing lists, source code control systems, and issue tracking systems
that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been
received by Licensor and subsequently incorporated within the Work.
## 2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
## 3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent
license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such
license applies only to those patent claims licensable by such Contributor that are necessarily infringed by
their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such
Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim
or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
constitutes direct or contributory patent infringement, then any patent licenses granted to You under this
License for that Work shall terminate as of the date such litigation is filed.
## 4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You meet the following conditions:
1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
2. You must cause any modified files to carry prominent notices stating that You changed the files; and
3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent,
trademark, and attribution notices from the Source form of the Work, excluding those notices that do
not pertain to any part of the Derivative Works; and
4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that
You distribute must include a readable copy of the attribution notices contained within such NOTICE
file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed as part of the Derivative Works; within
the Source form or documentation, if provided along with the Derivative Works; or, within a display
generated by the Derivative Works, if and wherever such third-party notices normally appear. The
contents of the NOTICE file are for informational purposes only and do not modify the License. You may
add Your own attribution notices within Derivative Works that You distribute, alongside or as an
addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be
construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license
terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative
Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the
conditions stated in this License.
## 5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by
You to the Licensor shall be under the terms and conditions of this License, without any additional terms or
conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate
license agreement you may have executed with Licensor regarding such Contributions.
## 6. Trademarks.
This License does not grant permission to use the trade names, trademarks, service marks, or product names of
the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
## 7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor
provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
## 8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless
required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any
Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential
damages of any character arising as a result of this License or out of the use or inability to use the Work
(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has been advised of the possibility
of such damages.
## 9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for,
acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole
responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold
each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
+64
View File
@@ -0,0 +1,64 @@
# AWS SDK for PHP
<http://aws.amazon.com/php>
Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
A copy of the License is located at
<http://aws.amazon.com/apache2.0>
or in the "license" file accompanying this file. This file is distributed
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the specific language governing
permissions and limitations under the License.
# Guzzle
<https://github.com/guzzle/guzzle>
Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling
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.
# jmespath.php
<https://github.com/mtdowling/jmespath.php>
Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling
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.
+68
View File
@@ -0,0 +1,68 @@
{
"name": "aws/aws-sdk-php",
"homepage": "http://aws.amazon.com/sdkforphp",
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
"keywords": ["aws","amazon","sdk","s3","ec2","dynamodb","cloud","glacier"],
"type": "library",
"license": "Apache-2.0",
"authors": [
{
"name": "Amazon Web Services",
"homepage": "http://aws.amazon.com"
}
],
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues"
},
"require": {
"php": ">=5.5",
"guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0",
"guzzlehttp/psr7": "^1.4.1",
"guzzlehttp/promises": "^1.0",
"mtdowling/jmespath.php": "^2.5",
"ext-pcre": "*",
"ext-json": "*",
"ext-simplexml": "*"
},
"require-dev": {
"ext-openssl": "*",
"ext-dom": "*",
"ext-pcntl": "*",
"ext-sockets": "*",
"phpunit/phpunit": "^4.8.35|^5.4.3",
"behat/behat": "~3.0",
"doctrine/cache": "~1.4",
"aws/aws-php-sns-message-validator": "~1.0",
"nette/neon": "^2.3",
"andrewsville/php-token-reflection": "^1.4",
"psr/cache": "^1.0",
"psr/simple-cache": "^1.0",
"paragonie/random_compat": ">= 2",
"sebastian/comparator": "^1.2.3"
},
"suggest": {
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
"ext-curl": "To send requests using cURL",
"ext-sockets": "To use client-side monitoring",
"doctrine/cache": "To use the DoctrineCacheAdapter",
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications"
},
"autoload": {
"psr-4": {
"Aws\\": "src/"
},
"files": ["src/functions.php"]
},
"autoload-dev": {
"psr-4": {
"Aws\\Test\\": "tests/"
},
"classmap": ["build/"]
},
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
}
}
@@ -0,0 +1,55 @@
<?php
namespace Aws\ACMPCA;
use Aws\AwsClient;
/**
* This client is used to interact with the **AWS Certificate Manager Private Certificate Authority** service.
* @method \Aws\Result createCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise createCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result createCertificateAuthorityAuditReport(array $args = [])
* @method \GuzzleHttp\Promise\Promise createCertificateAuthorityAuditReportAsync(array $args = [])
* @method \Aws\Result createPermission(array $args = [])
* @method \GuzzleHttp\Promise\Promise createPermissionAsync(array $args = [])
* @method \Aws\Result deleteCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result deletePermission(array $args = [])
* @method \GuzzleHttp\Promise\Promise deletePermissionAsync(array $args = [])
* @method \Aws\Result deletePolicy(array $args = [])
* @method \GuzzleHttp\Promise\Promise deletePolicyAsync(array $args = [])
* @method \Aws\Result describeCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise describeCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result describeCertificateAuthorityAuditReport(array $args = [])
* @method \GuzzleHttp\Promise\Promise describeCertificateAuthorityAuditReportAsync(array $args = [])
* @method \Aws\Result getCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAsync(array $args = [])
* @method \Aws\Result getCertificateAuthorityCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAuthorityCertificateAsync(array $args = [])
* @method \Aws\Result getCertificateAuthorityCsr(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAuthorityCsrAsync(array $args = [])
* @method \Aws\Result getPolicy(array $args = [])
* @method \GuzzleHttp\Promise\Promise getPolicyAsync(array $args = [])
* @method \Aws\Result importCertificateAuthorityCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise importCertificateAuthorityCertificateAsync(array $args = [])
* @method \Aws\Result issueCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise issueCertificateAsync(array $args = [])
* @method \Aws\Result listCertificateAuthorities(array $args = [])
* @method \GuzzleHttp\Promise\Promise listCertificateAuthoritiesAsync(array $args = [])
* @method \Aws\Result listPermissions(array $args = [])
* @method \GuzzleHttp\Promise\Promise listPermissionsAsync(array $args = [])
* @method \Aws\Result listTags(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
* @method \Aws\Result putPolicy(array $args = [])
* @method \GuzzleHttp\Promise\Promise putPolicyAsync(array $args = [])
* @method \Aws\Result restoreCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise restoreCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result revokeCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise revokeCertificateAsync(array $args = [])
* @method \Aws\Result tagCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result untagCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagCertificateAuthorityAsync(array $args = [])
* @method \Aws\Result updateCertificateAuthority(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateCertificateAuthorityAsync(array $args = [])
*/
class ACMPCAClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\ACMPCA\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AWS Certificate Manager Private Certificate Authority** service.
*/
class ACMPCAException extends AwsException {}
@@ -0,0 +1,157 @@
<?php
namespace Aws;
use GuzzleHttp\Promise;
/**
* A configuration provider is a function that returns a promise that is
* fulfilled with a configuration object. This class provides base functionality
* usable by specific configuration provider implementations
*/
abstract class AbstractConfigurationProvider
{
const ENV_PROFILE = 'AWS_PROFILE';
const ENV_CONFIG_FILE = 'AWS_CONFIG_FILE';
public static $cacheKey;
protected static $interfaceClass;
protected static $exceptionClass;
/**
* Wraps a config provider and saves provided configuration in an
* instance of Aws\CacheInterface. Forwards calls when no config found
* in cache and updates cache with the results.
*
* @param callable $provider Configuration provider function to wrap
* @param CacheInterface $cache Cache to store configuration
* @param string|null $cacheKey (optional) Cache key to use
*
* @return callable
*/
public static function cache(
callable $provider,
CacheInterface $cache,
$cacheKey = null
) {
$cacheKey = $cacheKey ?: static::$cacheKey;
return function () use ($provider, $cache, $cacheKey) {
$found = $cache->get($cacheKey);
if ($found instanceof static::$interfaceClass) {
return Promise\promise_for($found);
}
return $provider()
->then(function ($config) use (
$cache,
$cacheKey
) {
$cache->set($cacheKey, $config);
return $config;
});
};
}
/**
* Creates an aggregate configuration provider that invokes the provided
* variadic providers one after the other until a provider returns
* configuration.
*
* @return callable
*/
public static function chain()
{
$links = func_get_args();
if (empty($links)) {
throw new \InvalidArgumentException('No providers in chain');
}
return function () use ($links) {
/** @var callable $parent */
$parent = array_shift($links);
$promise = $parent();
while ($next = array_shift($links)) {
$promise = $promise->otherwise($next);
}
return $promise;
};
}
/**
* Gets the environment's HOME directory if available.
*
* @return null|string
*/
protected static function getHomeDir()
{
// On Linux/Unix-like systems, use the HOME environment variable
if ($homeDir = getenv('HOME')) {
return $homeDir;
}
// Get the HOMEDRIVE and HOMEPATH values for Windows hosts
$homeDrive = getenv('HOMEDRIVE');
$homePath = getenv('HOMEPATH');
return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;
}
/**
* Gets default config file location from environment, falling back to aws
* default location
*
* @return string
*/
protected static function getDefaultConfigFilename()
{
if ($filename = getenv(self::ENV_CONFIG_FILE)) {
return $filename;
}
return self::getHomeDir() . '/.aws/config';
}
/**
* Wraps a config provider and caches previously provided configuration.
*
* @param callable $provider Config provider function to wrap.
*
* @return callable
*/
public static function memoize(callable $provider)
{
return function () use ($provider) {
static $result;
static $isConstant;
// Constant config will be returned constantly.
if ($isConstant) {
return $result;
}
// Create the initial promise that will be used as the cached value
if (null === $result) {
$result = $provider();
}
// Return config and set flag that provider is already set
return $result
->then(function ($config) use (&$isConstant) {
$isConstant = true;
return $config;
});
};
}
/**
* Reject promise with standardized exception.
*
* @param $msg
* @return Promise\RejectedPromise
*/
protected static function reject($msg)
{
$exceptionClass = static::$exceptionClass;
return new Promise\RejectedPromise(new $exceptionClass($msg));
}
}
@@ -0,0 +1,47 @@
<?php
namespace Aws\AccessAnalyzer;
use Aws\AwsClient;
/**
* This client is used to interact with the **Access Analyzer** service.
* @method \Aws\Result applyArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise applyArchiveRuleAsync(array $args = [])
* @method \Aws\Result createAnalyzer(array $args = [])
* @method \GuzzleHttp\Promise\Promise createAnalyzerAsync(array $args = [])
* @method \Aws\Result createArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise createArchiveRuleAsync(array $args = [])
* @method \Aws\Result deleteAnalyzer(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAnalyzerAsync(array $args = [])
* @method \Aws\Result deleteArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteArchiveRuleAsync(array $args = [])
* @method \Aws\Result getAnalyzedResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAnalyzedResourceAsync(array $args = [])
* @method \Aws\Result getAnalyzer(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAnalyzerAsync(array $args = [])
* @method \Aws\Result getArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise getArchiveRuleAsync(array $args = [])
* @method \Aws\Result getFinding(array $args = [])
* @method \GuzzleHttp\Promise\Promise getFindingAsync(array $args = [])
* @method \Aws\Result listAnalyzedResources(array $args = [])
* @method \GuzzleHttp\Promise\Promise listAnalyzedResourcesAsync(array $args = [])
* @method \Aws\Result listAnalyzers(array $args = [])
* @method \GuzzleHttp\Promise\Promise listAnalyzersAsync(array $args = [])
* @method \Aws\Result listArchiveRules(array $args = [])
* @method \GuzzleHttp\Promise\Promise listArchiveRulesAsync(array $args = [])
* @method \Aws\Result listFindings(array $args = [])
* @method \GuzzleHttp\Promise\Promise listFindingsAsync(array $args = [])
* @method \Aws\Result listTagsForResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
* @method \Aws\Result startResourceScan(array $args = [])
* @method \GuzzleHttp\Promise\Promise startResourceScanAsync(array $args = [])
* @method \Aws\Result tagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
* @method \Aws\Result untagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
* @method \Aws\Result updateArchiveRule(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateArchiveRuleAsync(array $args = [])
* @method \Aws\Result updateFindings(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateFindingsAsync(array $args = [])
*/
class AccessAnalyzerClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\AccessAnalyzer\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **Access Analyzer** service.
*/
class AccessAnalyzerException extends AwsException {}
+36
View File
@@ -0,0 +1,36 @@
<?php
namespace Aws\Acm;
use Aws\AwsClient;
/**
* This client is used to interact with the **AWS Certificate Manager** service.
*
* @method \Aws\Result addTagsToCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise addTagsToCertificateAsync(array $args = [])
* @method \Aws\Result deleteCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteCertificateAsync(array $args = [])
* @method \Aws\Result describeCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise describeCertificateAsync(array $args = [])
* @method \Aws\Result exportCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise exportCertificateAsync(array $args = [])
* @method \Aws\Result getCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getCertificateAsync(array $args = [])
* @method \Aws\Result importCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise importCertificateAsync(array $args = [])
* @method \Aws\Result listCertificates(array $args = [])
* @method \GuzzleHttp\Promise\Promise listCertificatesAsync(array $args = [])
* @method \Aws\Result listTagsForCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsForCertificateAsync(array $args = [])
* @method \Aws\Result removeTagsFromCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise removeTagsFromCertificateAsync(array $args = [])
* @method \Aws\Result renewCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise renewCertificateAsync(array $args = [])
* @method \Aws\Result requestCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise requestCertificateAsync(array $args = [])
* @method \Aws\Result resendValidationEmail(array $args = [])
* @method \GuzzleHttp\Promise\Promise resendValidationEmailAsync(array $args = [])
* @method \Aws\Result updateCertificateOptions(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateCertificateOptionsAsync(array $args = [])
*/
class AcmClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\Acm\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AWS Certificate Manager** service.
*/
class AcmException extends AwsException {}
@@ -0,0 +1,195 @@
<?php
namespace Aws\AlexaForBusiness;
use Aws\AwsClient;
/**
* This client is used to interact with the **Alexa For Business** service.
* @method \Aws\Result approveSkill(array $args = [])
* @method \GuzzleHttp\Promise\Promise approveSkillAsync(array $args = [])
* @method \Aws\Result associateContactWithAddressBook(array $args = [])
* @method \GuzzleHttp\Promise\Promise associateContactWithAddressBookAsync(array $args = [])
* @method \Aws\Result associateDeviceWithNetworkProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise associateDeviceWithNetworkProfileAsync(array $args = [])
* @method \Aws\Result associateDeviceWithRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise associateDeviceWithRoomAsync(array $args = [])
* @method \Aws\Result associateSkillGroupWithRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise associateSkillGroupWithRoomAsync(array $args = [])
* @method \Aws\Result associateSkillWithSkillGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise associateSkillWithSkillGroupAsync(array $args = [])
* @method \Aws\Result associateSkillWithUsers(array $args = [])
* @method \GuzzleHttp\Promise\Promise associateSkillWithUsersAsync(array $args = [])
* @method \Aws\Result createAddressBook(array $args = [])
* @method \GuzzleHttp\Promise\Promise createAddressBookAsync(array $args = [])
* @method \Aws\Result createBusinessReportSchedule(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBusinessReportScheduleAsync(array $args = [])
* @method \Aws\Result createConferenceProvider(array $args = [])
* @method \GuzzleHttp\Promise\Promise createConferenceProviderAsync(array $args = [])
* @method \Aws\Result createContact(array $args = [])
* @method \GuzzleHttp\Promise\Promise createContactAsync(array $args = [])
* @method \Aws\Result createGatewayGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise createGatewayGroupAsync(array $args = [])
* @method \Aws\Result createNetworkProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise createNetworkProfileAsync(array $args = [])
* @method \Aws\Result createProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise createProfileAsync(array $args = [])
* @method \Aws\Result createRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise createRoomAsync(array $args = [])
* @method \Aws\Result createSkillGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise createSkillGroupAsync(array $args = [])
* @method \Aws\Result createUser(array $args = [])
* @method \GuzzleHttp\Promise\Promise createUserAsync(array $args = [])
* @method \Aws\Result deleteAddressBook(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAddressBookAsync(array $args = [])
* @method \Aws\Result deleteBusinessReportSchedule(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBusinessReportScheduleAsync(array $args = [])
* @method \Aws\Result deleteConferenceProvider(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteConferenceProviderAsync(array $args = [])
* @method \Aws\Result deleteContact(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteContactAsync(array $args = [])
* @method \Aws\Result deleteDevice(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDeviceAsync(array $args = [])
* @method \Aws\Result deleteDeviceUsageData(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDeviceUsageDataAsync(array $args = [])
* @method \Aws\Result deleteGatewayGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteGatewayGroupAsync(array $args = [])
* @method \Aws\Result deleteNetworkProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteNetworkProfileAsync(array $args = [])
* @method \Aws\Result deleteProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteProfileAsync(array $args = [])
* @method \Aws\Result deleteRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRoomAsync(array $args = [])
* @method \Aws\Result deleteRoomSkillParameter(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRoomSkillParameterAsync(array $args = [])
* @method \Aws\Result deleteSkillAuthorization(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteSkillAuthorizationAsync(array $args = [])
* @method \Aws\Result deleteSkillGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteSkillGroupAsync(array $args = [])
* @method \Aws\Result deleteUser(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteUserAsync(array $args = [])
* @method \Aws\Result disassociateContactFromAddressBook(array $args = [])
* @method \GuzzleHttp\Promise\Promise disassociateContactFromAddressBookAsync(array $args = [])
* @method \Aws\Result disassociateDeviceFromRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise disassociateDeviceFromRoomAsync(array $args = [])
* @method \Aws\Result disassociateSkillFromSkillGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise disassociateSkillFromSkillGroupAsync(array $args = [])
* @method \Aws\Result disassociateSkillFromUsers(array $args = [])
* @method \GuzzleHttp\Promise\Promise disassociateSkillFromUsersAsync(array $args = [])
* @method \Aws\Result disassociateSkillGroupFromRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise disassociateSkillGroupFromRoomAsync(array $args = [])
* @method \Aws\Result forgetSmartHomeAppliances(array $args = [])
* @method \GuzzleHttp\Promise\Promise forgetSmartHomeAppliancesAsync(array $args = [])
* @method \Aws\Result getAddressBook(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAddressBookAsync(array $args = [])
* @method \Aws\Result getConferencePreference(array $args = [])
* @method \GuzzleHttp\Promise\Promise getConferencePreferenceAsync(array $args = [])
* @method \Aws\Result getConferenceProvider(array $args = [])
* @method \GuzzleHttp\Promise\Promise getConferenceProviderAsync(array $args = [])
* @method \Aws\Result getContact(array $args = [])
* @method \GuzzleHttp\Promise\Promise getContactAsync(array $args = [])
* @method \Aws\Result getDevice(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDeviceAsync(array $args = [])
* @method \Aws\Result getGateway(array $args = [])
* @method \GuzzleHttp\Promise\Promise getGatewayAsync(array $args = [])
* @method \Aws\Result getGatewayGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise getGatewayGroupAsync(array $args = [])
* @method \Aws\Result getInvitationConfiguration(array $args = [])
* @method \GuzzleHttp\Promise\Promise getInvitationConfigurationAsync(array $args = [])
* @method \Aws\Result getNetworkProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise getNetworkProfileAsync(array $args = [])
* @method \Aws\Result getProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise getProfileAsync(array $args = [])
* @method \Aws\Result getRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRoomAsync(array $args = [])
* @method \Aws\Result getRoomSkillParameter(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRoomSkillParameterAsync(array $args = [])
* @method \Aws\Result getSkillGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise getSkillGroupAsync(array $args = [])
* @method \Aws\Result listBusinessReportSchedules(array $args = [])
* @method \GuzzleHttp\Promise\Promise listBusinessReportSchedulesAsync(array $args = [])
* @method \Aws\Result listConferenceProviders(array $args = [])
* @method \GuzzleHttp\Promise\Promise listConferenceProvidersAsync(array $args = [])
* @method \Aws\Result listDeviceEvents(array $args = [])
* @method \GuzzleHttp\Promise\Promise listDeviceEventsAsync(array $args = [])
* @method \Aws\Result listGatewayGroups(array $args = [])
* @method \GuzzleHttp\Promise\Promise listGatewayGroupsAsync(array $args = [])
* @method \Aws\Result listGateways(array $args = [])
* @method \GuzzleHttp\Promise\Promise listGatewaysAsync(array $args = [])
* @method \Aws\Result listSkills(array $args = [])
* @method \GuzzleHttp\Promise\Promise listSkillsAsync(array $args = [])
* @method \Aws\Result listSkillsStoreCategories(array $args = [])
* @method \GuzzleHttp\Promise\Promise listSkillsStoreCategoriesAsync(array $args = [])
* @method \Aws\Result listSkillsStoreSkillsByCategory(array $args = [])
* @method \GuzzleHttp\Promise\Promise listSkillsStoreSkillsByCategoryAsync(array $args = [])
* @method \Aws\Result listSmartHomeAppliances(array $args = [])
* @method \GuzzleHttp\Promise\Promise listSmartHomeAppliancesAsync(array $args = [])
* @method \Aws\Result listTags(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
* @method \Aws\Result putConferencePreference(array $args = [])
* @method \GuzzleHttp\Promise\Promise putConferencePreferenceAsync(array $args = [])
* @method \Aws\Result putInvitationConfiguration(array $args = [])
* @method \GuzzleHttp\Promise\Promise putInvitationConfigurationAsync(array $args = [])
* @method \Aws\Result putRoomSkillParameter(array $args = [])
* @method \GuzzleHttp\Promise\Promise putRoomSkillParameterAsync(array $args = [])
* @method \Aws\Result putSkillAuthorization(array $args = [])
* @method \GuzzleHttp\Promise\Promise putSkillAuthorizationAsync(array $args = [])
* @method \Aws\Result registerAVSDevice(array $args = [])
* @method \GuzzleHttp\Promise\Promise registerAVSDeviceAsync(array $args = [])
* @method \Aws\Result rejectSkill(array $args = [])
* @method \GuzzleHttp\Promise\Promise rejectSkillAsync(array $args = [])
* @method \Aws\Result resolveRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise resolveRoomAsync(array $args = [])
* @method \Aws\Result revokeInvitation(array $args = [])
* @method \GuzzleHttp\Promise\Promise revokeInvitationAsync(array $args = [])
* @method \Aws\Result searchAddressBooks(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchAddressBooksAsync(array $args = [])
* @method \Aws\Result searchContacts(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchContactsAsync(array $args = [])
* @method \Aws\Result searchDevices(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchDevicesAsync(array $args = [])
* @method \Aws\Result searchNetworkProfiles(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchNetworkProfilesAsync(array $args = [])
* @method \Aws\Result searchProfiles(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchProfilesAsync(array $args = [])
* @method \Aws\Result searchRooms(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchRoomsAsync(array $args = [])
* @method \Aws\Result searchSkillGroups(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchSkillGroupsAsync(array $args = [])
* @method \Aws\Result searchUsers(array $args = [])
* @method \GuzzleHttp\Promise\Promise searchUsersAsync(array $args = [])
* @method \Aws\Result sendAnnouncement(array $args = [])
* @method \GuzzleHttp\Promise\Promise sendAnnouncementAsync(array $args = [])
* @method \Aws\Result sendInvitation(array $args = [])
* @method \GuzzleHttp\Promise\Promise sendInvitationAsync(array $args = [])
* @method \Aws\Result startDeviceSync(array $args = [])
* @method \GuzzleHttp\Promise\Promise startDeviceSyncAsync(array $args = [])
* @method \Aws\Result startSmartHomeApplianceDiscovery(array $args = [])
* @method \GuzzleHttp\Promise\Promise startSmartHomeApplianceDiscoveryAsync(array $args = [])
* @method \Aws\Result tagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
* @method \Aws\Result untagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
* @method \Aws\Result updateAddressBook(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateAddressBookAsync(array $args = [])
* @method \Aws\Result updateBusinessReportSchedule(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBusinessReportScheduleAsync(array $args = [])
* @method \Aws\Result updateConferenceProvider(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateConferenceProviderAsync(array $args = [])
* @method \Aws\Result updateContact(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateContactAsync(array $args = [])
* @method \Aws\Result updateDevice(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDeviceAsync(array $args = [])
* @method \Aws\Result updateGateway(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateGatewayAsync(array $args = [])
* @method \Aws\Result updateGatewayGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateGatewayGroupAsync(array $args = [])
* @method \Aws\Result updateNetworkProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateNetworkProfileAsync(array $args = [])
* @method \Aws\Result updateProfile(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateProfileAsync(array $args = [])
* @method \Aws\Result updateRoom(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateRoomAsync(array $args = [])
* @method \Aws\Result updateSkillGroup(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateSkillGroupAsync(array $args = [])
*/
class AlexaForBusinessClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\AlexaForBusiness\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **Alexa For Business** service.
*/
class AlexaForBusinessException extends AwsException {}
@@ -0,0 +1,83 @@
<?php
namespace Aws\Amplify;
use Aws\AwsClient;
/**
* This client is used to interact with the **AWS Amplify** service.
* @method \Aws\Result createApp(array $args = [])
* @method \GuzzleHttp\Promise\Promise createAppAsync(array $args = [])
* @method \Aws\Result createBackendEnvironment(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBackendEnvironmentAsync(array $args = [])
* @method \Aws\Result createBranch(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBranchAsync(array $args = [])
* @method \Aws\Result createDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDeploymentAsync(array $args = [])
* @method \Aws\Result createDomainAssociation(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDomainAssociationAsync(array $args = [])
* @method \Aws\Result createWebhook(array $args = [])
* @method \GuzzleHttp\Promise\Promise createWebhookAsync(array $args = [])
* @method \Aws\Result deleteApp(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAppAsync(array $args = [])
* @method \Aws\Result deleteBackendEnvironment(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBackendEnvironmentAsync(array $args = [])
* @method \Aws\Result deleteBranch(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBranchAsync(array $args = [])
* @method \Aws\Result deleteDomainAssociation(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDomainAssociationAsync(array $args = [])
* @method \Aws\Result deleteJob(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteJobAsync(array $args = [])
* @method \Aws\Result deleteWebhook(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteWebhookAsync(array $args = [])
* @method \Aws\Result generateAccessLogs(array $args = [])
* @method \GuzzleHttp\Promise\Promise generateAccessLogsAsync(array $args = [])
* @method \Aws\Result getApp(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAppAsync(array $args = [])
* @method \Aws\Result getArtifactUrl(array $args = [])
* @method \GuzzleHttp\Promise\Promise getArtifactUrlAsync(array $args = [])
* @method \Aws\Result getBackendEnvironment(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBackendEnvironmentAsync(array $args = [])
* @method \Aws\Result getBranch(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBranchAsync(array $args = [])
* @method \Aws\Result getDomainAssociation(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDomainAssociationAsync(array $args = [])
* @method \Aws\Result getJob(array $args = [])
* @method \GuzzleHttp\Promise\Promise getJobAsync(array $args = [])
* @method \Aws\Result getWebhook(array $args = [])
* @method \GuzzleHttp\Promise\Promise getWebhookAsync(array $args = [])
* @method \Aws\Result listApps(array $args = [])
* @method \GuzzleHttp\Promise\Promise listAppsAsync(array $args = [])
* @method \Aws\Result listArtifacts(array $args = [])
* @method \GuzzleHttp\Promise\Promise listArtifactsAsync(array $args = [])
* @method \Aws\Result listBackendEnvironments(array $args = [])
* @method \GuzzleHttp\Promise\Promise listBackendEnvironmentsAsync(array $args = [])
* @method \Aws\Result listBranches(array $args = [])
* @method \GuzzleHttp\Promise\Promise listBranchesAsync(array $args = [])
* @method \Aws\Result listDomainAssociations(array $args = [])
* @method \GuzzleHttp\Promise\Promise listDomainAssociationsAsync(array $args = [])
* @method \Aws\Result listJobs(array $args = [])
* @method \GuzzleHttp\Promise\Promise listJobsAsync(array $args = [])
* @method \Aws\Result listTagsForResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
* @method \Aws\Result listWebhooks(array $args = [])
* @method \GuzzleHttp\Promise\Promise listWebhooksAsync(array $args = [])
* @method \Aws\Result startDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise startDeploymentAsync(array $args = [])
* @method \Aws\Result startJob(array $args = [])
* @method \GuzzleHttp\Promise\Promise startJobAsync(array $args = [])
* @method \Aws\Result stopJob(array $args = [])
* @method \GuzzleHttp\Promise\Promise stopJobAsync(array $args = [])
* @method \Aws\Result tagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
* @method \Aws\Result untagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
* @method \Aws\Result updateApp(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateAppAsync(array $args = [])
* @method \Aws\Result updateBranch(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBranchAsync(array $args = [])
* @method \Aws\Result updateDomainAssociation(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDomainAssociationAsync(array $args = [])
* @method \Aws\Result updateWebhook(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateWebhookAsync(array $args = [])
*/
class AmplifyClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\Amplify\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AWS Amplify** service.
*/
class AmplifyException extends AwsException {}
@@ -0,0 +1,57 @@
<?php
namespace Aws\AmplifyBackend;
use Aws\AwsClient;
/**
* This client is used to interact with the **AmplifyBackend** service.
* @method \Aws\Result cloneBackend(array $args = [])
* @method \GuzzleHttp\Promise\Promise cloneBackendAsync(array $args = [])
* @method \Aws\Result createBackend(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBackendAsync(array $args = [])
* @method \Aws\Result createBackendAPI(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBackendAPIAsync(array $args = [])
* @method \Aws\Result createBackendAuth(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBackendAuthAsync(array $args = [])
* @method \Aws\Result createBackendConfig(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBackendConfigAsync(array $args = [])
* @method \Aws\Result createToken(array $args = [])
* @method \GuzzleHttp\Promise\Promise createTokenAsync(array $args = [])
* @method \Aws\Result deleteBackend(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBackendAsync(array $args = [])
* @method \Aws\Result deleteBackendAPI(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBackendAPIAsync(array $args = [])
* @method \Aws\Result deleteBackendAuth(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBackendAuthAsync(array $args = [])
* @method \Aws\Result deleteToken(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteTokenAsync(array $args = [])
* @method \Aws\Result generateBackendAPIModels(array $args = [])
* @method \GuzzleHttp\Promise\Promise generateBackendAPIModelsAsync(array $args = [])
* @method \Aws\Result getBackend(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBackendAsync(array $args = [])
* @method \Aws\Result getBackendAPI(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBackendAPIAsync(array $args = [])
* @method \Aws\Result getBackendAPIModels(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBackendAPIModelsAsync(array $args = [])
* @method \Aws\Result getBackendAuth(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBackendAuthAsync(array $args = [])
* @method \Aws\Result getBackendJob(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBackendJobAsync(array $args = [])
* @method \Aws\Result getToken(array $args = [])
* @method \GuzzleHttp\Promise\Promise getTokenAsync(array $args = [])
* @method \Aws\Result listBackendJobs(array $args = [])
* @method \GuzzleHttp\Promise\Promise listBackendJobsAsync(array $args = [])
* @method \Aws\Result removeAllBackends(array $args = [])
* @method \GuzzleHttp\Promise\Promise removeAllBackendsAsync(array $args = [])
* @method \Aws\Result removeBackendConfig(array $args = [])
* @method \GuzzleHttp\Promise\Promise removeBackendConfigAsync(array $args = [])
* @method \Aws\Result updateBackendAPI(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBackendAPIAsync(array $args = [])
* @method \Aws\Result updateBackendAuth(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBackendAuthAsync(array $args = [])
* @method \Aws\Result updateBackendConfig(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBackendConfigAsync(array $args = [])
* @method \Aws\Result updateBackendJob(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBackendJobAsync(array $args = [])
*/
class AmplifyBackendClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\AmplifyBackend\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AmplifyBackend** service.
*/
class AmplifyBackendException extends AwsException {}
@@ -0,0 +1,67 @@
<?php
namespace Aws\Api;
/**
* Base class that is used by most API shapes
*/
abstract class AbstractModel implements \ArrayAccess
{
/** @var array */
protected $definition;
/** @var ShapeMap */
protected $shapeMap;
/**
* @param array $definition Service description
* @param ShapeMap $shapeMap Shapemap used for creating shapes
*/
public function __construct(array $definition, ShapeMap $shapeMap)
{
$this->definition = $definition;
$this->shapeMap = $shapeMap;
}
public function toArray()
{
return $this->definition;
}
public function offsetGet($offset)
{
return isset($this->definition[$offset])
? $this->definition[$offset] : null;
}
public function offsetSet($offset, $value)
{
$this->definition[$offset] = $value;
}
public function offsetExists($offset)
{
return isset($this->definition[$offset]);
}
public function offsetUnset($offset)
{
unset($this->definition[$offset]);
}
protected function shapeAt($key)
{
if (!isset($this->definition[$key])) {
throw new \InvalidArgumentException('Expected shape definition at '
. $key);
}
return $this->shapeFor($this->definition[$key]);
}
protected function shapeFor(array $definition)
{
return isset($definition['shape'])
? $this->shapeMap->resolve($definition)
: Shape::create($definition, $this->shapeMap);
}
}
+244
View File
@@ -0,0 +1,244 @@
<?php
namespace Aws\Api;
use Aws\Exception\UnresolvedApiException;
/**
* API providers.
*
* An API provider is a function that accepts a type, service, and version and
* returns an array of API data on success or NULL if no API data can be created
* for the provided arguments.
*
* You can wrap your calls to an API provider with the
* {@see ApiProvider::resolve} method to ensure that API data is created. If the
* API data is not created, then the resolve() method will throw a
* {@see Aws\Exception\UnresolvedApiException}.
*
* use Aws\Api\ApiProvider;
* $provider = ApiProvider::defaultProvider();
* // Returns an array or NULL.
* $data = $provider('api', 's3', '2006-03-01');
* // Returns an array or throws.
* $data = ApiProvider::resolve($provider, 'api', 'elasticfood', '2020-01-01');
*
* You can compose multiple providers into a single provider using
* {@see Aws\or_chain}. This method accepts providers as arguments and
* returns a new function that will invoke each provider until a non-null value
* is returned.
*
* $a = ApiProvider::filesystem(sys_get_temp_dir() . '/aws-beta-models');
* $b = ApiProvider::manifest();
*
* $c = \Aws\or_chain($a, $b);
* $data = $c('api', 'betaservice', '2015-08-08'); // $a handles this.
* $data = $c('api', 's3', '2006-03-01'); // $b handles this.
* $data = $c('api', 'invalid', '2014-12-15'); // Neither handles this.
*/
class ApiProvider
{
/** @var array A map of public API type names to their file suffix. */
private static $typeMap = [
'api' => 'api-2',
'paginator' => 'paginators-1',
'waiter' => 'waiters-2',
'docs' => 'docs-2',
];
/** @var array API manifest */
private $manifest;
/** @var string The directory containing service models. */
private $modelsDir;
/**
* Resolves an API provider and ensures a non-null return value.
*
* @param callable $provider Provider function to invoke.
* @param string $type Type of data ('api', 'waiter', 'paginator').
* @param string $service Service name.
* @param string $version API version.
*
* @return array
* @throws UnresolvedApiException
*/
public static function resolve(callable $provider, $type, $service, $version)
{
// Execute the provider and return the result, if there is one.
$result = $provider($type, $service, $version);
if (is_array($result)) {
if (!isset($result['metadata']['serviceIdentifier'])) {
$result['metadata']['serviceIdentifier'] = $service;
}
return $result;
}
// Throw an exception with a message depending on the inputs.
if (!isset(self::$typeMap[$type])) {
$msg = "The type must be one of: " . implode(', ', self::$typeMap);
} elseif ($service) {
$msg = "The {$service} service does not have version: {$version}.";
} else {
$msg = "You must specify a service name to retrieve its API data.";
}
throw new UnresolvedApiException($msg);
}
/**
* Default SDK API provider.
*
* This provider loads pre-built manifest data from the `data` directory.
*
* @return self
*/
public static function defaultProvider()
{
return new self(__DIR__ . '/../data', \Aws\manifest());
}
/**
* Loads API data after resolving the version to the latest, compatible,
* available version based on the provided manifest data.
*
* Manifest data is essentially an associative array of service names to
* associative arrays of API version aliases.
*
* [
* ...
* 'ec2' => [
* 'latest' => '2014-10-01',
* '2014-10-01' => '2014-10-01',
* '2014-09-01' => '2014-10-01',
* '2014-06-15' => '2014-10-01',
* ...
* ],
* 'ecs' => [...],
* 'elasticache' => [...],
* ...
* ]
*
* @param string $dir Directory containing service models.
* @param array $manifest The API version manifest data.
*
* @return self
*/
public static function manifest($dir, array $manifest)
{
return new self($dir, $manifest);
}
/**
* Loads API data from the specified directory.
*
* If "latest" is specified as the version, this provider must glob the
* directory to find which is the latest available version.
*
* @param string $dir Directory containing service models.
*
* @return self
* @throws \InvalidArgumentException if the provided `$dir` is invalid.
*/
public static function filesystem($dir)
{
return new self($dir);
}
/**
* Retrieves a list of valid versions for the specified service.
*
* @param string $service Service name
*
* @return array
*/
public function getVersions($service)
{
if (!isset($this->manifest)) {
$this->buildVersionsList($service);
}
if (!isset($this->manifest[$service]['versions'])) {
return [];
}
return array_values(array_unique($this->manifest[$service]['versions']));
}
/**
* Execute the provider.
*
* @param string $type Type of data ('api', 'waiter', 'paginator').
* @param string $service Service name.
* @param string $version API version.
*
* @return array|null
*/
public function __invoke($type, $service, $version)
{
// Resolve the type or return null.
if (isset(self::$typeMap[$type])) {
$type = self::$typeMap[$type];
} else {
return null;
}
// Resolve the version or return null.
if (!isset($this->manifest)) {
$this->buildVersionsList($service);
}
if (!isset($this->manifest[$service]['versions'][$version])) {
return null;
}
$version = $this->manifest[$service]['versions'][$version];
$path = "{$this->modelsDir}/{$service}/{$version}/{$type}.json";
try {
return \Aws\load_compiled_json($path);
} catch (\InvalidArgumentException $e) {
return null;
}
}
/**
* @param string $modelsDir Directory containing service models.
* @param array $manifest The API version manifest data.
*/
private function __construct($modelsDir, array $manifest = null)
{
$this->manifest = $manifest;
$this->modelsDir = rtrim($modelsDir, '/');
if (!is_dir($this->modelsDir)) {
throw new \InvalidArgumentException(
"The specified models directory, {$modelsDir}, was not found."
);
}
}
/**
* Build the versions list for the specified service by globbing the dir.
*/
private function buildVersionsList($service)
{
$dir = "{$this->modelsDir}/{$service}/";
if (!is_dir($dir)) {
return;
}
// Get versions, remove . and .., and sort in descending order.
$results = array_diff(scandir($dir, SCANDIR_SORT_DESCENDING), ['..', '.']);
if (!$results) {
$this->manifest[$service] = ['versions' => []];
} else {
$this->manifest[$service] = [
'versions' => [
'latest' => $results[0]
]
];
$this->manifest[$service]['versions'] += array_combine($results, $results);
}
}
}
@@ -0,0 +1,102 @@
<?php
namespace Aws\Api;
use Aws\Api\Parser\Exception\ParserException;
use Exception;
/**
* DateTime overrides that make DateTime work more seamlessly as a string,
* with JSON documents, and with JMESPath.
*/
class DateTimeResult extends \DateTime implements \JsonSerializable
{
/**
* Create a new DateTimeResult from a unix timestamp.
* The Unix epoch (or Unix time or POSIX time or Unix
* timestamp) is the number of seconds that have elapsed since
* January 1, 1970 (midnight UTC/GMT).
* @param $unixTimestamp
*
* @return DateTimeResult
* @throws Exception
*/
public static function fromEpoch($unixTimestamp)
{
return new self(gmdate('c', $unixTimestamp));
}
/**
* @param $iso8601Timestamp
*
* @return DateTimeResult
*/
public static function fromISO8601($iso8601Timestamp)
{
if (is_numeric($iso8601Timestamp) || !is_string($iso8601Timestamp)) {
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromISO8601');
}
return new DateTimeResult($iso8601Timestamp);
}
/**
* Create a new DateTimeResult from an unknown timestamp.
*
* @param $timestamp
*
* @return DateTimeResult
* @throws ParserException|Exception
*/
public static function fromTimestamp($timestamp, $expectedFormat = null)
{
if (empty($timestamp)) {
return self::fromEpoch(0);
}
if (!(is_string($timestamp) || is_numeric($timestamp))) {
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromTimestamp');
}
try {
if ($expectedFormat == 'iso8601') {
try {
return self::fromISO8601($timestamp);
} catch (Exception $exception) {
return self::fromEpoch($timestamp);
}
} else if ($expectedFormat == 'unixTimestamp') {
try {
return self::fromEpoch($timestamp);
} catch (Exception $exception) {
return self::fromISO8601($timestamp);
}
} else if (\Aws\is_valid_epoch($timestamp)) {
return self::fromEpoch($timestamp);
}
return self::fromISO8601($timestamp);
} catch (Exception $exception) {
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromTimestamp');
}
}
/**
* Serialize the DateTimeResult as an ISO 8601 date string.
*
* @return string
*/
public function __toString()
{
return $this->format('c');
}
/**
* Serialize the date as an ISO 8601 date when serializing as JSON.
*
* @return mixed|string
*/
public function jsonSerialize()
{
return (string) $this;
}
}
+128
View File
@@ -0,0 +1,128 @@
<?php
namespace Aws\Api;
/**
* Encapsulates the documentation strings for a given service-version and
* provides methods for extracting the desired parts related to a service,
* operation, error, or shape (i.e., parameter).
*/
class DocModel
{
/** @var array */
private $docs;
/**
* @param array $docs
*
* @throws \RuntimeException
*/
public function __construct(array $docs)
{
if (!extension_loaded('tidy')) {
throw new \RuntimeException('The "tidy" PHP extension is required.');
}
$this->docs = $docs;
}
/**
* Convert the doc model to an array.
*
* @return array
*/
public function toArray()
{
return $this->docs;
}
/**
* Retrieves documentation about the service.
*
* @return null|string
*/
public function getServiceDocs()
{
return isset($this->docs['service']) ? $this->docs['service'] : null;
}
/**
* Retrieves documentation about an operation.
*
* @param string $operation Name of the operation
*
* @return null|string
*/
public function getOperationDocs($operation)
{
return isset($this->docs['operations'][$operation])
? $this->docs['operations'][$operation]
: null;
}
/**
* Retrieves documentation about an error.
*
* @param string $error Name of the error
*
* @return null|string
*/
public function getErrorDocs($error)
{
return isset($this->docs['shapes'][$error]['base'])
? $this->docs['shapes'][$error]['base']
: null;
}
/**
* Retrieves documentation about a shape, specific to the context.
*
* @param string $shapeName Name of the shape.
* @param string $parentName Name of the parent/context shape.
* @param string $ref Name used by the context to reference the shape.
*
* @return null|string
*/
public function getShapeDocs($shapeName, $parentName, $ref)
{
if (!isset($this->docs['shapes'][$shapeName])) {
return '';
}
$result = '';
$d = $this->docs['shapes'][$shapeName];
if (isset($d['refs']["{$parentName}\$${ref}"])) {
$result = $d['refs']["{$parentName}\$${ref}"];
} elseif (isset($d['base'])) {
$result = $d['base'];
}
if (isset($d['append'])) {
$result .= $d['append'];
}
return $this->clean($result);
}
private function clean($content)
{
if (!$content) {
return '';
}
$tidy = new \tidy();
$tidy->parseString($content, [
'indent' => true,
'doctype' => 'omit',
'output-html' => true,
'show-body-only' => true,
'drop-empty-paras' => true,
'drop-font-tags' => true,
'drop-proprietary-attributes' => true,
'hide-comments' => true,
'logical-emphasis' => true
]);
$tidy->cleanRepair();
return (string) $content;
}
}
@@ -0,0 +1,95 @@
<?php
namespace Aws\Api\ErrorParser;
use Aws\Api\Parser\MetadataParserTrait;
use Aws\Api\Parser\PayloadParserTrait;
use Aws\Api\Service;
use Aws\Api\StructureShape;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
abstract class AbstractErrorParser
{
use MetadataParserTrait;
use PayloadParserTrait;
/**
* @var Service
*/
protected $api;
/**
* @param Service $api
*/
public function __construct(Service $api = null)
{
$this->api = $api;
}
abstract protected function payload(
ResponseInterface $response,
StructureShape $member
);
protected function extractPayload(
StructureShape $member,
ResponseInterface $response
) {
if ($member instanceof StructureShape) {
// Structure members parse top-level data into a specific key.
return $this->payload($response, $member);
} else {
// Streaming data is just the stream from the response body.
return $response->getBody();
}
}
protected function populateShape(
array &$data,
ResponseInterface $response,
CommandInterface $command = null
) {
$data['body'] = [];
if (!empty($command) && !empty($this->api)) {
// If modeled error code is indicated, check for known error shape
if (!empty($data['code'])) {
$errors = $this->api->getOperation($command->getName())->getErrors();
foreach ($errors as $key => $error) {
// If error code matches a known error shape, populate the body
if ($data['code'] == $error['name']
&& $error instanceof StructureShape
) {
$modeledError = $error;
$data['body'] = $this->extractPayload(
$modeledError,
$response
);
$data['error_shape'] = $modeledError;
foreach ($error->getMembers() as $name => $member) {
switch ($member['location']) {
case 'header':
$this->extractHeader($name, $member, $response, $data['body']);
break;
case 'headers':
$this->extractHeaders($name, $member, $response, $data['body']);
break;
case 'statusCode':
$this->extractStatus($name, $response, $data['body']);
break;
}
}
break;
}
}
}
}
return $data;
}
}
@@ -0,0 +1,38 @@
<?php
namespace Aws\Api\ErrorParser;
use Aws\Api\Parser\PayloadParserTrait;
use Aws\Api\StructureShape;
use Psr\Http\Message\ResponseInterface;
/**
* Provides basic JSON error parsing functionality.
*/
trait JsonParserTrait
{
use PayloadParserTrait;
private function genericHandler(ResponseInterface $response)
{
$code = (string) $response->getStatusCode();
return [
'request_id' => (string) $response->getHeaderLine('x-amzn-requestid'),
'code' => null,
'message' => null,
'type' => $code[0] == '4' ? 'client' : 'server',
'parsed' => $this->parseJson($response->getBody(), $response)
];
}
protected function payload(
ResponseInterface $response,
StructureShape $member
) {
$jsonBody = $this->parseJson($response->getBody(), $response);
if ($jsonBody) {
return $this->parser->parse($member, $jsonBody);
}
}
}
@@ -0,0 +1,47 @@
<?php
namespace Aws\Api\ErrorParser;
use Aws\Api\Parser\JsonParser;
use Aws\Api\Service;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Parsers JSON-RPC errors.
*/
class JsonRpcErrorParser extends AbstractErrorParser
{
use JsonParserTrait;
private $parser;
public function __construct(Service $api = null, JsonParser $parser = null)
{
parent::__construct($api);
$this->parser = $parser ?: new JsonParser();
}
public function __invoke(
ResponseInterface $response,
CommandInterface $command = null
) {
$data = $this->genericHandler($response);
// Make the casing consistent across services.
if ($data['parsed']) {
$data['parsed'] = array_change_key_case($data['parsed']);
}
if (isset($data['parsed']['__type'])) {
$parts = explode('#', $data['parsed']['__type']);
$data['code'] = isset($parts[1]) ? $parts[1] : $parts[0];
$data['message'] = isset($data['parsed']['message'])
? $data['parsed']['message']
: null;
}
$this->populateShape($data, $response, $command);
return $data;
}
}
@@ -0,0 +1,58 @@
<?php
namespace Aws\Api\ErrorParser;
use Aws\Api\Parser\JsonParser;
use Aws\Api\Service;
use Aws\Api\StructureShape;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Parses JSON-REST errors.
*/
class RestJsonErrorParser extends AbstractErrorParser
{
use JsonParserTrait;
private $parser;
public function __construct(Service $api = null, JsonParser $parser = null)
{
parent::__construct($api);
$this->parser = $parser ?: new JsonParser();
}
public function __invoke(
ResponseInterface $response,
CommandInterface $command = null
) {
$data = $this->genericHandler($response);
// Merge in error data from the JSON body
if ($json = $data['parsed']) {
$data = array_replace($data, $json);
}
// Correct error type from services like Amazon Glacier
if (!empty($data['type'])) {
$data['type'] = strtolower($data['type']);
}
// Retrieve the error code from services like Amazon Elastic Transcoder
if ($code = $response->getHeaderLine('x-amzn-errortype')) {
$colon = strpos($code, ':');
$data['code'] = $colon ? substr($code, 0, $colon) : $code;
}
// Retrieve error message directly
$data['message'] = isset($data['parsed']['message'])
? $data['parsed']['message']
: (isset($data['parsed']['Message'])
? $data['parsed']['Message']
: null);
$this->populateShape($data, $response, $command);
return $data;
}
}
@@ -0,0 +1,111 @@
<?php
namespace Aws\Api\ErrorParser;
use Aws\Api\Parser\PayloadParserTrait;
use Aws\Api\Parser\XmlParser;
use Aws\Api\Service;
use Aws\Api\StructureShape;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Parses XML errors.
*/
class XmlErrorParser extends AbstractErrorParser
{
use PayloadParserTrait;
protected $parser;
public function __construct(Service $api = null, XmlParser $parser = null)
{
parent::__construct($api);
$this->parser = $parser ?: new XmlParser();
}
public function __invoke(
ResponseInterface $response,
CommandInterface $command = null
) {
$code = (string) $response->getStatusCode();
$data = [
'type' => $code[0] == '4' ? 'client' : 'server',
'request_id' => null,
'code' => null,
'message' => null,
'parsed' => null
];
$body = $response->getBody();
if ($body->getSize() > 0) {
$this->parseBody($this->parseXml($body, $response), $data);
} else {
$this->parseHeaders($response, $data);
}
$this->populateShape($data, $response, $command);
return $data;
}
private function parseHeaders(ResponseInterface $response, array &$data)
{
if ($response->getStatusCode() == '404') {
$data['code'] = 'NotFound';
}
$data['message'] = $response->getStatusCode() . ' '
. $response->getReasonPhrase();
if ($requestId = $response->getHeaderLine('x-amz-request-id')) {
$data['request_id'] = $requestId;
$data['message'] .= " (Request-ID: $requestId)";
}
}
private function parseBody(\SimpleXMLElement $body, array &$data)
{
$data['parsed'] = $body;
$prefix = $this->registerNamespacePrefix($body);
if ($tempXml = $body->xpath("//{$prefix}Code[1]")) {
$data['code'] = (string) $tempXml[0];
}
if ($tempXml = $body->xpath("//{$prefix}Message[1]")) {
$data['message'] = (string) $tempXml[0];
}
$tempXml = $body->xpath("//{$prefix}RequestId[1]");
if (isset($tempXml[0])) {
$data['request_id'] = (string)$tempXml[0];
}
}
protected function registerNamespacePrefix(\SimpleXMLElement $element)
{
$namespaces = $element->getDocNamespaces();
if (!isset($namespaces[''])) {
return '';
}
// Account for the default namespace being defined and PHP not
// being able to handle it :(.
$element->registerXPathNamespace('ns', $namespaces['']);
return 'ns:';
}
protected function payload(
ResponseInterface $response,
StructureShape $member
) {
$xmlBody = $this->parseXml($response->getBody(), $response);
$prefix = $this->registerNamespacePrefix($xmlBody);
$errorBody = $xmlBody->xpath("//{$prefix}Error");
if (is_array($errorBody) && !empty($errorBody[0])) {
return $this->parser->parse($member, $errorBody[0]);
}
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace Aws\Api;
/**
* Represents a list shape.
*/
class ListShape extends Shape
{
private $member;
public function __construct(array $definition, ShapeMap $shapeMap)
{
$definition['type'] = 'list';
parent::__construct($definition, $shapeMap);
}
/**
* @return Shape
* @throws \RuntimeException if no member is specified
*/
public function getMember()
{
if (!$this->member) {
if (!isset($this->definition['member'])) {
throw new \RuntimeException('No member attribute specified');
}
$this->member = Shape::create(
$this->definition['member'],
$this->shapeMap
);
}
return $this->member;
}
}
+54
View File
@@ -0,0 +1,54 @@
<?php
namespace Aws\Api;
/**
* Represents a map shape.
*/
class MapShape extends Shape
{
/** @var Shape */
private $value;
/** @var Shape */
private $key;
public function __construct(array $definition, ShapeMap $shapeMap)
{
$definition['type'] = 'map';
parent::__construct($definition, $shapeMap);
}
/**
* @return Shape
* @throws \RuntimeException if no value is specified
*/
public function getValue()
{
if (!$this->value) {
if (!isset($this->definition['value'])) {
throw new \RuntimeException('No value specified');
}
$this->value = Shape::create(
$this->definition['value'],
$this->shapeMap
);
}
return $this->value;
}
/**
* @return Shape
*/
public function getKey()
{
if (!$this->key) {
$this->key = isset($this->definition['key'])
? Shape::create($this->definition['key'], $this->shapeMap)
: new Shape(['type' => 'string'], $this->shapeMap);
}
return $this->key;
}
}
+97
View File
@@ -0,0 +1,97 @@
<?php
namespace Aws\Api;
/**
* Represents an API operation.
*/
class Operation extends AbstractModel
{
private $input;
private $output;
private $errors;
public function __construct(array $definition, ShapeMap $shapeMap)
{
$definition['type'] = 'structure';
if (!isset($definition['http']['method'])) {
$definition['http']['method'] = 'POST';
}
if (!isset($definition['http']['requestUri'])) {
$definition['http']['requestUri'] = '/';
}
parent::__construct($definition, $shapeMap);
}
/**
* Returns an associative array of the HTTP attribute of the operation:
*
* - method: HTTP method of the operation
* - requestUri: URI of the request (can include URI template placeholders)
*
* @return array
*/
public function getHttp()
{
return $this->definition['http'];
}
/**
* Get the input shape of the operation.
*
* @return StructureShape
*/
public function getInput()
{
if (!$this->input) {
if ($input = $this['input']) {
$this->input = $this->shapeFor($input);
} else {
$this->input = new StructureShape([], $this->shapeMap);
}
}
return $this->input;
}
/**
* Get the output shape of the operation.
*
* @return StructureShape
*/
public function getOutput()
{
if (!$this->output) {
if ($output = $this['output']) {
$this->output = $this->shapeFor($output);
} else {
$this->output = new StructureShape([], $this->shapeMap);
}
}
return $this->output;
}
/**
* Get an array of operation error shapes.
*
* @return Shape[]
*/
public function getErrors()
{
if ($this->errors === null) {
if ($errors = $this['errors']) {
foreach ($errors as $key => $error) {
$errors[$key] = $this->shapeFor($error);
}
$this->errors = $errors;
} else {
$this->errors = [];
}
}
return $this->errors;
}
}
@@ -0,0 +1,46 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\Service;
use Aws\Api\StructureShape;
use Aws\CommandInterface;
use Aws\ResultInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* @internal
*/
abstract class AbstractParser
{
/** @var \Aws\Api\Service Representation of the service API*/
protected $api;
/** @var callable */
protected $parser;
/**
* @param Service $api Service description.
*/
public function __construct(Service $api)
{
$this->api = $api;
}
/**
* @param CommandInterface $command Command that was executed.
* @param ResponseInterface $response Response that was received.
*
* @return ResultInterface
*/
abstract public function __invoke(
CommandInterface $command,
ResponseInterface $response
);
abstract public function parseMemberFromStream(
StreamInterface $stream,
StructureShape $member,
$response
);
}
@@ -0,0 +1,184 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\DateTimeResult;
use Aws\Api\Shape;
use Aws\Api\StructureShape;
use Aws\Result;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
/**
* @internal
*/
abstract class AbstractRestParser extends AbstractParser
{
use PayloadParserTrait;
/**
* Parses a payload from a response.
*
* @param ResponseInterface $response Response to parse.
* @param StructureShape $member Member to parse
* @param array $result Result value
*
* @return mixed
*/
abstract protected function payload(
ResponseInterface $response,
StructureShape $member,
array &$result
);
public function __invoke(
CommandInterface $command,
ResponseInterface $response
) {
$output = $this->api->getOperation($command->getName())->getOutput();
$result = [];
if ($payload = $output['payload']) {
$this->extractPayload($payload, $output, $response, $result);
}
foreach ($output->getMembers() as $name => $member) {
switch ($member['location']) {
case 'header':
$this->extractHeader($name, $member, $response, $result);
break;
case 'headers':
$this->extractHeaders($name, $member, $response, $result);
break;
case 'statusCode':
$this->extractStatus($name, $response, $result);
break;
}
}
if (!$payload
&& $response->getBody()->getSize() > 0
&& count($output->getMembers()) > 0
) {
// if no payload was found, then parse the contents of the body
$this->payload($response, $output, $result);
}
return new Result($result);
}
private function extractPayload(
$payload,
StructureShape $output,
ResponseInterface $response,
array &$result
) {
$member = $output->getMember($payload);
if (!empty($member['eventstream'])) {
$result[$payload] = new EventParsingIterator(
$response->getBody(),
$member,
$this
);
} else if ($member instanceof StructureShape) {
// Structure members parse top-level data into a specific key.
$result[$payload] = [];
$this->payload($response, $member, $result[$payload]);
} else {
// Streaming data is just the stream from the response body.
$result[$payload] = $response->getBody();
}
}
/**
* Extract a single header from the response into the result.
*/
private function extractHeader(
$name,
Shape $shape,
ResponseInterface $response,
&$result
) {
$value = $response->getHeaderLine($shape['locationName'] ?: $name);
switch ($shape->getType()) {
case 'float':
case 'double':
$value = (float) $value;
break;
case 'long':
$value = (int) $value;
break;
case 'boolean':
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
break;
case 'blob':
$value = base64_decode($value);
break;
case 'timestamp':
try {
$value = DateTimeResult::fromTimestamp(
$value,
!empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null
);
break;
} catch (\Exception $e) {
// If the value cannot be parsed, then do not add it to the
// output structure.
return;
}
case 'string':
try {
if ($shape['jsonvalue']) {
$value = $this->parseJson(base64_decode($value), $response);
}
// If value is not set, do not add to output structure.
if (!isset($value)) {
return;
}
break;
} catch (\Exception $e) {
//If the value cannot be parsed, then do not add it to the
//output structure.
return;
}
}
$result[$name] = $value;
}
/**
* Extract a map of headers with an optional prefix from the response.
*/
private function extractHeaders(
$name,
Shape $shape,
ResponseInterface $response,
&$result
) {
// Check if the headers are prefixed by a location name
$result[$name] = [];
$prefix = $shape['locationName'];
$prefixLen = strlen($prefix);
foreach ($response->getHeaders() as $k => $values) {
if (!$prefixLen) {
$result[$name][$k] = implode(', ', $values);
} elseif (stripos($k, $prefix) === 0) {
$result[$name][substr($k, $prefixLen)] = implode(', ', $values);
}
}
}
/**
* Places the status code of the response into the result array.
*/
private function extractStatus(
$name,
ResponseInterface $response,
array &$result
) {
$result[$name] = (int) $response->getStatusCode();
}
}
@@ -0,0 +1,54 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\StructureShape;
use Aws\CommandInterface;
use Aws\Exception\AwsException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use GuzzleHttp\Psr7;
/**
* @internal Decorates a parser and validates the x-amz-crc32 header.
*/
class Crc32ValidatingParser extends AbstractParser
{
/**
* @param callable $parser Parser to wrap.
*/
public function __construct(callable $parser)
{
$this->parser = $parser;
}
public function __invoke(
CommandInterface $command,
ResponseInterface $response
) {
if ($expected = $response->getHeaderLine('x-amz-crc32')) {
$hash = hexdec(Psr7\hash($response->getBody(), 'crc32b'));
if ($expected != $hash) {
throw new AwsException(
"crc32 mismatch. Expected {$expected}, found {$hash}.",
$command,
[
'code' => 'ClientChecksumMismatch',
'connection_error' => true,
'response' => $response
]
);
}
}
$fn = $this->parser;
return $fn($command, $response);
}
public function parseMemberFromStream(
StreamInterface $stream,
StructureShape $member,
$response
) {
return $this->parser->parseMemberFromStream($stream, $member, $response);
}
}
@@ -0,0 +1,335 @@
<?php
namespace Aws\Api\Parser;
use \Iterator;
use Aws\Api\DateTimeResult;
use GuzzleHttp\Psr7;
use Psr\Http\Message\StreamInterface;
use Aws\Api\Parser\Exception\ParserException;
/**
* @internal Implements a decoder for a binary encoded event stream that will
* decode, validate, and provide individual events from the stream.
*/
class DecodingEventStreamIterator implements Iterator
{
const HEADERS = 'headers';
const PAYLOAD = 'payload';
const LENGTH_TOTAL = 'total_length';
const LENGTH_HEADERS = 'headers_length';
const CRC_PRELUDE = 'prelude_crc';
const BYTES_PRELUDE = 12;
const BYTES_TRAILING = 4;
private static $preludeFormat = [
self::LENGTH_TOTAL => 'decodeUint32',
self::LENGTH_HEADERS => 'decodeUint32',
self::CRC_PRELUDE => 'decodeUint32',
];
private static $lengthFormatMap = [
1 => 'decodeUint8',
2 => 'decodeUint16',
4 => 'decodeUint32',
8 => 'decodeUint64',
];
private static $headerTypeMap = [
0 => 'decodeBooleanTrue',
1 => 'decodeBooleanFalse',
2 => 'decodeInt8',
3 => 'decodeInt16',
4 => 'decodeInt32',
5 => 'decodeInt64',
6 => 'decodeBytes',
7 => 'decodeString',
8 => 'decodeTimestamp',
9 => 'decodeUuid',
];
/** @var StreamInterface Stream of eventstream shape to parse. */
private $stream;
/** @var array Currently parsed event. */
private $currentEvent;
/** @var int Current in-order event key. */
private $key;
/** @var resource|\HashContext CRC32 hash context for event validation */
private $hashContext;
/** @var int $currentPosition */
private $currentPosition;
/**
* DecodingEventStreamIterator constructor.
*
* @param StreamInterface $stream
*/
public function __construct(StreamInterface $stream)
{
$this->stream = $stream;
$this->rewind();
}
private function parseHeaders($headerBytes)
{
$headers = [];
$bytesRead = 0;
while ($bytesRead < $headerBytes) {
list($key, $numBytes) = $this->decodeString(1);
$bytesRead += $numBytes;
list($type, $numBytes) = $this->decodeUint8();
$bytesRead += $numBytes;
$f = self::$headerTypeMap[$type];
list($value, $numBytes) = $this->{$f}();
$bytesRead += $numBytes;
if (isset($headers[$key])) {
throw new ParserException('Duplicate key in event headers.');
}
$headers[$key] = $value;
}
return [$headers, $bytesRead];
}
private function parsePrelude()
{
$prelude = [];
$bytesRead = 0;
$calculatedCrc = null;
foreach (self::$preludeFormat as $key => $decodeFunction) {
if ($key === self::CRC_PRELUDE) {
$hashCopy = hash_copy($this->hashContext);
$calculatedCrc = hash_final($this->hashContext, true);
$this->hashContext = $hashCopy;
}
list($value, $numBytes) = $this->{$decodeFunction}();
$bytesRead += $numBytes;
$prelude[$key] = $value;
}
if (unpack('N', $calculatedCrc)[1] !== $prelude[self::CRC_PRELUDE]) {
throw new ParserException('Prelude checksum mismatch.');
}
return [$prelude, $bytesRead];
}
private function parseEvent()
{
$event = [];
if ($this->stream->tell() < $this->stream->getSize()) {
$this->hashContext = hash_init('crc32b');
$bytesLeft = $this->stream->getSize() - $this->stream->tell();
list($prelude, $numBytes) = $this->parsePrelude();
if ($prelude[self::LENGTH_TOTAL] > $bytesLeft) {
throw new ParserException('Message length too long.');
}
$bytesLeft -= $numBytes;
if ($prelude[self::LENGTH_HEADERS] > $bytesLeft) {
throw new ParserException('Headers length too long.');
}
list(
$event[self::HEADERS],
$numBytes
) = $this->parseHeaders($prelude[self::LENGTH_HEADERS]);
$event[self::PAYLOAD] = Psr7\stream_for(
$this->readAndHashBytes(
$prelude[self::LENGTH_TOTAL] - self::BYTES_PRELUDE
- $numBytes - self::BYTES_TRAILING
)
);
$calculatedCrc = hash_final($this->hashContext, true);
$messageCrc = $this->stream->read(4);
if ($calculatedCrc !== $messageCrc) {
throw new ParserException('Message checksum mismatch.');
}
}
return $event;
}
// Iterator Functionality
/**
* @return array
*/
public function current()
{
return $this->currentEvent;
}
/**
* @return int
*/
public function key()
{
return $this->key;
}
public function next()
{
$this->currentPosition = $this->stream->tell();
if ($this->valid()) {
$this->key++;
$this->currentEvent = $this->parseEvent();
}
}
public function rewind()
{
$this->stream->rewind();
$this->key = 0;
$this->currentPosition = 0;
$this->currentEvent = $this->parseEvent();
}
/**
* @return bool
*/
public function valid()
{
return $this->currentPosition < $this->stream->getSize();
}
// Decoding Utilities
private function readAndHashBytes($num)
{
$bytes = $this->stream->read($num);
hash_update($this->hashContext, $bytes);
return $bytes;
}
private function decodeBooleanTrue()
{
return [true, 0];
}
private function decodeBooleanFalse()
{
return [false, 0];
}
private function uintToInt($val, $size)
{
$signedCap = pow(2, $size - 1);
if ($val > $signedCap) {
$val -= (2 * $signedCap);
}
return $val;
}
private function decodeInt8()
{
$val = (int)unpack('C', $this->readAndHashBytes(1))[1];
return [$this->uintToInt($val, 8), 1];
}
private function decodeUint8()
{
return [unpack('C', $this->readAndHashBytes(1))[1], 1];
}
private function decodeInt16()
{
$val = (int)unpack('n', $this->readAndHashBytes(2))[1];
return [$this->uintToInt($val, 16), 2];
}
private function decodeUint16()
{
return [unpack('n', $this->readAndHashBytes(2))[1], 2];
}
private function decodeInt32()
{
$val = (int)unpack('N', $this->readAndHashBytes(4))[1];
return [$this->uintToInt($val, 32), 4];
}
private function decodeUint32()
{
return [unpack('N', $this->readAndHashBytes(4))[1], 4];
}
private function decodeInt64()
{
$val = $this->unpackInt64($this->readAndHashBytes(8))[1];
return [$this->uintToInt($val, 64), 8];
}
private function decodeUint64()
{
return [$this->unpackInt64($this->readAndHashBytes(8))[1], 8];
}
private function unpackInt64($bytes)
{
if (version_compare(PHP_VERSION, '5.6.3', '<')) {
$d = unpack('N2', $bytes);
return [1 => $d[1] << 32 | $d[2]];
}
return unpack('J', $bytes);
}
private function decodeBytes($lengthBytes=2)
{
if (!isset(self::$lengthFormatMap[$lengthBytes])) {
throw new ParserException('Undefined variable length format.');
}
$f = self::$lengthFormatMap[$lengthBytes];
list($len, $bytes) = $this->{$f}();
return [$this->readAndHashBytes($len), $len + $bytes];
}
private function decodeString($lengthBytes=2)
{
if (!isset(self::$lengthFormatMap[$lengthBytes])) {
throw new ParserException('Undefined variable length format.');
}
$f = self::$lengthFormatMap[$lengthBytes];
list($len, $bytes) = $this->{$f}();
return [$this->readAndHashBytes($len), $len + $bytes];
}
private function decodeTimestamp()
{
list($val, $bytes) = $this->decodeInt64();
return [
DateTimeResult::createFromFormat('U.u', $val / 1000),
$bytes
];
}
private function decodeUuid()
{
$val = unpack('H32', $this->readAndHashBytes(16))[1];
return [
substr($val, 0, 8) . '-'
. substr($val, 8, 4) . '-'
. substr($val, 12, 4) . '-'
. substr($val, 16, 4) . '-'
. substr($val, 20, 12),
16
];
}
}
@@ -0,0 +1,107 @@
<?php
namespace Aws\Api\Parser;
use \Iterator;
use Aws\Exception\EventStreamDataException;
use Aws\Api\Parser\Exception\ParserException;
use Aws\Api\StructureShape;
use Psr\Http\Message\StreamInterface;
/**
* @internal Implements a decoder for a binary encoded event stream that will
* decode, validate, and provide individual events from the stream.
*/
class EventParsingIterator implements Iterator
{
/** @var StreamInterface */
private $decodingIterator;
/** @var StructureShape */
private $shape;
/** @var AbstractParser */
private $parser;
public function __construct(
StreamInterface $stream,
StructureShape $shape,
AbstractParser $parser
) {
$this->decodingIterator = new DecodingEventStreamIterator($stream);
$this->shape = $shape;
$this->parser = $parser;
}
public function current()
{
return $this->parseEvent($this->decodingIterator->current());
}
public function key()
{
return $this->decodingIterator->key();
}
public function next()
{
$this->decodingIterator->next();
}
public function rewind()
{
$this->decodingIterator->rewind();
}
public function valid()
{
return $this->decodingIterator->valid();
}
private function parseEvent(array $event)
{
if (!empty($event['headers'][':message-type'])) {
if ($event['headers'][':message-type'] === 'error') {
return $this->parseError($event);
}
if ($event['headers'][':message-type'] !== 'event') {
throw new ParserException('Failed to parse unknown message type.');
}
}
if (empty($event['headers'][':event-type'])) {
throw new ParserException('Failed to parse without event type.');
}
$eventShape = $this->shape->getMember($event['headers'][':event-type']);
$parsedEvent = [];
foreach ($eventShape['members'] as $shape => $details) {
if (!empty($details['eventpayload'])) {
$payloadShape = $eventShape->getMember($shape);
if ($payloadShape['type'] === 'blob') {
$parsedEvent[$shape] = $event['payload'];
} else {
$parsedEvent[$shape] = $this->parser->parseMemberFromStream(
$event['payload'],
$payloadShape,
null
);
}
} else {
$parsedEvent[$shape] = $event['headers'][$shape];
}
}
return [
$event['headers'][':event-type'] => $parsedEvent
];
}
private function parseError(array $event)
{
throw new EventStreamDataException(
$event['headers'][':error-code'],
$event['headers'][':error-message']
);
}
}
@@ -0,0 +1,56 @@
<?php
namespace Aws\Api\Parser\Exception;
use Aws\HasMonitoringEventsTrait;
use Aws\MonitoringEventsInterface;
use Aws\ResponseContainerInterface;
use Psr\Http\Message\ResponseInterface;
class ParserException extends \RuntimeException implements
MonitoringEventsInterface,
ResponseContainerInterface
{
use HasMonitoringEventsTrait;
private $errorCode;
private $requestId;
private $response;
public function __construct($message = '', $code = 0, $previous = null, array $context = [])
{
$this->errorCode = isset($context['error_code']) ? $context['error_code'] : null;
$this->requestId = isset($context['request_id']) ? $context['request_id'] : null;
$this->response = isset($context['response']) ? $context['response'] : null;
parent::__construct($message, $code, $previous);
}
/**
* Get the error code, if any.
*
* @return string|null
*/
public function getErrorCode()
{
return $this->errorCode;
}
/**
* Get the request ID, if any.
*
* @return string|null
*/
public function getRequestId()
{
return $this->requestId;
}
/**
* Get the received HTTP response if any.
*
* @return ResponseInterface|null
*/
public function getResponse()
{
return $this->response;
}
}
@@ -0,0 +1,59 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\DateTimeResult;
use Aws\Api\Shape;
/**
* @internal Implements standard JSON parsing.
*/
class JsonParser
{
public function parse(Shape $shape, $value)
{
if ($value === null) {
return $value;
}
switch ($shape['type']) {
case 'structure':
$target = [];
foreach ($shape->getMembers() as $name => $member) {
$locationName = $member['locationName'] ?: $name;
if (isset($value[$locationName])) {
$target[$name] = $this->parse($member, $value[$locationName]);
}
}
return $target;
case 'list':
$member = $shape->getMember();
$target = [];
foreach ($value as $v) {
$target[] = $this->parse($member, $v);
}
return $target;
case 'map':
$values = $shape->getValue();
$target = [];
foreach ($value as $k => $v) {
$target[$k] = $this->parse($values, $v);
}
return $target;
case 'timestamp':
return DateTimeResult::fromTimestamp(
$value,
!empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null
);
case 'blob':
return base64_decode($value);
default:
return $value;
}
}
}
@@ -0,0 +1,51 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\StructureShape;
use Aws\Api\Service;
use Aws\Result;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* @internal Implements JSON-RPC parsing (e.g., DynamoDB)
*/
class JsonRpcParser extends AbstractParser
{
use PayloadParserTrait;
/**
* @param Service $api Service description
* @param JsonParser $parser JSON body builder
*/
public function __construct(Service $api, JsonParser $parser = null)
{
parent::__construct($api);
$this->parser = $parser ?: new JsonParser();
}
public function __invoke(
CommandInterface $command,
ResponseInterface $response
) {
$operation = $this->api->getOperation($command->getName());
$result = null === $operation['output']
? null
: $this->parseMemberFromStream(
$response->getBody(),
$operation->getOutput(),
$response
);
return new Result($result ?: []);
}
public function parseMemberFromStream(
StreamInterface $stream,
StructureShape $member,
$response
) {
return $this->parser->parse($member, $this->parseJson($stream, $response));
}
}
@@ -0,0 +1,90 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\DateTimeResult;
use Aws\Api\Shape;
use Psr\Http\Message\ResponseInterface;
trait MetadataParserTrait
{
/**
* Extract a single header from the response into the result.
*/
protected function extractHeader(
$name,
Shape $shape,
ResponseInterface $response,
&$result
) {
$value = $response->getHeaderLine($shape['locationName'] ?: $name);
switch ($shape->getType()) {
case 'float':
case 'double':
$value = (float) $value;
break;
case 'long':
$value = (int) $value;
break;
case 'boolean':
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
break;
case 'blob':
$value = base64_decode($value);
break;
case 'timestamp':
try {
$value = DateTimeResult::fromTimestamp(
$value,
!empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null
);
break;
} catch (\Exception $e) {
// If the value cannot be parsed, then do not add it to the
// output structure.
return;
}
case 'string':
if ($shape['jsonvalue']) {
$value = $this->parseJson(base64_decode($value), $response);
}
break;
}
$result[$name] = $value;
}
/**
* Extract a map of headers with an optional prefix from the response.
*/
protected function extractHeaders(
$name,
Shape $shape,
ResponseInterface $response,
&$result
) {
// Check if the headers are prefixed by a location name
$result[$name] = [];
$prefix = $shape['locationName'];
$prefixLen = strlen($prefix);
foreach ($response->getHeaders() as $k => $values) {
if (!$prefixLen) {
$result[$name][$k] = implode(', ', $values);
} elseif (stripos($k, $prefix) === 0) {
$result[$name][substr($k, $prefixLen)] = implode(', ', $values);
}
}
}
/**
* Places the status code of the response into the result array.
*/
protected function extractStatus(
$name,
ResponseInterface $response,
array &$result
) {
$result[$name] = (int) $response->getStatusCode();
}
}
@@ -0,0 +1,61 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\Parser\Exception\ParserException;
use Psr\Http\Message\ResponseInterface;
trait PayloadParserTrait
{
/**
* @param string $json
*
* @throws ParserException
*
* @return array
*/
private function parseJson($json, $response)
{
$jsonPayload = json_decode($json, true);
if (JSON_ERROR_NONE !== json_last_error()) {
throw new ParserException(
'Error parsing JSON: ' . json_last_error_msg(),
0,
null,
['response' => $response]
);
}
return $jsonPayload;
}
/**
* @param string $xml
*
* @throws ParserException
*
* @return \SimpleXMLElement
*/
protected function parseXml($xml, $response)
{
$priorSetting = libxml_use_internal_errors(true);
try {
libxml_clear_errors();
$xmlPayload = new \SimpleXMLElement($xml);
if ($error = libxml_get_last_error()) {
throw new \RuntimeException($error->message);
}
} catch (\Exception $e) {
throw new ParserException(
"Error parsing XML: {$e->getMessage()}",
0,
$e,
['response' => $response]
);
} finally {
libxml_use_internal_errors($priorSetting);
}
return $xmlPayload;
}
}
@@ -0,0 +1,60 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\Service;
use Aws\Api\StructureShape;
use Aws\Result;
use Aws\CommandInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* @internal Parses query (XML) responses (e.g., EC2, SQS, and many others)
*/
class QueryParser extends AbstractParser
{
use PayloadParserTrait;
/** @var bool */
private $honorResultWrapper;
/**
* @param Service $api Service description
* @param XmlParser $xmlParser Optional XML parser
* @param bool $honorResultWrapper Set to false to disable the peeling
* back of result wrappers from the
* output structure.
*/
public function __construct(
Service $api,
XmlParser $xmlParser = null,
$honorResultWrapper = true
) {
parent::__construct($api);
$this->parser = $xmlParser ?: new XmlParser();
$this->honorResultWrapper = $honorResultWrapper;
}
public function __invoke(
CommandInterface $command,
ResponseInterface $response
) {
$output = $this->api->getOperation($command->getName())->getOutput();
$xml = $this->parseXml($response->getBody(), $response);
if ($this->honorResultWrapper && $output['resultWrapper']) {
$xml = $xml->{$output['resultWrapper']};
}
return new Result($this->parser->parse($output, $xml));
}
public function parseMemberFromStream(
StreamInterface $stream,
StructureShape $member,
$response
) {
$xml = $this->parseXml($stream, $response);
return $this->parser->parse($member, $xml);
}
}
@@ -0,0 +1,49 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\Service;
use Aws\Api\StructureShape;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* @internal Implements REST-JSON parsing (e.g., Glacier, Elastic Transcoder)
*/
class RestJsonParser extends AbstractRestParser
{
use PayloadParserTrait;
/**
* @param Service $api Service description
* @param JsonParser $parser JSON body builder
*/
public function __construct(Service $api, JsonParser $parser = null)
{
parent::__construct($api);
$this->parser = $parser ?: new JsonParser();
}
protected function payload(
ResponseInterface $response,
StructureShape $member,
array &$result
) {
$jsonBody = $this->parseJson($response->getBody(), $response);
if ($jsonBody) {
$result += $this->parser->parse($member, $jsonBody);
}
}
public function parseMemberFromStream(
StreamInterface $stream,
StructureShape $member,
$response
) {
$jsonBody = $this->parseJson($stream, $response);
if ($jsonBody) {
return $this->parser->parse($member, $jsonBody);
}
return [];
}
}
@@ -0,0 +1,42 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\StructureShape;
use Aws\Api\Service;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/**
* @internal Implements REST-XML parsing (e.g., S3, CloudFront, etc...)
*/
class RestXmlParser extends AbstractRestParser
{
use PayloadParserTrait;
/**
* @param Service $api Service description
* @param XmlParser $parser XML body parser
*/
public function __construct(Service $api, XmlParser $parser = null)
{
parent::__construct($api);
$this->parser = $parser ?: new XmlParser();
}
protected function payload(
ResponseInterface $response,
StructureShape $member,
array &$result
) {
$result += $this->parseMemberFromStream($response->getBody(), $member, $response);
}
public function parseMemberFromStream(
StreamInterface $stream,
StructureShape $member,
$response
) {
$xml = $this->parseXml($stream, $response);
return $this->parser->parse($member, $xml);
}
}
@@ -0,0 +1,171 @@
<?php
namespace Aws\Api\Parser;
use Aws\Api\DateTimeResult;
use Aws\Api\ListShape;
use Aws\Api\MapShape;
use Aws\Api\Parser\Exception\ParserException;
use Aws\Api\Shape;
use Aws\Api\StructureShape;
/**
* @internal Implements standard XML parsing for REST-XML and Query protocols.
*/
class XmlParser
{
public function parse(StructureShape $shape, \SimpleXMLElement $value)
{
return $this->dispatch($shape, $value);
}
private function dispatch($shape, \SimpleXMLElement $value)
{
static $methods = [
'structure' => 'parse_structure',
'list' => 'parse_list',
'map' => 'parse_map',
'blob' => 'parse_blob',
'boolean' => 'parse_boolean',
'integer' => 'parse_integer',
'float' => 'parse_float',
'double' => 'parse_float',
'timestamp' => 'parse_timestamp',
];
$type = $shape['type'];
if (isset($methods[$type])) {
return $this->{$methods[$type]}($shape, $value);
}
return (string) $value;
}
private function parse_structure(
StructureShape $shape,
\SimpleXMLElement $value
) {
$target = [];
foreach ($shape->getMembers() as $name => $member) {
// Extract the name of the XML node
$node = $this->memberKey($member, $name);
if (isset($value->{$node})) {
$target[$name] = $this->dispatch($member, $value->{$node});
} else {
$memberShape = $shape->getMember($name);
if (!empty($memberShape['xmlAttribute'])) {
$target[$name] = $this->parse_xml_attribute(
$shape,
$memberShape,
$value
);
}
}
}
return $target;
}
private function memberKey(Shape $shape, $name)
{
if (null !== $shape['locationName']) {
return $shape['locationName'];
}
if ($shape instanceof ListShape && $shape['flattened']) {
return $shape->getMember()['locationName'] ?: $name;
}
return $name;
}
private function parse_list(ListShape $shape, \SimpleXMLElement $value)
{
$target = [];
$member = $shape->getMember();
if (!$shape['flattened']) {
$value = $value->{$member['locationName'] ?: 'member'};
}
foreach ($value as $v) {
$target[] = $this->dispatch($member, $v);
}
return $target;
}
private function parse_map(MapShape $shape, \SimpleXMLElement $value)
{
$target = [];
if (!$shape['flattened']) {
$value = $value->entry;
}
$mapKey = $shape->getKey();
$mapValue = $shape->getValue();
$keyName = $shape->getKey()['locationName'] ?: 'key';
$valueName = $shape->getValue()['locationName'] ?: 'value';
foreach ($value as $node) {
$key = $this->dispatch($mapKey, $node->{$keyName});
$value = $this->dispatch($mapValue, $node->{$valueName});
$target[$key] = $value;
}
return $target;
}
private function parse_blob(Shape $shape, $value)
{
return base64_decode((string) $value);
}
private function parse_float(Shape $shape, $value)
{
return (float) (string) $value;
}
private function parse_integer(Shape $shape, $value)
{
return (int) (string) $value;
}
private function parse_boolean(Shape $shape, $value)
{
return $value == 'true';
}
private function parse_timestamp(Shape $shape, $value)
{
if (is_string($value)
|| is_int($value)
|| (is_object($value)
&& method_exists($value, '__toString'))
) {
return DateTimeResult::fromTimestamp(
(string) $value,
!empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null
);
}
throw new ParserException('Invalid timestamp value passed to XmlParser::parse_timestamp');
}
private function parse_xml_attribute(Shape $shape, Shape $memberShape, $value)
{
$namespace = $shape['xmlNamespace']['uri']
? $shape['xmlNamespace']['uri']
: '';
$prefix = $shape['xmlNamespace']['prefix']
? $shape['xmlNamespace']['prefix']
: '';
if (!empty($prefix)) {
$prefix .= ':';
}
$key = str_replace($prefix, '', $memberShape['locationName']);
$attributes = $value->attributes($namespace);
return isset($attributes[$key]) ? (string) $attributes[$key] : null;
}
}
@@ -0,0 +1,40 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\Shape;
use Aws\Api\ListShape;
/**
* @internal
*/
class Ec2ParamBuilder extends QueryParamBuilder
{
protected function queryName(Shape $shape, $default = null)
{
return ($shape['queryName']
?: ucfirst($shape['locationName']))
?: $default;
}
protected function isFlat(Shape $shape)
{
return false;
}
protected function format_list(
ListShape $shape,
array $value,
$prefix,
&$query
) {
// Handle empty list serialization
if (!$value) {
$query[$prefix] = false;
} else {
$items = $shape->getMember();
foreach ($value as $k => $v) {
$this->format($items, $v, $prefix . '.' . ($k + 1), $query);
}
}
}
}
@@ -0,0 +1,96 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\Service;
use Aws\Api\Shape;
use Aws\Api\TimestampShape;
/**
* Formats the JSON body of a JSON-REST or JSON-RPC operation.
* @internal
*/
class JsonBody
{
private $api;
public function __construct(Service $api)
{
$this->api = $api;
}
/**
* Gets the JSON Content-Type header for a service API
*
* @param Service $service
*
* @return string
*/
public static function getContentType(Service $service)
{
return 'application/x-amz-json-'
. number_format($service->getMetadata('jsonVersion'), 1);
}
/**
* Builds the JSON body based on an array of arguments.
*
* @param Shape $shape Operation being constructed
* @param array $args Associative array of arguments
*
* @return string
*/
public function build(Shape $shape, array $args)
{
$result = json_encode($this->format($shape, $args));
return $result == '[]' ? '{}' : $result;
}
private function format(Shape $shape, $value)
{
switch ($shape['type']) {
case 'structure':
$data = [];
foreach ($value as $k => $v) {
if ($v !== null && $shape->hasMember($k)) {
$valueShape = $shape->getMember($k);
$data[$valueShape['locationName'] ?: $k]
= $this->format($valueShape, $v);
}
}
if (empty($data)) {
return new \stdClass;
}
return $data;
case 'list':
$items = $shape->getMember();
foreach ($value as $k => $v) {
$value[$k] = $this->format($items, $v);
}
return $value;
case 'map':
if (empty($value)) {
return new \stdClass;
}
$values = $shape->getValue();
foreach ($value as $k => $v) {
$value[$k] = $this->format($values, $v);
}
return $value;
case 'blob':
return base64_encode($value);
case 'timestamp':
$timestampFormat = !empty($shape['timestampFormat'])
? $shape['timestampFormat']
: 'unixTimestamp';
return TimestampShape::format($value, $timestampFormat);
default:
return $value;
}
}
}
@@ -0,0 +1,69 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\Service;
use Aws\CommandInterface;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\RequestInterface;
/**
* Prepares a JSON-RPC request for transfer.
* @internal
*/
class JsonRpcSerializer
{
/** @var JsonBody */
private $jsonFormatter;
/** @var string */
private $endpoint;
/** @var Service */
private $api;
/** @var string */
private $contentType;
/**
* @param Service $api Service description
* @param string $endpoint Endpoint to connect to
* @param JsonBody $jsonFormatter Optional JSON formatter to use
*/
public function __construct(
Service $api,
$endpoint,
JsonBody $jsonFormatter = null
) {
$this->endpoint = $endpoint;
$this->api = $api;
$this->jsonFormatter = $jsonFormatter ?: new JsonBody($this->api);
$this->contentType = JsonBody::getContentType($api);
}
/**
* When invoked with an AWS command, returns a serialization array
* containing "method", "uri", "headers", and "body" key value pairs.
*
* @param CommandInterface $command
*
* @return RequestInterface
*/
public function __invoke(CommandInterface $command)
{
$name = $command->getName();
$operation = $this->api->getOperation($name);
return new Request(
$operation['http']['method'],
$this->endpoint,
[
'X-Amz-Target' => $this->api->getMetadata('targetPrefix') . '.' . $name,
'Content-Type' => $this->contentType
],
$this->jsonFormatter->build(
$operation->getInput(),
$command->toArray()
)
);
}
}
@@ -0,0 +1,157 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\StructureShape;
use Aws\Api\ListShape;
use Aws\Api\MapShape;
use Aws\Api\Shape;
use Aws\Api\TimestampShape;
/**
* @internal
*/
class QueryParamBuilder
{
private $methods;
protected function queryName(Shape $shape, $default = null)
{
if (null !== $shape['queryName']) {
return $shape['queryName'];
}
if (null !== $shape['locationName']) {
return $shape['locationName'];
}
if ($this->isFlat($shape) && !empty($shape['member']['locationName'])) {
return $shape['member']['locationName'];
}
return $default;
}
protected function isFlat(Shape $shape)
{
return $shape['flattened'] === true;
}
public function __invoke(StructureShape $shape, array $params)
{
if (!$this->methods) {
$this->methods = array_fill_keys(get_class_methods($this), true);
}
$query = [];
$this->format_structure($shape, $params, '', $query);
return $query;
}
protected function format(Shape $shape, $value, $prefix, array &$query)
{
$type = 'format_' . $shape['type'];
if (isset($this->methods[$type])) {
$this->{$type}($shape, $value, $prefix, $query);
} else {
$query[$prefix] = (string) $value;
}
}
protected function format_structure(
StructureShape $shape,
array $value,
$prefix,
&$query
) {
if ($prefix) {
$prefix .= '.';
}
foreach ($value as $k => $v) {
if ($shape->hasMember($k)) {
$member = $shape->getMember($k);
$this->format(
$member,
$v,
$prefix . $this->queryName($member, $k),
$query
);
}
}
}
protected function format_list(
ListShape $shape,
array $value,
$prefix,
&$query
) {
// Handle empty list serialization
if (!$value) {
$query[$prefix] = '';
return;
}
$items = $shape->getMember();
if (!$this->isFlat($shape)) {
$locationName = $shape->getMember()['locationName'] ?: 'member';
$prefix .= ".$locationName";
} elseif ($name = $this->queryName($items)) {
$parts = explode('.', $prefix);
$parts[count($parts) - 1] = $name;
$prefix = implode('.', $parts);
}
foreach ($value as $k => $v) {
$this->format($items, $v, $prefix . '.' . ($k + 1), $query);
}
}
protected function format_map(
MapShape $shape,
array $value,
$prefix,
array &$query
) {
$vals = $shape->getValue();
$keys = $shape->getKey();
if (!$this->isFlat($shape)) {
$prefix .= '.entry';
}
$i = 0;
$keyName = '%s.%d.' . $this->queryName($keys, 'key');
$valueName = '%s.%s.' . $this->queryName($vals, 'value');
foreach ($value as $k => $v) {
$i++;
$this->format($keys, $k, sprintf($keyName, $prefix, $i), $query);
$this->format($vals, $v, sprintf($valueName, $prefix, $i), $query);
}
}
protected function format_blob(Shape $shape, $value, $prefix, array &$query)
{
$query[$prefix] = base64_encode($value);
}
protected function format_timestamp(
TimestampShape $shape,
$value,
$prefix,
array &$query
) {
$timestampFormat = !empty($shape['timestampFormat'])
? $shape['timestampFormat']
: 'iso8601';
$query[$prefix] = TimestampShape::format($value, $timestampFormat);
}
protected function format_boolean(Shape $shape, $value, $prefix, array &$query)
{
$query[$prefix] = ($value) ? 'true' : 'false';
}
}
@@ -0,0 +1,69 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\Service;
use Aws\CommandInterface;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\RequestInterface;
/**
* Serializes a query protocol request.
* @internal
*/
class QuerySerializer
{
private $endpoint;
private $api;
private $paramBuilder;
public function __construct(
Service $api,
$endpoint,
callable $paramBuilder = null
) {
$this->api = $api;
$this->endpoint = $endpoint;
$this->paramBuilder = $paramBuilder ?: new QueryParamBuilder();
}
/**
* When invoked with an AWS command, returns a serialization array
* containing "method", "uri", "headers", and "body" key value pairs.
*
* @param CommandInterface $command
*
* @return RequestInterface
*/
public function __invoke(CommandInterface $command)
{
$operation = $this->api->getOperation($command->getName());
$body = [
'Action' => $command->getName(),
'Version' => $this->api->getMetadata('apiVersion')
];
$params = $command->toArray();
// Only build up the parameters when there are parameters to build
if ($params) {
$body += call_user_func(
$this->paramBuilder,
$operation->getInput(),
$params
);
}
$body = http_build_query($body, null, '&', PHP_QUERY_RFC3986);
return new Request(
'POST',
$this->endpoint,
[
'Content-Length' => strlen($body),
'Content-Type' => 'application/x-www-form-urlencoded'
],
$body
);
}
}
@@ -0,0 +1,39 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\Service;
use Aws\Api\StructureShape;
/**
* Serializes requests for the REST-JSON protocol.
* @internal
*/
class RestJsonSerializer extends RestSerializer
{
/** @var JsonBody */
private $jsonFormatter;
/** @var string */
private $contentType;
/**
* @param Service $api Service API description
* @param string $endpoint Endpoint to connect to
* @param JsonBody $jsonFormatter Optional JSON formatter to use
*/
public function __construct(
Service $api,
$endpoint,
JsonBody $jsonFormatter = null
) {
parent::__construct($api, $endpoint);
$this->contentType = 'application/json';
$this->jsonFormatter = $jsonFormatter ?: new JsonBody($api);
}
protected function payload(StructureShape $member, array $value, array &$opts)
{
$opts['headers']['Content-Type'] = $this->contentType;
$opts['body'] = (string) $this->jsonFormatter->build($member, $value);
}
}
@@ -0,0 +1,225 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\MapShape;
use Aws\Api\Service;
use Aws\Api\Operation;
use Aws\Api\Shape;
use Aws\Api\StructureShape;
use Aws\Api\TimestampShape;
use Aws\CommandInterface;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
use Psr\Http\Message\RequestInterface;
/**
* Serializes HTTP locations like header, uri, payload, etc...
* @internal
*/
abstract class RestSerializer
{
/** @var Service */
private $api;
/** @var Psr7\Uri */
private $endpoint;
/**
* @param Service $api Service API description
* @param string $endpoint Endpoint to connect to
*/
public function __construct(Service $api, $endpoint)
{
$this->api = $api;
$this->endpoint = Psr7\uri_for($endpoint);
}
/**
* @param CommandInterface $command Command to serialized
*
* @return RequestInterface
*/
public function __invoke(CommandInterface $command)
{
$operation = $this->api->getOperation($command->getName());
$args = $command->toArray();
$opts = $this->serialize($operation, $args);
$uri = $this->buildEndpoint($operation, $args, $opts);
return new Psr7\Request(
$operation['http']['method'],
$uri,
isset($opts['headers']) ? $opts['headers'] : [],
isset($opts['body']) ? $opts['body'] : null
);
}
/**
* Modifies a hash of request options for a payload body.
*
* @param StructureShape $member Member to serialize
* @param array $value Value to serialize
* @param array $opts Request options to modify.
*/
abstract protected function payload(
StructureShape $member,
array $value,
array &$opts
);
private function serialize(Operation $operation, array $args)
{
$opts = [];
$input = $operation->getInput();
// Apply the payload trait if present
if ($payload = $input['payload']) {
$this->applyPayload($input, $payload, $args, $opts);
}
foreach ($args as $name => $value) {
if ($input->hasMember($name)) {
$member = $input->getMember($name);
$location = $member['location'];
if (!$payload && !$location) {
$bodyMembers[$name] = $value;
} elseif ($location == 'header') {
$this->applyHeader($name, $member, $value, $opts);
} elseif ($location == 'querystring') {
$this->applyQuery($name, $member, $value, $opts);
} elseif ($location == 'headers') {
$this->applyHeaderMap($name, $member, $value, $opts);
}
}
}
if (isset($bodyMembers)) {
$this->payload($operation->getInput(), $bodyMembers, $opts);
}
return $opts;
}
private function applyPayload(StructureShape $input, $name, array $args, array &$opts)
{
if (!isset($args[$name])) {
return;
}
$m = $input->getMember($name);
if ($m['streaming'] ||
($m['type'] == 'string' || $m['type'] == 'blob')
) {
// Streaming bodies or payloads that are strings are
// always just a stream of data.
$opts['body'] = Psr7\stream_for($args[$name]);
return;
}
$this->payload($m, $args[$name], $opts);
}
private function applyHeader($name, Shape $member, $value, array &$opts)
{
if ($member->getType() === 'timestamp') {
$timestampFormat = !empty($member['timestampFormat'])
? $member['timestampFormat']
: 'rfc822';
$value = TimestampShape::format($value, $timestampFormat);
}
if ($member['jsonvalue']) {
$value = json_encode($value);
if (empty($value) && JSON_ERROR_NONE !== json_last_error()) {
throw new \InvalidArgumentException('Unable to encode the provided value'
. ' with \'json_encode\'. ' . json_last_error_msg());
}
$value = base64_encode($value);
}
$opts['headers'][$member['locationName'] ?: $name] = $value;
}
/**
* Note: This is currently only present in the Amazon S3 model.
*/
private function applyHeaderMap($name, Shape $member, array $value, array &$opts)
{
$prefix = $member['locationName'];
foreach ($value as $k => $v) {
$opts['headers'][$prefix . $k] = $v;
}
}
private function applyQuery($name, Shape $member, $value, array &$opts)
{
if ($member instanceof MapShape) {
$opts['query'] = isset($opts['query']) && is_array($opts['query'])
? $opts['query'] + $value
: $value;
} elseif ($value !== null) {
$type = $member->getType();
if ($type === 'boolean') {
$value = $value ? 'true' : 'false';
} elseif ($type === 'timestamp') {
$timestampFormat = !empty($member['timestampFormat'])
? $member['timestampFormat']
: 'iso8601';
$value = TimestampShape::format($value, $timestampFormat);
}
$opts['query'][$member['locationName'] ?: $name] = $value;
}
}
private function buildEndpoint(Operation $operation, array $args, array $opts)
{
$varspecs = [];
// Create an associative array of varspecs used in expansions
foreach ($operation->getInput()->getMembers() as $name => $member) {
if ($member['location'] == 'uri') {
$varspecs[$member['locationName'] ?: $name] =
isset($args[$name])
? $args[$name]
: null;
}
}
$relative = preg_replace_callback(
'/\{([^\}]+)\}/',
function (array $matches) use ($varspecs) {
$isGreedy = substr($matches[1], -1, 1) == '+';
$k = $isGreedy ? substr($matches[1], 0, -1) : $matches[1];
if (!isset($varspecs[$k])) {
return '';
}
if ($isGreedy) {
return str_replace('%2F', '/', rawurlencode($varspecs[$k]));
}
return rawurlencode($varspecs[$k]);
},
$operation['http']['requestUri']
);
// Add the query string variables or appending to one if needed.
if (!empty($opts['query'])) {
$append = Psr7\build_query($opts['query']);
$relative .= strpos($relative, '?') ? "&{$append}" : "?$append";
}
// If endpoint has path, remove leading '/' to preserve URI resolution.
$path = $this->endpoint->getPath();
if ($path && $relative[0] === '/') {
$relative = substr($relative, 1);
}
// Expand path place holders using Amazon's slightly different URI
// template syntax.
return UriResolver::resolve($this->endpoint, new Uri($relative));
}
}
@@ -0,0 +1,34 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\StructureShape;
use Aws\Api\Service;
/**
* @internal
*/
class RestXmlSerializer extends RestSerializer
{
/** @var XmlBody */
private $xmlBody;
/**
* @param Service $api Service API description
* @param string $endpoint Endpoint to connect to
* @param XmlBody $xmlBody Optional XML formatter to use
*/
public function __construct(
Service $api,
$endpoint,
XmlBody $xmlBody = null
) {
parent::__construct($api, $endpoint);
$this->xmlBody = $xmlBody ?: new XmlBody($api);
}
protected function payload(StructureShape $member, array $value, array &$opts)
{
$opts['headers']['Content-Type'] = 'application/xml';
$opts['body'] = (string) $this->xmlBody->build($member, $value);
}
}
@@ -0,0 +1,220 @@
<?php
namespace Aws\Api\Serializer;
use Aws\Api\MapShape;
use Aws\Api\Service;
use Aws\Api\Shape;
use Aws\Api\StructureShape;
use Aws\Api\ListShape;
use Aws\Api\TimestampShape;
use XMLWriter;
/**
* @internal Formats the XML body of a REST-XML services.
*/
class XmlBody
{
/** @var \Aws\Api\Service */
private $api;
/**
* @param Service $api API being used to create the XML body.
*/
public function __construct(Service $api)
{
$this->api = $api;
}
/**
* Builds the XML body based on an array of arguments.
*
* @param Shape $shape Operation being constructed
* @param array $args Associative array of arguments
*
* @return string
*/
public function build(Shape $shape, array $args)
{
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'UTF-8');
$this->format($shape, $shape['locationName'] ?: $shape['name'], $args, $xml);
$xml->endDocument();
return $xml->outputMemory();
}
private function startElement(Shape $shape, $name, XMLWriter $xml)
{
$xml->startElement($name);
if ($ns = $shape['xmlNamespace']) {
$xml->writeAttribute(
isset($ns['prefix']) ? "xmlns:{$ns['prefix']}" : 'xmlns',
$shape['xmlNamespace']['uri']
);
}
}
private function format(Shape $shape, $name, $value, XMLWriter $xml)
{
// Any method mentioned here has a custom serialization handler.
static $methods = [
'add_structure' => true,
'add_list' => true,
'add_blob' => true,
'add_timestamp' => true,
'add_boolean' => true,
'add_map' => true,
'add_string' => true
];
$type = 'add_' . $shape['type'];
if (isset($methods[$type])) {
$this->{$type}($shape, $name, $value, $xml);
} else {
$this->defaultShape($shape, $name, $value, $xml);
}
}
private function defaultShape(Shape $shape, $name, $value, XMLWriter $xml)
{
$this->startElement($shape, $name, $xml);
$xml->text($value);
$xml->endElement();
}
private function add_structure(
StructureShape $shape,
$name,
array $value,
\XMLWriter $xml
) {
$this->startElement($shape, $name, $xml);
foreach ($this->getStructureMembers($shape, $value) as $k => $definition) {
$this->format(
$definition['member'],
$definition['member']['locationName'] ?: $k,
$definition['value'],
$xml
);
}
$xml->endElement();
}
private function getStructureMembers(StructureShape $shape, array $value)
{
$members = [];
foreach ($value as $k => $v) {
if ($v !== null && $shape->hasMember($k)) {
$definition = [
'member' => $shape->getMember($k),
'value' => $v,
];
if ($definition['member']['xmlAttribute']) {
// array_unshift_associative
$members = [$k => $definition] + $members;
} else {
$members[$k] = $definition;
}
}
}
return $members;
}
private function add_list(
ListShape $shape,
$name,
array $value,
XMLWriter $xml
) {
$items = $shape->getMember();
if ($shape['flattened']) {
$elementName = $name;
} else {
$this->startElement($shape, $name, $xml);
$elementName = $items['locationName'] ?: 'member';
}
foreach ($value as $v) {
$this->format($items, $elementName, $v, $xml);
}
if (!$shape['flattened']) {
$xml->endElement();
}
}
private function add_map(
MapShape $shape,
$name,
array $value,
XMLWriter $xml
) {
$xmlEntry = $shape['flattened'] ? $shape['locationName'] : 'entry';
$xmlKey = $shape->getKey()['locationName'] ?: 'key';
$xmlValue = $shape->getValue()['locationName'] ?: 'value';
$this->startElement($shape, $name, $xml);
foreach ($value as $key => $v) {
$this->startElement($shape, $xmlEntry, $xml);
$this->format($shape->getKey(), $xmlKey, $key, $xml);
$this->format($shape->getValue(), $xmlValue, $v, $xml);
$xml->endElement();
}
$xml->endElement();
}
private function add_blob(Shape $shape, $name, $value, XMLWriter $xml)
{
$this->startElement($shape, $name, $xml);
$xml->writeRaw(base64_encode($value));
$xml->endElement();
}
private function add_timestamp(
TimestampShape $shape,
$name,
$value,
XMLWriter $xml
) {
$this->startElement($shape, $name, $xml);
$timestampFormat = !empty($shape['timestampFormat'])
? $shape['timestampFormat']
: 'iso8601';
$xml->writeRaw(TimestampShape::format($value, $timestampFormat));
$xml->endElement();
}
private function add_boolean(
Shape $shape,
$name,
$value,
XMLWriter $xml
) {
$this->startElement($shape, $name, $xml);
$xml->writeRaw($value ? 'true' : 'false');
$xml->endElement();
}
private function add_string(
Shape $shape,
$name,
$value,
XMLWriter $xml
) {
if ($shape['xmlAttribute']) {
$xml->writeAttribute($shape['locationName'] ?: $name, $value);
} else {
$this->defaultShape($shape, $name, $value, $xml);
}
}
}
+468
View File
@@ -0,0 +1,468 @@
<?php
namespace Aws\Api;
use Aws\Api\Serializer\QuerySerializer;
use Aws\Api\Serializer\Ec2ParamBuilder;
use Aws\Api\Parser\QueryParser;
/**
* Represents a web service API model.
*/
class Service extends AbstractModel
{
/** @var callable */
private $apiProvider;
/** @var string */
private $serviceName;
/** @var string */
private $apiVersion;
/** @var Operation[] */
private $operations = [];
/** @var array */
private $paginators = null;
/** @var array */
private $waiters = null;
/**
* @param array $definition
* @param callable $provider
*
* @internal param array $definition Service description
*/
public function __construct(array $definition, callable $provider)
{
static $defaults = [
'operations' => [],
'shapes' => [],
'metadata' => []
], $defaultMeta = [
'apiVersion' => null,
'serviceFullName' => null,
'serviceId' => null,
'endpointPrefix' => null,
'signingName' => null,
'signatureVersion' => null,
'protocol' => null,
'uid' => null
];
$definition += $defaults;
$definition['metadata'] += $defaultMeta;
$this->definition = $definition;
$this->apiProvider = $provider;
parent::__construct($definition, new ShapeMap($definition['shapes']));
if (isset($definition['metadata']['serviceIdentifier'])) {
$this->serviceName = $this->getServiceName();
} else {
$this->serviceName = $this->getEndpointPrefix();
}
$this->apiVersion = $this->getApiVersion();
}
/**
* Creates a request serializer for the provided API object.
*
* @param Service $api API that contains a protocol.
* @param string $endpoint Endpoint to send requests to.
*
* @return callable
* @throws \UnexpectedValueException
*/
public static function createSerializer(Service $api, $endpoint)
{
static $mapping = [
'json' => 'Aws\Api\Serializer\JsonRpcSerializer',
'query' => 'Aws\Api\Serializer\QuerySerializer',
'rest-json' => 'Aws\Api\Serializer\RestJsonSerializer',
'rest-xml' => 'Aws\Api\Serializer\RestXmlSerializer'
];
$proto = $api->getProtocol();
if (isset($mapping[$proto])) {
return new $mapping[$proto]($api, $endpoint);
}
if ($proto == 'ec2') {
return new QuerySerializer($api, $endpoint, new Ec2ParamBuilder());
}
throw new \UnexpectedValueException(
'Unknown protocol: ' . $api->getProtocol()
);
}
/**
* Creates an error parser for the given protocol.
*
* Redundant method signature to preserve backwards compatibility.
*
* @param string $protocol Protocol to parse (e.g., query, json, etc.)
*
* @return callable
* @throws \UnexpectedValueException
*/
public static function createErrorParser($protocol, Service $api = null)
{
static $mapping = [
'json' => 'Aws\Api\ErrorParser\JsonRpcErrorParser',
'query' => 'Aws\Api\ErrorParser\XmlErrorParser',
'rest-json' => 'Aws\Api\ErrorParser\RestJsonErrorParser',
'rest-xml' => 'Aws\Api\ErrorParser\XmlErrorParser',
'ec2' => 'Aws\Api\ErrorParser\XmlErrorParser'
];
if (isset($mapping[$protocol])) {
return new $mapping[$protocol]($api);
}
throw new \UnexpectedValueException("Unknown protocol: $protocol");
}
/**
* Applies the listeners needed to parse client models.
*
* @param Service $api API to create a parser for
* @return callable
* @throws \UnexpectedValueException
*/
public static function createParser(Service $api)
{
static $mapping = [
'json' => 'Aws\Api\Parser\JsonRpcParser',
'query' => 'Aws\Api\Parser\QueryParser',
'rest-json' => 'Aws\Api\Parser\RestJsonParser',
'rest-xml' => 'Aws\Api\Parser\RestXmlParser'
];
$proto = $api->getProtocol();
if (isset($mapping[$proto])) {
return new $mapping[$proto]($api);
}
if ($proto == 'ec2') {
return new QueryParser($api, null, false);
}
throw new \UnexpectedValueException(
'Unknown protocol: ' . $api->getProtocol()
);
}
/**
* Get the full name of the service
*
* @return string
*/
public function getServiceFullName()
{
return $this->definition['metadata']['serviceFullName'];
}
/**
* Get the service id
*
* @return string
*/
public function getServiceId()
{
return $this->definition['metadata']['serviceId'];
}
/**
* Get the API version of the service
*
* @return string
*/
public function getApiVersion()
{
return $this->definition['metadata']['apiVersion'];
}
/**
* Get the API version of the service
*
* @return string
*/
public function getEndpointPrefix()
{
return $this->definition['metadata']['endpointPrefix'];
}
/**
* Get the signing name used by the service.
*
* @return string
*/
public function getSigningName()
{
return $this->definition['metadata']['signingName']
?: $this->definition['metadata']['endpointPrefix'];
}
/**
* Get the service name.
*
* @return string
*/
public function getServiceName()
{
return $this->definition['metadata']['serviceIdentifier'];
}
/**
* Get the default signature version of the service.
*
* Note: this method assumes "v4" when not specified in the model.
*
* @return string
*/
public function getSignatureVersion()
{
return $this->definition['metadata']['signatureVersion'] ?: 'v4';
}
/**
* Get the protocol used by the service.
*
* @return string
*/
public function getProtocol()
{
return $this->definition['metadata']['protocol'];
}
/**
* Get the uid string used by the service
*
* @return string
*/
public function getUid()
{
return $this->definition['metadata']['uid'];
}
/**
* Check if the description has a specific operation by name.
*
* @param string $name Operation to check by name
*
* @return bool
*/
public function hasOperation($name)
{
return isset($this['operations'][$name]);
}
/**
* Get an operation by name.
*
* @param string $name Operation to retrieve by name
*
* @return Operation
* @throws \InvalidArgumentException If the operation is not found
*/
public function getOperation($name)
{
if (!isset($this->operations[$name])) {
if (!isset($this->definition['operations'][$name])) {
throw new \InvalidArgumentException("Unknown operation: $name");
}
$this->operations[$name] = new Operation(
$this->definition['operations'][$name],
$this->shapeMap
);
}
return $this->operations[$name];
}
/**
* Get all of the operations of the description.
*
* @return Operation[]
*/
public function getOperations()
{
$result = [];
foreach ($this->definition['operations'] as $name => $definition) {
$result[$name] = $this->getOperation($name);
}
return $result;
}
/**
* Get all of the error shapes of the service
*
* @return array
*/
public function getErrorShapes()
{
$result = [];
foreach ($this->definition['shapes'] as $name => $definition) {
if (!empty($definition['exception'])) {
$definition['name'] = $name;
$result[] = new StructureShape($definition, $this->getShapeMap());
}
}
return $result;
}
/**
* Get all of the service metadata or a specific metadata key value.
*
* @param string|null $key Key to retrieve or null to retrieve all metadata
*
* @return mixed Returns the result or null if the key is not found
*/
public function getMetadata($key = null)
{
if (!$key) {
return $this['metadata'];
}
if (isset($this->definition['metadata'][$key])) {
return $this->definition['metadata'][$key];
}
return null;
}
/**
* Gets an associative array of available paginator configurations where
* the key is the name of the paginator, and the value is the paginator
* configuration.
*
* @return array
* @unstable The configuration format of paginators may change in the future
*/
public function getPaginators()
{
if (!isset($this->paginators)) {
$res = call_user_func(
$this->apiProvider,
'paginator',
$this->serviceName,
$this->apiVersion
);
$this->paginators = isset($res['pagination'])
? $res['pagination']
: [];
}
return $this->paginators;
}
/**
* Determines if the service has a paginator by name.
*
* @param string $name Name of the paginator.
*
* @return bool
*/
public function hasPaginator($name)
{
return isset($this->getPaginators()[$name]);
}
/**
* Retrieve a paginator by name.
*
* @param string $name Paginator to retrieve by name. This argument is
* typically the operation name.
* @return array
* @throws \UnexpectedValueException if the paginator does not exist.
* @unstable The configuration format of paginators may change in the future
*/
public function getPaginatorConfig($name)
{
static $defaults = [
'input_token' => null,
'output_token' => null,
'limit_key' => null,
'result_key' => null,
'more_results' => null,
];
if ($this->hasPaginator($name)) {
return $this->paginators[$name] + $defaults;
}
throw new \UnexpectedValueException("There is no {$name} "
. "paginator defined for the {$this->serviceName} service.");
}
/**
* Gets an associative array of available waiter configurations where the
* key is the name of the waiter, and the value is the waiter
* configuration.
*
* @return array
*/
public function getWaiters()
{
if (!isset($this->waiters)) {
$res = call_user_func(
$this->apiProvider,
'waiter',
$this->serviceName,
$this->apiVersion
);
$this->waiters = isset($res['waiters'])
? $res['waiters']
: [];
}
return $this->waiters;
}
/**
* Determines if the service has a waiter by name.
*
* @param string $name Name of the waiter.
*
* @return bool
*/
public function hasWaiter($name)
{
return isset($this->getWaiters()[$name]);
}
/**
* Get a waiter configuration by name.
*
* @param string $name Name of the waiter by name.
*
* @return array
* @throws \UnexpectedValueException if the waiter does not exist.
*/
public function getWaiterConfig($name)
{
// Error if the waiter is not defined
if ($this->hasWaiter($name)) {
return $this->waiters[$name];
}
throw new \UnexpectedValueException("There is no {$name} waiter "
. "defined for the {$this->serviceName} service.");
}
/**
* Get the shape map used by the API.
*
* @return ShapeMap
*/
public function getShapeMap()
{
return $this->shapeMap;
}
}
+69
View File
@@ -0,0 +1,69 @@
<?php
namespace Aws\Api;
/**
* Base class representing a modeled shape.
*/
class Shape extends AbstractModel
{
/**
* Get a concrete shape for the given definition.
*
* @param array $definition
* @param ShapeMap $shapeMap
*
* @return mixed
* @throws \RuntimeException if the type is invalid
*/
public static function create(array $definition, ShapeMap $shapeMap)
{
static $map = [
'structure' => 'Aws\Api\StructureShape',
'map' => 'Aws\Api\MapShape',
'list' => 'Aws\Api\ListShape',
'timestamp' => 'Aws\Api\TimestampShape',
'integer' => 'Aws\Api\Shape',
'double' => 'Aws\Api\Shape',
'float' => 'Aws\Api\Shape',
'long' => 'Aws\Api\Shape',
'string' => 'Aws\Api\Shape',
'byte' => 'Aws\Api\Shape',
'character' => 'Aws\Api\Shape',
'blob' => 'Aws\Api\Shape',
'boolean' => 'Aws\Api\Shape'
];
if (isset($definition['shape'])) {
return $shapeMap->resolve($definition);
}
if (!isset($map[$definition['type']])) {
throw new \RuntimeException('Invalid type: '
. print_r($definition, true));
}
$type = $map[$definition['type']];
return new $type($definition, $shapeMap);
}
/**
* Get the type of the shape
*
* @return string
*/
public function getType()
{
return $this->definition['type'];
}
/**
* Get the name of the shape
*
* @return string
*/
public function getName()
{
return $this->definition['name'];
}
}
+68
View File
@@ -0,0 +1,68 @@
<?php
namespace Aws\Api;
/**
* Builds shape based on shape references.
*/
class ShapeMap
{
/** @var array */
private $definitions;
/** @var Shape[] */
private $simple;
/**
* @param array $shapeModels Associative array of shape definitions.
*/
public function __construct(array $shapeModels)
{
$this->definitions = $shapeModels;
}
/**
* Get an array of shape names.
*
* @return array
*/
public function getShapeNames()
{
return array_keys($this->definitions);
}
/**
* Resolve a shape reference
*
* @param array $shapeRef Shape reference shape
*
* @return Shape
* @throws \InvalidArgumentException
*/
public function resolve(array $shapeRef)
{
$shape = $shapeRef['shape'];
if (!isset($this->definitions[$shape])) {
throw new \InvalidArgumentException('Shape not found: ' . $shape);
}
$isSimple = count($shapeRef) == 1;
if ($isSimple && isset($this->simple[$shape])) {
return $this->simple[$shape];
}
$definition = $shapeRef + $this->definitions[$shape];
$definition['name'] = $definition['shape'];
if (isset($definition['shape'])) {
unset($definition['shape']);
}
$result = Shape::create($definition, $this);
if ($isSimple) {
$this->simple[$shape] = $result;
}
return $result;
}
}
@@ -0,0 +1,79 @@
<?php
namespace Aws\Api;
/**
* Represents a structure shape and resolve member shape references.
*/
class StructureShape extends Shape
{
/**
* @var Shape[]
*/
private $members;
public function __construct(array $definition, ShapeMap $shapeMap)
{
$definition['type'] = 'structure';
if (!isset($definition['members'])) {
$definition['members'] = [];
}
parent::__construct($definition, $shapeMap);
}
/**
* Gets a list of all members
*
* @return Shape[]
*/
public function getMembers()
{
if (empty($this->members)) {
$this->generateMembersHash();
}
return $this->members;
}
/**
* Check if a specific member exists by name.
*
* @param string $name Name of the member to check
*
* @return bool
*/
public function hasMember($name)
{
return isset($this->definition['members'][$name]);
}
/**
* Retrieve a member by name.
*
* @param string $name Name of the member to retrieve
*
* @return Shape
* @throws \InvalidArgumentException if the member is not found.
*/
public function getMember($name)
{
$members = $this->getMembers();
if (!isset($members[$name])) {
throw new \InvalidArgumentException('Unknown member ' . $name);
}
return $members[$name];
}
private function generateMembersHash()
{
$this->members = [];
foreach ($this->definition['members'] as $name => $definition) {
$this->members[$name] = $this->shapeFor($definition);
}
}
}
@@ -0,0 +1,48 @@
<?php
namespace Aws\Api;
/**
* Represents a timestamp shape.
*/
class TimestampShape extends Shape
{
public function __construct(array $definition, ShapeMap $shapeMap)
{
$definition['type'] = 'timestamp';
parent::__construct($definition, $shapeMap);
}
/**
* Formats a timestamp value for a service.
*
* @param mixed $value Value to format
* @param string $format Format used to serialize the value
*
* @return int|string
* @throws \UnexpectedValueException if the format is unknown.
* @throws \InvalidArgumentException if the value is an unsupported type.
*/
public static function format($value, $format)
{
if ($value instanceof \DateTime) {
$value = $value->getTimestamp();
} elseif (is_string($value)) {
$value = strtotime($value);
} elseif (!is_int($value)) {
throw new \InvalidArgumentException('Unable to handle the provided'
. ' timestamp type: ' . gettype($value));
}
switch ($format) {
case 'iso8601':
return gmdate('Y-m-d\TH:i:s\Z', $value);
case 'rfc822':
return gmdate('D, d M Y H:i:s \G\M\T', $value);
case 'unixTimestamp':
return $value;
default:
throw new \UnexpectedValueException('Unknown timestamp format: '
. $format);
}
}
}
+286
View File
@@ -0,0 +1,286 @@
<?php
namespace Aws\Api;
use Aws;
/**
* Validates a schema against a hash of input.
*/
class Validator
{
private $path = [];
private $errors = [];
private $constraints = [];
private static $defaultConstraints = [
'required' => true,
'min' => true,
'max' => false,
'pattern' => false
];
/**
* @param array $constraints Associative array of constraints to enforce.
* Accepts the following keys: "required", "min",
* "max", and "pattern". If a key is not
* provided, the constraint will assume false.
*/
public function __construct(array $constraints = null)
{
static $assumedFalseValues = [
'required' => false,
'min' => false,
'max' => false,
'pattern' => false
];
$this->constraints = empty($constraints)
? self::$defaultConstraints
: $constraints + $assumedFalseValues;
}
/**
* Validates the given input against the schema.
*
* @param string $name Operation name
* @param Shape $shape Shape to validate
* @param array $input Input to validate
*
* @throws \InvalidArgumentException if the input is invalid.
*/
public function validate($name, Shape $shape, array $input)
{
$this->dispatch($shape, $input);
if ($this->errors) {
$message = sprintf(
"Found %d error%s while validating the input provided for the "
. "%s operation:\n%s",
count($this->errors),
count($this->errors) > 1 ? 's' : '',
$name,
implode("\n", $this->errors)
);
$this->errors = [];
throw new \InvalidArgumentException($message);
}
}
private function dispatch(Shape $shape, $value)
{
static $methods = [
'structure' => 'check_structure',
'list' => 'check_list',
'map' => 'check_map',
'blob' => 'check_blob',
'boolean' => 'check_boolean',
'integer' => 'check_numeric',
'float' => 'check_numeric',
'long' => 'check_numeric',
'string' => 'check_string',
'byte' => 'check_string',
'char' => 'check_string'
];
$type = $shape->getType();
if (isset($methods[$type])) {
$this->{$methods[$type]}($shape, $value);
}
}
private function check_structure(StructureShape $shape, $value)
{
if (!$this->checkAssociativeArray($value)) {
return;
}
if ($this->constraints['required'] && $shape['required']) {
foreach ($shape['required'] as $req) {
if (!isset($value[$req])) {
$this->path[] = $req;
$this->addError('is missing and is a required parameter');
array_pop($this->path);
}
}
}
foreach ($value as $name => $v) {
if ($shape->hasMember($name)) {
$this->path[] = $name;
$this->dispatch(
$shape->getMember($name),
isset($value[$name]) ? $value[$name] : null
);
array_pop($this->path);
}
}
}
private function check_list(ListShape $shape, $value)
{
if (!is_array($value)) {
$this->addError('must be an array. Found '
. Aws\describe_type($value));
return;
}
$this->validateRange($shape, count($value), "list element count");
$items = $shape->getMember();
foreach ($value as $index => $v) {
$this->path[] = $index;
$this->dispatch($items, $v);
array_pop($this->path);
}
}
private function check_map(MapShape $shape, $value)
{
if (!$this->checkAssociativeArray($value)) {
return;
}
$values = $shape->getValue();
foreach ($value as $key => $v) {
$this->path[] = $key;
$this->dispatch($values, $v);
array_pop($this->path);
}
}
private function check_blob(Shape $shape, $value)
{
static $valid = [
'string' => true,
'integer' => true,
'double' => true,
'resource' => true
];
$type = gettype($value);
if (!isset($valid[$type])) {
if ($type != 'object' || !method_exists($value, '__toString')) {
$this->addError('must be an fopen resource, a '
. 'GuzzleHttp\Stream\StreamInterface object, or something '
. 'that can be cast to a string. Found '
. Aws\describe_type($value));
}
}
}
private function check_numeric(Shape $shape, $value)
{
if (!is_numeric($value)) {
$this->addError('must be numeric. Found '
. Aws\describe_type($value));
return;
}
$this->validateRange($shape, $value, "numeric value");
}
private function check_boolean(Shape $shape, $value)
{
if (!is_bool($value)) {
$this->addError('must be a boolean. Found '
. Aws\describe_type($value));
}
}
private function check_string(Shape $shape, $value)
{
if ($shape['jsonvalue']) {
if (!self::canJsonEncode($value)) {
$this->addError('must be a value encodable with \'json_encode\'.'
. ' Found ' . Aws\describe_type($value));
}
return;
}
if (!$this->checkCanString($value)) {
$this->addError('must be a string or an object that implements '
. '__toString(). Found ' . Aws\describe_type($value));
return;
}
$this->validateRange($shape, strlen($value), "string length");
if ($this->constraints['pattern']) {
$pattern = $shape['pattern'];
if ($pattern && !preg_match("/$pattern/", $value)) {
$this->addError("Pattern /$pattern/ failed to match '$value'");
}
}
}
private function validateRange(Shape $shape, $length, $descriptor)
{
if ($this->constraints['min']) {
$min = $shape['min'];
if ($min && $length < $min) {
$this->addError("expected $descriptor to be >= $min, but "
. "found $descriptor of $length");
}
}
if ($this->constraints['max']) {
$max = $shape['max'];
if ($max && $length > $max) {
$this->addError("expected $descriptor to be <= $max, but "
. "found $descriptor of $length");
}
}
}
private function checkCanString($value)
{
static $valid = [
'string' => true,
'integer' => true,
'double' => true,
'NULL' => true,
];
$type = gettype($value);
return isset($valid[$type]) ||
($type == 'object' && method_exists($value, '__toString'));
}
private function checkAssociativeArray($value)
{
$isAssociative = false;
if (is_array($value)) {
$expectedIndex = 0;
$key = key($value);
do {
$isAssociative = $key !== $expectedIndex++;
next($value);
$key = key($value);
} while (!$isAssociative && null !== $key);
}
if (!$isAssociative) {
$this->addError('must be an associative array. Found '
. Aws\describe_type($value));
return false;
}
return true;
}
private function addError($message)
{
$this->errors[] =
implode('', array_map(function ($s) { return "[{$s}]"; }, $this->path))
. ' '
. $message;
}
private function canJsonEncode($data)
{
return !is_resource($data);
}
}
@@ -0,0 +1,272 @@
<?php
namespace Aws\ApiGateway;
use Aws\AwsClient;
use Aws\CommandInterface;
use Psr\Http\Message\RequestInterface;
/**
* This client is used to interact with the **AWS API Gateway** service.
*
* @method \Aws\Result createApiKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise createApiKeyAsync(array $args = [])
* @method \Aws\Result createAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise createAuthorizerAsync(array $args = [])
* @method \Aws\Result createBasePathMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise createBasePathMappingAsync(array $args = [])
* @method \Aws\Result createDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDeploymentAsync(array $args = [])
* @method \Aws\Result createDocumentationPart(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDocumentationPartAsync(array $args = [])
* @method \Aws\Result createDocumentationVersion(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDocumentationVersionAsync(array $args = [])
* @method \Aws\Result createDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDomainNameAsync(array $args = [])
* @method \Aws\Result createModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise createModelAsync(array $args = [])
* @method \Aws\Result createRequestValidator(array $args = [])
* @method \GuzzleHttp\Promise\Promise createRequestValidatorAsync(array $args = [])
* @method \Aws\Result createResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise createResourceAsync(array $args = [])
* @method \Aws\Result createRestApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise createRestApiAsync(array $args = [])
* @method \Aws\Result createStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise createStageAsync(array $args = [])
* @method \Aws\Result createUsagePlan(array $args = [])
* @method \GuzzleHttp\Promise\Promise createUsagePlanAsync(array $args = [])
* @method \Aws\Result createUsagePlanKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise createUsagePlanKeyAsync(array $args = [])
* @method \Aws\Result createVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise createVpcLinkAsync(array $args = [])
* @method \Aws\Result deleteApiKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteApiKeyAsync(array $args = [])
* @method \Aws\Result deleteAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAuthorizerAsync(array $args = [])
* @method \Aws\Result deleteBasePathMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteBasePathMappingAsync(array $args = [])
* @method \Aws\Result deleteClientCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteClientCertificateAsync(array $args = [])
* @method \Aws\Result deleteDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDeploymentAsync(array $args = [])
* @method \Aws\Result deleteDocumentationPart(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDocumentationPartAsync(array $args = [])
* @method \Aws\Result deleteDocumentationVersion(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDocumentationVersionAsync(array $args = [])
* @method \Aws\Result deleteDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDomainNameAsync(array $args = [])
* @method \Aws\Result deleteGatewayResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteGatewayResponseAsync(array $args = [])
* @method \Aws\Result deleteIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteIntegrationAsync(array $args = [])
* @method \Aws\Result deleteIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteIntegrationResponseAsync(array $args = [])
* @method \Aws\Result deleteMethod(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteMethodAsync(array $args = [])
* @method \Aws\Result deleteMethodResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteMethodResponseAsync(array $args = [])
* @method \Aws\Result deleteModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteModelAsync(array $args = [])
* @method \Aws\Result deleteRequestValidator(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRequestValidatorAsync(array $args = [])
* @method \Aws\Result deleteResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteResourceAsync(array $args = [])
* @method \Aws\Result deleteRestApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRestApiAsync(array $args = [])
* @method \Aws\Result deleteStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteStageAsync(array $args = [])
* @method \Aws\Result deleteUsagePlan(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteUsagePlanAsync(array $args = [])
* @method \Aws\Result deleteUsagePlanKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteUsagePlanKeyAsync(array $args = [])
* @method \Aws\Result deleteVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteVpcLinkAsync(array $args = [])
* @method \Aws\Result flushStageAuthorizersCache(array $args = [])
* @method \GuzzleHttp\Promise\Promise flushStageAuthorizersCacheAsync(array $args = [])
* @method \Aws\Result flushStageCache(array $args = [])
* @method \GuzzleHttp\Promise\Promise flushStageCacheAsync(array $args = [])
* @method \Aws\Result generateClientCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise generateClientCertificateAsync(array $args = [])
* @method \Aws\Result getAccount(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAccountAsync(array $args = [])
* @method \Aws\Result getApiKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise getApiKeyAsync(array $args = [])
* @method \Aws\Result getApiKeys(array $args = [])
* @method \GuzzleHttp\Promise\Promise getApiKeysAsync(array $args = [])
* @method \Aws\Result getAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAuthorizerAsync(array $args = [])
* @method \Aws\Result getAuthorizers(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAuthorizersAsync(array $args = [])
* @method \Aws\Result getBasePathMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBasePathMappingAsync(array $args = [])
* @method \Aws\Result getBasePathMappings(array $args = [])
* @method \GuzzleHttp\Promise\Promise getBasePathMappingsAsync(array $args = [])
* @method \Aws\Result getClientCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getClientCertificateAsync(array $args = [])
* @method \Aws\Result getClientCertificates(array $args = [])
* @method \GuzzleHttp\Promise\Promise getClientCertificatesAsync(array $args = [])
* @method \Aws\Result getDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDeploymentAsync(array $args = [])
* @method \Aws\Result getDeployments(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDeploymentsAsync(array $args = [])
* @method \Aws\Result getDocumentationPart(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDocumentationPartAsync(array $args = [])
* @method \Aws\Result getDocumentationParts(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDocumentationPartsAsync(array $args = [])
* @method \Aws\Result getDocumentationVersion(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDocumentationVersionAsync(array $args = [])
* @method \Aws\Result getDocumentationVersions(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDocumentationVersionsAsync(array $args = [])
* @method \Aws\Result getDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDomainNameAsync(array $args = [])
* @method \Aws\Result getDomainNames(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDomainNamesAsync(array $args = [])
* @method \Aws\Result getExport(array $args = [])
* @method \GuzzleHttp\Promise\Promise getExportAsync(array $args = [])
* @method \Aws\Result getGatewayResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise getGatewayResponseAsync(array $args = [])
* @method \Aws\Result getGatewayResponses(array $args = [])
* @method \GuzzleHttp\Promise\Promise getGatewayResponsesAsync(array $args = [])
* @method \Aws\Result getIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise getIntegrationAsync(array $args = [])
* @method \Aws\Result getIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise getIntegrationResponseAsync(array $args = [])
* @method \Aws\Result getMethod(array $args = [])
* @method \GuzzleHttp\Promise\Promise getMethodAsync(array $args = [])
* @method \Aws\Result getMethodResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise getMethodResponseAsync(array $args = [])
* @method \Aws\Result getModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise getModelAsync(array $args = [])
* @method \Aws\Result getModelTemplate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getModelTemplateAsync(array $args = [])
* @method \Aws\Result getModels(array $args = [])
* @method \GuzzleHttp\Promise\Promise getModelsAsync(array $args = [])
* @method \Aws\Result getRequestValidator(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRequestValidatorAsync(array $args = [])
* @method \Aws\Result getRequestValidators(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRequestValidatorsAsync(array $args = [])
* @method \Aws\Result getResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise getResourceAsync(array $args = [])
* @method \Aws\Result getResources(array $args = [])
* @method \GuzzleHttp\Promise\Promise getResourcesAsync(array $args = [])
* @method \Aws\Result getRestApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRestApiAsync(array $args = [])
* @method \Aws\Result getRestApis(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRestApisAsync(array $args = [])
* @method \Aws\Result getSdk(array $args = [])
* @method \GuzzleHttp\Promise\Promise getSdkAsync(array $args = [])
* @method \Aws\Result getSdkType(array $args = [])
* @method \GuzzleHttp\Promise\Promise getSdkTypeAsync(array $args = [])
* @method \Aws\Result getSdkTypes(array $args = [])
* @method \GuzzleHttp\Promise\Promise getSdkTypesAsync(array $args = [])
* @method \Aws\Result getStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise getStageAsync(array $args = [])
* @method \Aws\Result getStages(array $args = [])
* @method \GuzzleHttp\Promise\Promise getStagesAsync(array $args = [])
* @method \Aws\Result getTags(array $args = [])
* @method \GuzzleHttp\Promise\Promise getTagsAsync(array $args = [])
* @method \Aws\Result getUsage(array $args = [])
* @method \GuzzleHttp\Promise\Promise getUsageAsync(array $args = [])
* @method \Aws\Result getUsagePlan(array $args = [])
* @method \GuzzleHttp\Promise\Promise getUsagePlanAsync(array $args = [])
* @method \Aws\Result getUsagePlanKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise getUsagePlanKeyAsync(array $args = [])
* @method \Aws\Result getUsagePlanKeys(array $args = [])
* @method \GuzzleHttp\Promise\Promise getUsagePlanKeysAsync(array $args = [])
* @method \Aws\Result getUsagePlans(array $args = [])
* @method \GuzzleHttp\Promise\Promise getUsagePlansAsync(array $args = [])
* @method \Aws\Result getVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise getVpcLinkAsync(array $args = [])
* @method \Aws\Result getVpcLinks(array $args = [])
* @method \GuzzleHttp\Promise\Promise getVpcLinksAsync(array $args = [])
* @method \Aws\Result importApiKeys(array $args = [])
* @method \GuzzleHttp\Promise\Promise importApiKeysAsync(array $args = [])
* @method \Aws\Result importDocumentationParts(array $args = [])
* @method \GuzzleHttp\Promise\Promise importDocumentationPartsAsync(array $args = [])
* @method \Aws\Result importRestApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise importRestApiAsync(array $args = [])
* @method \Aws\Result putGatewayResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise putGatewayResponseAsync(array $args = [])
* @method \Aws\Result putIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise putIntegrationAsync(array $args = [])
* @method \Aws\Result putIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise putIntegrationResponseAsync(array $args = [])
* @method \Aws\Result putMethod(array $args = [])
* @method \GuzzleHttp\Promise\Promise putMethodAsync(array $args = [])
* @method \Aws\Result putMethodResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise putMethodResponseAsync(array $args = [])
* @method \Aws\Result putRestApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise putRestApiAsync(array $args = [])
* @method \Aws\Result tagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
* @method \Aws\Result testInvokeAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise testInvokeAuthorizerAsync(array $args = [])
* @method \Aws\Result testInvokeMethod(array $args = [])
* @method \GuzzleHttp\Promise\Promise testInvokeMethodAsync(array $args = [])
* @method \Aws\Result untagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
* @method \Aws\Result updateAccount(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateAccountAsync(array $args = [])
* @method \Aws\Result updateApiKey(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateApiKeyAsync(array $args = [])
* @method \Aws\Result updateAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateAuthorizerAsync(array $args = [])
* @method \Aws\Result updateBasePathMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateBasePathMappingAsync(array $args = [])
* @method \Aws\Result updateClientCertificate(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateClientCertificateAsync(array $args = [])
* @method \Aws\Result updateDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDeploymentAsync(array $args = [])
* @method \Aws\Result updateDocumentationPart(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDocumentationPartAsync(array $args = [])
* @method \Aws\Result updateDocumentationVersion(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDocumentationVersionAsync(array $args = [])
* @method \Aws\Result updateDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDomainNameAsync(array $args = [])
* @method \Aws\Result updateGatewayResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateGatewayResponseAsync(array $args = [])
* @method \Aws\Result updateIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateIntegrationAsync(array $args = [])
* @method \Aws\Result updateIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateIntegrationResponseAsync(array $args = [])
* @method \Aws\Result updateMethod(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateMethodAsync(array $args = [])
* @method \Aws\Result updateMethodResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateMethodResponseAsync(array $args = [])
* @method \Aws\Result updateModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateModelAsync(array $args = [])
* @method \Aws\Result updateRequestValidator(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateRequestValidatorAsync(array $args = [])
* @method \Aws\Result updateResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateResourceAsync(array $args = [])
* @method \Aws\Result updateRestApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateRestApiAsync(array $args = [])
* @method \Aws\Result updateStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateStageAsync(array $args = [])
* @method \Aws\Result updateUsage(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateUsageAsync(array $args = [])
* @method \Aws\Result updateUsagePlan(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateUsagePlanAsync(array $args = [])
* @method \Aws\Result updateVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateVpcLinkAsync(array $args = [])
*/
class ApiGatewayClient extends AwsClient
{
public function __construct(array $args)
{
parent::__construct($args);
$stack = $this->getHandlerList();
$stack->appendBuild([__CLASS__, '_add_accept_header']);
}
public static function _add_accept_header(callable $handler)
{
return function (
CommandInterface $command,
RequestInterface $request
) use ($handler) {
$request = $request->withHeader('Accept', 'application/json');
return $handler($command, $request);
};
}
}
@@ -0,0 +1,9 @@
<?php
namespace Aws\ApiGateway\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AWS API Gateway** service.
*/
class ApiGatewayException extends AwsException {}
@@ -0,0 +1,15 @@
<?php
namespace Aws\ApiGatewayManagementApi;
use Aws\AwsClient;
/**
* This client is used to interact with the **AmazonApiGatewayManagementApi** service.
* @method \Aws\Result deleteConnection(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteConnectionAsync(array $args = [])
* @method \Aws\Result getConnection(array $args = [])
* @method \GuzzleHttp\Promise\Promise getConnectionAsync(array $args = [])
* @method \Aws\Result postToConnection(array $args = [])
* @method \GuzzleHttp\Promise\Promise postToConnectionAsync(array $args = [])
*/
class ApiGatewayManagementApiClient extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\ApiGatewayManagementApi\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AmazonApiGatewayManagementApi** service.
*/
class ApiGatewayManagementApiException extends AwsException {}
@@ -0,0 +1,153 @@
<?php
namespace Aws\ApiGatewayV2;
use Aws\AwsClient;
/**
* This client is used to interact with the **AmazonApiGatewayV2** service.
* @method \Aws\Result createApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise createApiAsync(array $args = [])
* @method \Aws\Result createApiMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise createApiMappingAsync(array $args = [])
* @method \Aws\Result createAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise createAuthorizerAsync(array $args = [])
* @method \Aws\Result createDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDeploymentAsync(array $args = [])
* @method \Aws\Result createDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise createDomainNameAsync(array $args = [])
* @method \Aws\Result createIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise createIntegrationAsync(array $args = [])
* @method \Aws\Result createIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise createIntegrationResponseAsync(array $args = [])
* @method \Aws\Result createModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise createModelAsync(array $args = [])
* @method \Aws\Result createRoute(array $args = [])
* @method \GuzzleHttp\Promise\Promise createRouteAsync(array $args = [])
* @method \Aws\Result createRouteResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise createRouteResponseAsync(array $args = [])
* @method \Aws\Result createStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise createStageAsync(array $args = [])
* @method \Aws\Result createVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise createVpcLinkAsync(array $args = [])
* @method \Aws\Result deleteAccessLogSettings(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAccessLogSettingsAsync(array $args = [])
* @method \Aws\Result deleteApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteApiAsync(array $args = [])
* @method \Aws\Result deleteApiMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteApiMappingAsync(array $args = [])
* @method \Aws\Result deleteAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteAuthorizerAsync(array $args = [])
* @method \Aws\Result deleteCorsConfiguration(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteCorsConfigurationAsync(array $args = [])
* @method \Aws\Result deleteDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDeploymentAsync(array $args = [])
* @method \Aws\Result deleteDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteDomainNameAsync(array $args = [])
* @method \Aws\Result deleteIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteIntegrationAsync(array $args = [])
* @method \Aws\Result deleteIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteIntegrationResponseAsync(array $args = [])
* @method \Aws\Result deleteModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteModelAsync(array $args = [])
* @method \Aws\Result deleteRoute(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRouteAsync(array $args = [])
* @method \Aws\Result deleteRouteRequestParameter(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRouteRequestParameterAsync(array $args = [])
* @method \Aws\Result deleteRouteResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRouteResponseAsync(array $args = [])
* @method \Aws\Result deleteRouteSettings(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteRouteSettingsAsync(array $args = [])
* @method \Aws\Result deleteStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteStageAsync(array $args = [])
* @method \Aws\Result deleteVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise deleteVpcLinkAsync(array $args = [])
* @method \Aws\Result exportApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise exportApiAsync(array $args = [])
* @method \Aws\Result resetAuthorizersCache(array $args = [])
* @method \GuzzleHttp\Promise\Promise resetAuthorizersCacheAsync(array $args = [])
* @method \Aws\Result getApiResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise getApiResourceAsync(array $args = [])
* @method \Aws\Result getApiMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise getApiMappingAsync(array $args = [])
* @method \Aws\Result getApiMappings(array $args = [])
* @method \GuzzleHttp\Promise\Promise getApiMappingsAsync(array $args = [])
* @method \Aws\Result getApis(array $args = [])
* @method \GuzzleHttp\Promise\Promise getApisAsync(array $args = [])
* @method \Aws\Result getAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAuthorizerAsync(array $args = [])
* @method \Aws\Result getAuthorizers(array $args = [])
* @method \GuzzleHttp\Promise\Promise getAuthorizersAsync(array $args = [])
* @method \Aws\Result getDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDeploymentAsync(array $args = [])
* @method \Aws\Result getDeployments(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDeploymentsAsync(array $args = [])
* @method \Aws\Result getDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDomainNameAsync(array $args = [])
* @method \Aws\Result getDomainNames(array $args = [])
* @method \GuzzleHttp\Promise\Promise getDomainNamesAsync(array $args = [])
* @method \Aws\Result getIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise getIntegrationAsync(array $args = [])
* @method \Aws\Result getIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise getIntegrationResponseAsync(array $args = [])
* @method \Aws\Result getIntegrationResponses(array $args = [])
* @method \GuzzleHttp\Promise\Promise getIntegrationResponsesAsync(array $args = [])
* @method \Aws\Result getIntegrations(array $args = [])
* @method \GuzzleHttp\Promise\Promise getIntegrationsAsync(array $args = [])
* @method \Aws\Result getModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise getModelAsync(array $args = [])
* @method \Aws\Result getModelTemplate(array $args = [])
* @method \GuzzleHttp\Promise\Promise getModelTemplateAsync(array $args = [])
* @method \Aws\Result getModels(array $args = [])
* @method \GuzzleHttp\Promise\Promise getModelsAsync(array $args = [])
* @method \Aws\Result getRoute(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRouteAsync(array $args = [])
* @method \Aws\Result getRouteResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRouteResponseAsync(array $args = [])
* @method \Aws\Result getRouteResponses(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRouteResponsesAsync(array $args = [])
* @method \Aws\Result getRoutes(array $args = [])
* @method \GuzzleHttp\Promise\Promise getRoutesAsync(array $args = [])
* @method \Aws\Result getStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise getStageAsync(array $args = [])
* @method \Aws\Result getStages(array $args = [])
* @method \GuzzleHttp\Promise\Promise getStagesAsync(array $args = [])
* @method \Aws\Result getTags(array $args = [])
* @method \GuzzleHttp\Promise\Promise getTagsAsync(array $args = [])
* @method \Aws\Result getVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise getVpcLinkAsync(array $args = [])
* @method \Aws\Result getVpcLinks(array $args = [])
* @method \GuzzleHttp\Promise\Promise getVpcLinksAsync(array $args = [])
* @method \Aws\Result importApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise importApiAsync(array $args = [])
* @method \Aws\Result reimportApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise reimportApiAsync(array $args = [])
* @method \Aws\Result tagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
* @method \Aws\Result untagResource(array $args = [])
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
* @method \Aws\Result updateApi(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateApiAsync(array $args = [])
* @method \Aws\Result updateApiMapping(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateApiMappingAsync(array $args = [])
* @method \Aws\Result updateAuthorizer(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateAuthorizerAsync(array $args = [])
* @method \Aws\Result updateDeployment(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDeploymentAsync(array $args = [])
* @method \Aws\Result updateDomainName(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateDomainNameAsync(array $args = [])
* @method \Aws\Result updateIntegration(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateIntegrationAsync(array $args = [])
* @method \Aws\Result updateIntegrationResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateIntegrationResponseAsync(array $args = [])
* @method \Aws\Result updateModel(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateModelAsync(array $args = [])
* @method \Aws\Result updateRoute(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateRouteAsync(array $args = [])
* @method \Aws\Result updateRouteResponse(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateRouteResponseAsync(array $args = [])
* @method \Aws\Result updateStage(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateStageAsync(array $args = [])
* @method \Aws\Result updateVpcLink(array $args = [])
* @method \GuzzleHttp\Promise\Promise updateVpcLinkAsync(array $args = [])
*/
class ApiGatewayV2Client extends AwsClient {}
@@ -0,0 +1,9 @@
<?php
namespace Aws\ApiGatewayV2\Exception;
use Aws\Exception\AwsException;
/**
* Represents an error interacting with the **AmazonApiGatewayV2** service.
*/
class ApiGatewayV2Exception extends AwsException {}

Some files were not shown because too many files have changed in this diff Show More