Showing posts with label HTML. Show all posts
Showing posts with label HTML. Show all posts

Thursday, 9 June 2022

Integrating Google Cloud reCAPTCHA Enterprise in PHP

Google Cloud reCAPTCHA Enterprise is the successor (?) to reCAPTCHA v3. 

The code snippets Google supplies for integrating reCATPCHA Enterprise in PHP are frustratingly uncohesive and neither a working demo or complete code sample exists (as far as I can find at the time of writing). 

Moreover, the code snippets that are provided were incomplete for my implementation and the number of moving parts (Cloud projects, keys and credentials) is nothing short of overwhelming. 

Given the above, I struggled for some time just get everything working--which is where I'm up to now. So a disclaimer for those of you readers who are proficient PHP developers and who possess a deeper understanding of the Google Cloud Platform, please use this as a starting point only. There may be a better (more refined) approach. 

In terms of the official documentation and the code snippets I refer to above and will discuss in this post, start here: https://cloud.google.com/recaptcha-enterprise/docs/choose-key-type

I should also note I'm working in a basic web hosting environment with PHP installed. It's not a Google environment--think more budget web host ;)

Setup

Before you can get started, you'll need to login to the Google Cloud Platform, create a new project if you don't have a suitable already, and create a reCAPTCHA Enterprise key. Save the key somewhere and take note of your Cloud project ID while you're there as we'll need that later. You'll find your project ID on the relevant dashboard card. 

Incidentally, you can follow the link to reCAPTCHA Enterprise in the documentation to get to where you need to be in the Google Cloud Platform (or just navigate to Menu > Security > reCAPTCHA Enterprise). 

Once that's done, you may want to hop into Menu > APIs and services. If the reCAPTCHA Enterprise API isn't already enabled, find it in the library and enable it. While you're here, you'll also want to create credentials. This is where things are still a bit blurry for me but I created both an API key and a service account. The API key isn't used in my final code and it's possibly not necessary. I'm just used to API keys, I guess! 

The service account basically receives a name and ID and is then assigned the reCAPTCHA Agent role (locate reCAPTCAHA Enterprise in the list of products and services and then select the reCAPTCHA Agent role). 

Once the service account exists, I chose to create a key ("Manage keys"). Google will warn you about the risks of downloading service account keys and suggests using Workload Identity Federation--I don't yet know what this is so do you own homework here. I created a new key (ADD KEY > Create new key) as a .json file--you'll be prompted to download/save this file and I'd suggest storing a copy in a safe place as I have yet to find a way to download this same file again in future. 

Code

With that setup done, we now move into the code. The code runs clients side and server side and is comprised of your HTML page (including a form), a couple of scripts in the HEAD tag and some attributes on the form button. And of course the PHP code. 

Be sure to add your reCAPTCHA Enterprise key to both the script tag in the head and the data-sitekey attribute on your button. It's also required in the call to create_assessment() in the PHP code. 

I'll point out that, in my case, I want to trigger a score-based reCAPTCHA assessment when a user submits a form--no sooner and not unecessarily. I'm therefore using the relevant Google examples here, combined into a single, cohesive file. 

The HTML and script source is taken from this page: https://cloud.google.com/recaptcha-enterprise/docs/instrument-web-pages 


Note the PHP code is slightly modified to include the putenv call, which references the JSON key file we created earlier. You'll also want to drop in your Google Cloud Platform project ID in the call to create_assessment(). 

<html>
<head>
	<script src="https://www.google.com/recaptcha/enterprise.js?render=your_recaptcha_key"></script>
	<script>
	   function onSubmit(token) {
		 document.getElementById("demo-form").submit();
	   }
	</script>
</head>
<body>
<form id="demo-form" method="post">
<input type="text" />
<button class="g-recaptcha"
data-sitekey="your_recaptcha_key"
data-callback='onSubmit'
data-action='submit'>Submit</button>
</form>
</body>
</html>

<?php

require 'google-re/vendor/autoload.php';

use Google\Cloud\RecaptchaEnterprise\V1\RecaptchaEnterpriseServiceClient;
use Google\Cloud\RecaptchaEnterprise\V1\Event;
use Google\Cloud\RecaptchaEnterprise\V1\Assessment;
use Google\Cloud\RecaptchaEnterprise\V1\TokenProperties\InvalidReason;

