Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107857 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 45323 invoked from network); 25 Nov 2019 20:11:54 -0000 Received: from unknown (HELO php-smtp3.php.net) (208.43.231.12) by pb1.pair.com with SMTP; 25 Nov 2019 20:11:54 -0000 Received: from php-smtp3.php.net (localhost [127.0.0.1]) by php-smtp3.php.net (Postfix) with ESMTP id 145562D19BE for ; Mon, 25 Nov 2019 10:06:22 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp3.php.net X-Spam-Level: X-Spam-Status: No, score=0.5 required=5.0 tests=BAYES_05,DKIM_SIGNED, DKIM_VALID,FORGED_SPF_HELO,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS8075 40.64.0.0/10 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) Received: from NAM05-DM3-obe.outbound.protection.outlook.com (mail-eopbgr730077.outbound.protection.outlook.com [40.107.73.77]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp3.php.net (Postfix) with ESMTPS for ; Mon, 25 Nov 2019 10:06:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=oTOzENE3knNdFYhRdjDB1qLPYP2zFxYn/dW2/fhPH7jFCDMEb/XngzVUOgrELapknahnGYquLqfWTVAwuBA5AQf89tNBvR+EH9m26rLrFReJAVt77RUMejLcpRsWAGOtM3KB2SMzDV+bqfQaXR8KG2RtuIeLOXahJb5FKY2vzNz5j2IMS+u1oQ7WbK3RHSxUvMKgRQtwbpvtK7Dz1aex2nSNASDVXOjUGcHmhyGkimhSIn76bz3zvLAbeTZpV+5lMOahr3JX/IGtSM5rk78D6DSNEJlA/cGJsoCavse5N7gOZ32/1U6o1JuIzKOHgdlCdQ/l/miiETVPst2uLdrhUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+zr9Yc/Ifx6g4SPWYe1eTCtRs+bAVFapyFz89x9651g=; b=ntZ5hUTNoBnVtu99OJnFKvL0WbwFyYpRAYKA55w5V6zKLQ4pqyzAvNgkaDiHzplxLJUcA9IiIeGHTaUW/9tlWXi0/ZCfKovLkPAN3KlQt8Ty4HHa3DxtWNjVDw8/KBCT1FF0tA4Q4Uvds5Zmg3tVuWbF2jzeHjJyKVWhR2HZGvKJ4Pbf+JePtzaI1+8DdDaeZB7BH595Cx6yYwpXFObetMsOBZrkm5q0FbLwprHeFqDfd/ynDlfhIJRj6BWfJS52qH4ULJqZo2vRSokigRAqjCmyrtHKm9ECG6G9M60T2g336g7rc/IGeOBp/1CZKr9jneeyYMkoEiIZ3gLuy+Gt+A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=onlinecommercegroup.com; dmarc=pass action=none header.from=onlinecommercegroup.com; dkim=pass header.d=onlinecommercegroup.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=appriver3651009564.onmicrosoft.com; s=selector2-appriver3651009564-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=+zr9Yc/Ifx6g4SPWYe1eTCtRs+bAVFapyFz89x9651g=; b=MHesD0/KinWUDCtVOtdSm1tTmlZPxE34wGF41aSQgOrjifgAYdEP8L1/rF68l+i1tElqFAXJQrxKL0PrSe5gac1qsze6QUeSSLxmehqOJJYaOhO9DYmHdKDrxTHMDv6CETclBecyKtkzheEFGNM+b/bup8jNGRfmBHt6mGUW9I0= Received: from MN2PR18MB2589.namprd18.prod.outlook.com (20.179.82.96) by MN2PR18MB2527.namprd18.prod.outlook.com (20.179.82.202) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2474.17; Mon, 25 Nov 2019 18:06:19 +0000 Received: from MN2PR18MB2589.namprd18.prod.outlook.com ([fe80::40e7:a14f:b07:9bae]) by MN2PR18MB2589.namprd18.prod.outlook.com ([fe80::40e7:a14f:b07:9bae%4]) with mapi id 15.20.2474.023; Mon, 25 Nov 2019 18:06:19 +0000 To: "internals@lists.php.net" Thread-Topic: mysqli needs a method to bind a single parameter Thread-Index: AdWjuwjZuAEPM+p8S7ag150DgwV5aw== Date: Mon, 25 Nov 2019 18:06:18 +0000 Message-ID: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: spf=none (sender IP is ) smtp.mailfrom=Joel.Hutchinson@onlinecommercegroup.com; x-originating-ip: [71.12.136.26] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 2d96dd17-2c75-4f97-d3a9-08d771d22c68 x-ms-traffictypediagnostic: MN2PR18MB2527: x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:9508; x-forefront-prvs: 0232B30BBC x-forefront-antispam-report: SFV:NSPM;SFS:(10009020)(136003)(396003)(376002)(39830400003)(346002)(366004)(189003)(199004)(6306002)(54896002)(71200400001)(71190400001)(9686003)(5640700003)(55016002)(6916009)(6436002)(7696005)(102836004)(561944003)(6506007)(26005)(186003)(508600001)(14444005)(256004)(25786009)(86362001)(33656002)(14454004)(2501003)(81166006)(81156014)(8676002)(52536014)(5660300002)(74316002)(7736002)(66476007)(66556008)(64756008)(66446008)(66946007)(76116006)(1730700003)(8936002)(2351001)(6116002)(790700001)(3846002)(316002)(99286004)(2906002)(66066001);DIR:OUT;SFP:1101;SCL:1;SRVR:MN2PR18MB2527;H:MN2PR18MB2589.namprd18.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;MX:1;A:1; received-spf: None (protection.outlook.com: onlinecommercegroup.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: ock+QYrB6GsyCsNN1oK339Vm3EV2fst5+rB3JCdihXhN7IfRLjV5ZMx/UXaNePL2GZynEHvbfWyBra+lDelrM0RKAONVAVuaaRnfDFHoGbW/3QnmzJZfvRN4QoClbMoZ8kX75HHaDwcnDw8f86xT7J6cGYlW7VqQgjzOU6MkNhlWXlIzB2VMqyEzMZ28Y5HG8RTl9jzqeeusneNmwpDqjwRoaOyXEWF4zZcuOejbKOzSceh9NP7gPDWCvD9b/1hfrADcjv4WSFK0NREb6BhtWddiSebku0ZShDf0X3fE8SHMUVKSHa2M+BKqozUaJBQaLfutIBHUr4wvVYGoqe277J7PuBq64SaUeNRYIuFojnPXOeadJKrMGjItfng4quwTgfu7EZngqYDOHAhP1OK7909wbTFiOkZCSVc8MUjxmJBKpiAlpx+oJWRcd1XMLetg x-ms-exchange-transport-forked: True Content-Type: multipart/alternative; boundary="_000_MN2PR18MB25894DE93EF773D3CF05B28AED4A0MN2PR18MB2589namp_" MIME-Version: 1.0 X-OriginatorOrg: onlinecommercegroup.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2d96dd17-2c75-4f97-d3a9-08d771d22c68 X-MS-Exchange-CrossTenant-originalarrivaltime: 25 Nov 2019 18:06:18.9347 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 733bee1d-43aa-48a2-a713-34870bf1749b X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: VChAykFpPh5AaIZzfMxffLLE+cM3L7n8JiR3hWpMG8sAB0vvoF0angwptTzsqveh X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR18MB2527 X-Envelope-From: Subject: mysqli needs a method to bind a single parameter From: Joel.Hutchinson@onlinecommercegroup.com (Joel Hutchinson) --_000_MN2PR18MB25894DE93EF773D3CF05B28AED4A0MN2PR18MB2589namp_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Prepared statements have become more important of late. By breaking a query= into instructions and data, we avoid the problem of SQL injection. While M= ySQLi supports prepared statements, it has a structural deficiency that PDO= does not share. MySQLi does not support binding parameters separately. Consider the following query (which we will put into a variable called $sql= ) INSERT INTO db.visits(page, ip) VALUES(?, ?) Within PDO we can do the following $stmt =3D $db->prepare($sql); $stmt->bindParam(1, $page, PDO::PARAM_STR); $stmt->bindParam(2, $ip, PDO::PARAM_STR); MySQLi takes a different approach, by binding all the parameters at the sam= e time (and mandating that they be passed by reference) $stmt =3D $db->prepare($sql); $stmt->bind_param('ss', $page, $ip); This is functional, but only for smaller queries. As the parameter list gro= ws, this methodology becomes unwieldy $stmt->bind_param('ssssisssid', $name, $company, $billing_addr, $billing_ci= ty, $billing_state, $billing_zip...); Not only is hard to maintain (you have to manually count parameters if you = get an error), it also introduces a structural problem, in that if we want = a conditional query and parameters, we have to get even more unwieldy $sql =3D 'SELECT name FROM db.customer WHERE record_id =3D ?'; $params =3D 'i'; $data =3D [&$_GET['record_id']]; if(isset($_GET['zip'])) { $params .=3D 's'; $data[] =3D &$_GET['zip']; $sql .=3D ' AND billing_zip =3D ?'; } // The first argument for mysqli_stmt_bind_param must be the data type list array_unshift($params, $data); $stmt =3D $db->prepare($sql); call_user_func_array([$stmt, 'bind_param'], $data); $stmt->execute(); PDO manages to make this work much more elegantly $sql =3D 'SELECT name FROM db.customer WHERE record_id =3D ?'; if(isset($_GET['zip'])) $sql .=3D ' AND billing_zip =3D ?'; $stmt =3D $db->prepare($sql); $stmt->bindParam(1, $_GET['record_id'], PDO::PARAM_INT); if(isset($_GET['zip'])) $stmt->bindParam(2, $_GET['zip'], PDO::PARAM_STR); $stmt->execute(); It's clear the MySQLi interface lags behind PDO here, yet still remains a s= taple in PHP. Many projects dutifully switched from the removed MySQL inter= face, yet, due to these issues, they still write procedural code to generat= e SQL because it's easier to simply escape the data and understand the code= , than it is to work these extra layers in to secure their queries with pre= pared statements. MySQLi desparately needs a single bind like PDO has. I would propose a new = function, named mysqli_stmt_bind_single. Reusing the PDO query above with p= roposed syntax $stmt =3D $db->prepare($sql); $stmt->bind_single('i', $_GET['record_id'], 1); if(isset($_GET['zip'])) $stmt->bind_single('s', $_GET['zip'], 2); $stmt->execute(); This proposal would leave the previous mysqli_stmt_bind_param mostly untouc= hed. Instead, the two could be used in tandem $sql =3D 'SELECT name FROM db.customer WHERE record_id =3D ? AND shipping_z= ip =3D ?'; if(isset($_GET['zip'])) $sql .=3D ' AND billing_zip =3D ?'; $stmt =3D $db->prepare($sql); $stmt->bind_param('is', $_GET['record_id'], $_GET['shipping_zip']); if(isset($_GET['zip'])) $stmt->bind_single('s', $_GET['billing_zip'], 3); $stmt->execute(); This necessitates a small change to mysqli_stmt_bind_param, in that the cur= rent function has a parameter check to ensure that the number of binds matc= hes the number of parameters in the query (or else it emits an E_WARNING). = That check would have to move to mysqli_stmt_execute, if it is still to be = performed. public mysqli_stmt::bind_single( mixed type, mixed $var [, int $position]) = : bool $position can be omitted, and it will take the next spot in the internal da= ta array. Passing an invalid postion would emit an E_WARNING. $postion can = overwrite an existing value silently, with a final check coming on the call= of mysqli_stmt_execute, as described above. This is how PDO operates now. --_000_MN2PR18MB25894DE93EF773D3CF05B28AED4A0MN2PR18MB2589namp_--