/**
* Create an assessment to analyze the risk of a UI action.
* @param string $siteKey The key ID for the reCAPTCHA key (See https://cloud.google.com/recaptcha-enterprise/docs/create-key)
* @param string $token The user's response token for which you want to receive a reCAPTCHA score. (See https://cloud.google.com/recaptcha-enterprise/docs/create-assessment#retrieve_token)
* @param string $project Your Google Cloud project ID
*/
function create_assessment(
  string $siteKey,
  string $token,
  string $project
): void {
	
  // *** I added this line ***
  putenv('GOOGLE_APPLICATION_CREDENTIALS=your-service-account-key-file.json');
    
  // TODO: To avoid memory issues, move this client generation outside
  // of this example, and cache it (recommended) or call client.close()
  // before exiting this method.
  $client = new RecaptchaEnterpriseServiceClient();

  $projectName = $client->projectName($project);

  $event = (new Event())
	  ->setSiteKey($siteKey)
	  ->setToken($token);

  $assessment = (new Assessment())
	  ->setEvent($event);

  try {
	  $response = $client->createAssessment(
		  $projectName,
		  $assessment
	  );

	  // You can use the score only if the assessment is valid,
	  // In case of failures like re-submitting the same token, getValid() will return false
	  if ($response->getTokenProperties()->getValid() == false) {
		  printf('The CreateAssessment() call failed because the token was invalid for the following reason: ');
		  printf(InvalidReason::name($response->getTokenProperties()->getInvalidReason()));
	  } else {
		  printf('The score for the protection action is:');
		  printf($response->getRiskAnalysis()->getScore());

		  // Optional: You can use the following methods to get more data about the token
		  // Action name provided at token generation.
		  // printf($response->getTokenProperties()->getAction() . PHP_EOL);
		  // The timestamp corresponding to the generation of the token.
		  // printf($response->getTokenProperties()->getCreateTime()->getSeconds() . PHP_EOL);
		  // The hostname of the page on which the token was generated.
		  // printf($response->getTokenProperties()->getHostname() . PHP_EOL);
	  }
  } catch (exception $e) {
	  printf('CreateAssessment() call failed with the following error: ');
	  printf($e);
  }
}

   create_assessment(
      'YOUR_RECAPTCHA_SITE_KEY',
      $_POST['g-recaptcha-response'], // Safety first! Do you trust this code?
      'YOUR_GOOGLE_CLOUD_PROJECT_ID'
    );
?>

Drop all of the above in a file named whatever.php and upload it to your web server. Before any of this will run on your server, you'll need to attend to some dependencies. 

Upload your .json key file alongside your .php file (or put it somewhere else on the server and amend the putenv path in the PHP code). This file may warrant additional protections. 

With that sorted, you need to fetch all of the Google Cloud files the PHP above depends on. You'll likely want to do this using Composer (which needs to be installed on your desktop) and you can then run this command in a command window: 

composer require google/cloud-recaptcha-enterprise

I'll note I'm only fetching the reCAPTCHA Enterprise bits here--not the entire Google Cloud file set. You do you. 

I saved all of the Google files in a directory named google-re, which you'll see referenced in the first line our PHP. Adjust as required. 

A final note for the FileZilla users out there: when uploading the Google dependencies in particular, you may encounter a horrible runtime exception ("Fail to push limit") if you don't configure the FileZilla transfer type as Binary (Transfer > Transfer type > Binary). Refer to the answer to this question for more information: https://groups.google.com/g/protobuf/c/8_S93nJWxUE?pli=1

Run It

And now you should be able to request your page, submit the button. All being well, you'll encounter no exceptions and receive a nice meessage like "The score for the protection action is:0.89999997615814". Use that and other, related assessment information to act accordingly.  

I hope that helps someone!


Friday, 3 December 2010

Relative URLs, the Rich Text Editor, and Reusable Content

We recently started leveraging the Reusable Content list to supply user-editable content to one of our interactive online forms and outbound emails. This allows the content owner to tweak the content as required as this content isn't locked away in custom code or resource files—no build and deploy required and the content management system is even used as such (whatdya know?!).

The Reusable Content list is provisioned by SharePoint when the Publishing feature is enabled; it allows users to define content snippets that can be maintained in a single location and updated automatically wherever they're used. You can optionally treat a reusable content snippet as a template—an editable copy is inserted into the page instead of a read-only, auto-updating view.

Reusable Content list items are pretty straightforward and, most importantly, contain a single HTML (rich text) field. SharePoint naturally displays its rich text editor around this field in edit mode so the edit user experience is similar to editing page content.

Unfortunately HTML fields in SharePoint are smarter than they should be and (in MOSS 2007), the product will mangle some content. I recently discovered it refuses to play with background-image style—they're silently removed whether they're inline or in an embedded stylesheet. (And yes, I know, inline styles are evil but this snippet was actually being plugged into an email so everything had to be self-contained).

Despite the tricks SharePoint plays on you with "managed" URLs, it seems the rich text field also stores URLs pointing to content within the current site as relative URLs. Absolute URLs are converted automagically but you'll never really see this until you pull the content out via the API.

We hunted for a way within SharePoint to convert all relative URLs in this content to absolute URLS but without much luck. I think there may be a Javascript function in one of the client scripts to do so for a chunk of content but there's nothing obvious in the server-side API.

To address this, we replace all relative URLs using the regex below (note the URL group) (is using regex to parse HTML bad? You be the judge). You may want to use SPUtility.GetFullUrl() to convert individual URLs.

@"(?:<\s*(?:a|img)\s+[^>]*(?:href|src)\s*=\s*[\""'])(?!http)(?<url>[^\""'>]+)[\""'>]"

If you found this post helpful, please support my advertisers.

Wednesday, 27 October 2010

Empty ImageUrl results in empty src and duplicate request

Not exactly a new issue but an empty ASP.NET ImageUrl tripped us up today. In this case there were no visible symptoms but two requests were coming through when Fiddlering the page view: the first initiated by the user and the second initiated by the page itself towards the end of the trace. In development with a debugger attached, this was manifest with Page_Load, CreateChildControls, etc being called twice for no obvious reason.

Because I initially thought I introduced the problem with the control I was working on, I first attempted to convince ASP.NET CreateChildControls was complete; I did so by clearing the Controls collection before unleashing my own code and setting the ChildControlsCreated property true once done. Neither of these tricks had any affect and the Fiddler trace had me convinced something beyond the ASP.NET pipeline and IIS had to be at fault.

That turned out to be the case but ASP.NET was still to blame ;-)

Specifically, we were adding a server-side ASP.NET image control but not initialising its ImageUrl property; the image src was later being set by jQuery at runtime on the client side. As mentioned, there were no visible symptoms of the double request: the image src was set as expected by jQuery and everything appeared okay on the surface. The IE dev toolbar also showed image src as being correctly set and there were no 404s in the mix.

It wasn't until we looked at the raw HTML that our ever-faithful admin extraordinaire noticed the empty src="" attribute. Removing the attribute removed the problem so I can only conclude IE is helpful enough to attempt to interpret a request for an empty image as a request for the parent directory of the current page while parsing the HTML before any Javascript runs. Thanks again, IE!

Notably this problem wasn't reproducible in Firefox or Chrome.

To fix the problem, we first set a default value for the ImageUrl property but that left me feeling dirty since it was still resulting in an unnecessary request. When I realised the server-side Image tag wasn't actually being used for anything server-side anyway, I replaced it with a boring old HTML img tag with no src. Microsoft has other, equally lame workarounds for this if you're interested; note they also don't plan to fix this bug.

If you found this post helpful, please support my advertisers.

Wednesday, 10 February 2010

YSlow Configuration “Use a Content Delivery Network (CDN)”

The westernaustralia.com site is served to users all over the world from the most remote city in the world: Perth, Western Australia. In other words, we target users in core markets across Australasia, Europe, and North America and while we expect a consistent homepage load time below ten seconds in all cases, Perth to New York, Perth to London, and, really, Perth to anywhere equates to high latency, congestion, and poor response times. Couple that with SharePoint, a rich, interactive site design, and an excessive number of page requests and you'll begin to appreciate why we chose to serve the site across Akamai's content delivery network.

I'll describe the setup in detail someday but for now, I've finally managed to convince YSlow the site is being served using a CDN; while we use better tools for global performance measurement (Gomez), seeing a low grade—in part because the hundred-odd requests were perceived to be served without a CDN—was starting to get me down ;) YSlow is a great plugin for analysing your site in Firebug but it's grading system can be a bit tough.

The YSlow FAQ will tell you how to configure the plugin to acknowledge the use of a CDN by setting a extensions.yslow.cdnHostnames preference. I won't repeat those details here but will expand on how the string value might be configured to tell YSlow a CDN is in use—whether you’re telling the truth or not. It’s surprisingly simple.

In our particular case, www.westernaustralia.com is a CNAME to an Akamai URL so telling YSlow to use akamai.com as a CDN doesn’t make sense and YSlow isn’t smart enough to figure things out on its own. Since www.westernaustralia.com is implicitly its own CDN, configuring the the extensions.yslow.cdnHostnames value as westernaustralia.com sorts everything out. I had to restart Firefox (3.5.x) and reload the page for things to take effect.

If you’re not using a CDN and want to turn off this particular component of your grade (or at least make it an “A”), simply add your own URL; regardless of whether you’re actually using a CDN, YSlow will think you are.

Sunday, 6 December 2009

The Keywords Meta Tag Doesn’t Matter

Every wondered if the major search engines still consider the keywords meta tag? Well most don’t and haven’t for a very long time. Here’s the latest from the search engine driving the majority of search-based traffic to your sites:

http://googlewebmastercentral.blogspot.com/2009/09/google-does-not-use-keywords-meta-tag.html

Manual keyword maintenance, automated keyword builders, and so on: goodbye and good riddance!

Wednesday, 8 July 2009

YSlow for Firefox 3.5 Lives?

YSlow has been the tool for measuring page payload and providing the metrics you need to optimise web site performance beyond the web server. Shock horror when I recently upgraded Firefox to version 3.5 and couldn’t install YSlow.

Initial rumours confirmed the current version of YSlow doesn’t work with FF3.5 but also suggested development by Yahoo! had ceased. Meanwhile Google launched Page Speed—a likeable YSlow competitor (maybe?).

A recent posting from a Yahoo! dev would suggest YSlow will actually be updated but “the team has run into some integration issues with firebug 1.4.” If you want to install FF 3.x and 3.5 side-by-side, check out this guy’s article.

Saturday, 21 March 2009

Putting Creative Agencies on Notice

Working across a number of highly-visual, rich, and interactive web sites, I’ve had the, ahem, delight of working with several of Australia’s big creative design firms over the years. I won’t name names.

These guys have variously been tasked with building good looking sites and funky widget things; their modus operandi involves mood boards, wireframes, and giving themselves stupid titles like Web Maven and Producer. They seem to rate their development ability on the basis of their ActionScript skills and their capability (I’m guessing) to offload—er, subcontract—work to an Indian sweatshop doing MOSS and AJAX and/or hire junior devs with just enough aptitude to fool most people. Naturally they’re happy to charge thousands of dollars for something like an email template—but they’re used to that because they all come from over East. Marketing people love them because they use the words “digital” and “creative” and have beards.

Well Mr. Creativity I’ve got news for you: your development skills suck and the recession economy means most organisations will be expecting full value for the outlandish buck you charge. To wit, you’ll need to start delivering more than spiel because I’m onto you.

Some of the experiences I could recount here would come across as unbelievable but here are a few classic examples nonetheless…

Creative Agency Blunder #1

We’ve been battling it out with a particular agency from Sydney for a year now just to get a reasonably simple data-driven application built that would integrate with our existing mapping solution (which the same firm built in 2007). When we first went back to these clowns the same guys who did most of the work back in 2007 were still around and picked up the new bits… before they resigned. Fair enough, people leave places. The only problem was the application was largely built in Flash and we’d already started integrating; you’ve already read my comments on the development abilities of these agencies (why can’t they just stick to being creative? They’re good at that!!) so needless to say the code was buggy and half the functionality requested hadn’t been implemented (spec? What spec? There never was a spec…).

Back and forth we went with the replacement creative team while they effectively rewrote the existing application in HTML and JQuery, retaining bits and pieces of the Flash here and there; deliveries kept coming, poor Luke in my team kept on re-integrating, bugs kept getting found, and no one had the guts to can the project.

Naturally we had a small number of change requests as the process trundled along and we were happy to pay for those changes. But the real punch line was when we received a bill for bugs they themselves had introduced! No joke—and this after significant delays brought about only by their incompetence.

Creative Agency Blunder #2

Then there’s our MOSS developer friends, also out in Sydney. Initially they requested remote access to our MOSS environment so they could develop yet another flashy but very simple applet. I declined that one as we hadn’t worked with them previously at the technical level and there’s no way I could trust them to behave within our constantly moving code base—and that’s apart from figuring out how to expose TFS and all other bits of our environment externally.

These guys actually produced a “spec” for us, which was reassuring; it was one page, of course, but the five bullet points covered largely what would be required and I made the silly assumption Marketing, as the group managing the contract (don’t ask), would have a firm grasp on things from their end. The spec basically said “web part”, “rss feed”, “web service you’ll write”, and some mention about Flash/Silverlight/AJAX. The price tag would be 10k+ and we would write all of the backend functionality in-house so they couldn’t botch it up and we could reuse it for another part of the site. Put it this way: all they had to build was a web part with some basic animation that pulled a small amount of data from a web service we would expose—nothing more.

The first delivery—after they emailed me to figure out how to invoke one of our web services—included a user control and instructions on how to install Son of Smart Part. The control was also built to rely on session state which I believe is a joke for any big web site (the widget would be going on our homepages… and we’re sitting behind two layers of caches, which was made clear to them). Finally, all the CSS and javascript was bunged into the control itself instead of sitting in external files—surely they can at least do that bit well?!?

I sent that version back before we even attempted to integrate and they responded a few days later with v2. Rewritten as a web part, I passed it along to Matt in our dev team for integration and he soon noticed basic functionality was missing—all of the key wiz bang, essentially. As Matt had already undertaken some work to integrate the thing, we sent it back with the request they work from our modified code base as much as possible, to which they agreed.

v3 came back to us the afternoon before launch day with none of our modifications but we progressed re-integration anyway—the turn around time to raise this and wait for a reply of some form was unacceptable. Did I mention when they “tested” version 3 before sending it our way they forgot to switch over to calling our web service and seemed to be astounded at the old data they were seeing—from their servers!!! Lo and behold, this version incorrectly addressed what was missing from the first version and broke another aspect of the control.

Sigh… by this point we’ve spent as much time attempting to integrate the thing as it took the agency to build it and it’s still nowhere near where it needs to be. Did I say how simple this was supposed to be?

My advice to these agencies is as follows:

  • Define a technical specification that you understand
  • Don’t deliver subpar code—test to make sure it meets the requirements and delivers basic functionality expected by any normal web user. Value add in this area.
  • Don’t charge your customers for your mistakes
  • Reduce your rates because you’re not worth what you’re charging
  • Get with the times: Flash sucks big time and Silverlight/AJAX will slowly kill it; do what you do best (design) and hire people with the skills to deliver in whatever technology set you’re selling—not inner-city Photoshop monkeys who think they’re developers because they can write bad Javascript.
  • You’ve got to communicate to integrate
  • Stop giving yourselves stupid titles you can’t back up

Wednesday, 29 August 2007

IE Renders Spurious '#text' Node as a Gap

I today had the misfortune of discovering IE6/7 doesn't like to display relatively "normal" HTML.

Take a look at this code and the bolded DIV in particular:

<html><body>
<style>
* { padding: 0px; margin: 0px; }
img { border-width: 0px; }
</style>
<div>
<img src="pic.gif" />
</div>
<div style="width: 285px; height: 100px; background-color: Green;">
<p>Other stuff</p>
</div>
</body></html>

This renders a lovely gap between the image in the top DIV and the bottom DIV:

Inspecting the DOM using the IE Developer Toolbar reveals IE is interpreting and rendering a spurious text node from the markup:

As you might expect, Firefox has no issues with this and renders the two DIVs one on top of the other with no gap between.

Despite average CSS skills, I was unable to style this into submission without completely mangling the existing code and CSS (simply adjusting the DIV's height had no effect); instead I managed to get around this by simply removing all whitespace between the opening and closing DIV tags:

<div><img src="pic.gif" /></div>

Since the image in this example is essentially functioning as background image for the DIV, I could have alternatively set its background-image to the URL of the image.

Wednesday, 15 August 2007

IE Dev Toolbar Stops Working (IE7)

The IEDevToolbar is a great help for web-based development with Internet Explorer. I've been using it since it was in beta and while it generally does the job, the bugs have been ever-present in different forms.

One of the latest things I've noticed is how the toolbar seems to stop working (generally after refreshing a page that's changed at the server). The menu options are greyed out and clicking with the pointer refuses to select any page elements. Closing the toolbar and re-opening it again fixes the problem but there is a better way.

For some reason, the toolbar doesn't always automatically refresh itself. As a result the DOM tree represented in the toolbar doesn't match the DOM tree in the browser. Closing and re-opening the toolbar synchronises the toolbar with the page but this can also be accomplished but hitting the IEDevToolbar's Refresh button (one of several icons that don't make a lot of sense at first glance). The menus function once again and page elements are clickable. Why this doesn't always happen automatically is beyond me.

Tuesday, 26 June 2007

Closing Tag Identifier

I often see HTML comments used to relate a closing tag to its opening tag; when a DIV or some other container tag contains enough content to make viewing the entire block without scrolling impossible, I think this makes perfect sense.

For example:

<div id="myTag">
</div> <!-- end myTag -->


This is also sometimes helpful with C-like languages that use braces to delimit blocks of code.

Although modern development tools highlight closing tags and braces, HTML code in particular isn't always read within one of these tools (View-->Source in IE opens the source code in Notepad, for instance).

To assist, I think it would be helpful to have the option of attributing a closing tag with the same id used by the opening tag:

<div id="myTag">
</div id="myTag">


Our fancy editors would keep the opening/closing ids in sync and browsers could safely ignore the additional attribute.

In practice, this works quite nicely with the caveat that a page built like this is invalid.

Wednesday, 16 May 2007

A comprehensive review of how to make an anchor tag do nothing

What's the best way to fire a javascript event from an anchor tag without mucking up your navigation? For that matter, what's the best way to do anchor tags all together? Have a look at the tests below and review the source before making your own decision (you might want to copy the source out to your html file).

Here's a few things to consider:

  • We do not usually want a link to return the caret to the top of the page.
    Javascript may be disabled on the client side (but all solutions presented here are javascript-dependent)
  • Microsoft apparently recommends against using javascript: calls from within the HREF element of an anchor tag and its use may also impact accessibility.
  • If using a click event handler, place a hash in the href attribute and a return false; as the final code for the onClick attribute; ensure any preceding function calls can be interpreted and executed or the return false may never be reached.
  • Alternatively, use another tag (not an anchor tag) and its onClick attribute.

a (without href) (no underline)
a href="wwww.mysite.com" (normal link)
a href="" (opens containing folder in IE (when run without a web server); scrolls to top of page in FF)
a href="#" (scrolls to top of page)
a href="javascript:" (works in IE but pops up javascript console in FF)
a href="javascript: return false;" (javascript error)
*
a href="javascript: void(0);" (works but may cause problems)
*
a href="javascript: myFunc();" (works if myFunc () is defined - myFunc does not need to return false)
a href="javascript: myUndefinedFunc ();" (javascript error)
a href="top" (scrolls to top of page)
a href="null" (no underline)
* a href="#bookmark" (works if a name is defined immediately above)
a onclick="return false;" (without href) (no underline)
*
a href="" onclick="return false;" (works)
*
a href="#" onclick="return false;" (works)
a href="#" onclick="myBrokenFunc; return false;" (javascript error and scroll to top because return false never executes)
*
a href="#" onclick="myOnClickFunc (); return false;" (works)
* styled span (works but doesn't "select" on click or change color on visit)

* = A preferred way to do nothing links

Friday, 20 April 2007

Fiddler Reverse Proxy Setup

The Fiddler documentation includes instructions on how to configure the tool as a reverse proxy (http://www.fiddlertool.com/Fiddler/help/reverseproxy.asp). Option #1 is only useful if you're setting up Fiddler as a local reverse proxy; if you want to use Fiddler from external clients, you need to go for Option #2.

The code snippet to be added to your custom rules file includes two string listerals: "webserver:8888" and "webserver:80". It's in important to note that "webserver" is not a variable name--it must be replaced with the name of your web server (i.e. MyServer, as in http://myserver). The other important thing is to add the code snippet to the OnBeforeRequest function and not the OnBeforeResponse function. You'll also probably want to allow remote clients to connet via Fiddler so make sure the Tools -> Fiddler Options... Allow remote clients to connect options is selected.

You can change the listen port from 8888 via Tools -> Fiddler Options... Listen Port if you want to use a port other than 8888.

If you implement both Option #1 and Option #2 you might end up with problems like an infinite loop.

The change may take a little while to come into effect so meanwhile, try restarting Fiddler, running an iisreset, or rebooting.